diff -Nru libemail-mime-contenttype-perl-1.022/Changes libemail-mime-contenttype-perl-1.024/Changes --- libemail-mime-contenttype-perl-1.022/Changes 2017-08-31 13:17:02.000000000 +0000 +++ libemail-mime-contenttype-perl-1.024/Changes 2020-05-24 14:19:22.000000000 +0000 @@ -1,5 +1,17 @@ Revision history for Perl extension Email::MIME::ContentType +1.024 2020-05-24 10:19:20-04:00 America/New_York + - no changes since stable release + +1.023 2020-05-09 14:51:41-04:00 America/New_York (TRIAL RELEASE) + - All of this release is thanks to Pali Rohár, who suffered through a + long period of waiting while RJBS, the maintainer, let the module + languish. Thank you for your patience, Pali and everybody else. + + - silence an uninitalized value warning + - avoid allowing non-Latin digits in numbers + - add new functions build_content_type() and build_content_disposition + 1.022 2017-08-31 09:16:58-04:00 America/New_York - add parse_content_disposition (thanks, Pali Rohár) @@ -56,4 +68,4 @@ 0.01 Wed Jan 7 17:38:23 2004 - original version; created by h2xs 1.22 with options - -AX -b 5.6.0 -n Email::MIME::ContentType + -AX -b 5.6.0 -n Email::MIME::ContentType diff -Nru libemail-mime-contenttype-perl-1.022/debian/changelog libemail-mime-contenttype-perl-1.024/debian/changelog --- libemail-mime-contenttype-perl-1.022/debian/changelog 2017-09-18 21:09:35.000000000 +0000 +++ libemail-mime-contenttype-perl-1.024/debian/changelog 2020-11-06 21:59:43.000000000 +0000 @@ -1,3 +1,35 @@ +libemail-mime-contenttype-perl (1.024-1) unstable; urgency=medium + + * Team upload + + [ Damyan Ivanov ] + * declare conformance with Policy 4.1.3 (no changes needed) + + [ Salvatore Bonaccorso ] + * Update Vcs-* headers for switch to salsa.debian.org + + [ gregor herrmann ] + * debian/watch: use uscan version 4. + + [ Debian Janitor ] + * Bump debhelper from old 9 to 12. + * Set debhelper-compat version in Build-Depends. + * Set upstream metadata fields: Bug-Submit. + * Remove obsolete fields Contact, Name from debian/upstream/metadata + (already present in machine-readable debian/copyright). + + [ Joenio Marques da Costa ] + * Import upstream version 1.024 + * Add myself to d/copyright + * using uscan special strings on d/watch + * d/control: depends on libtext-unidecode-perl + + [ gregor herrmann ] + * Set Rules-Requires-Root: no. + * Annotate test-only build dependencies with . + + -- Joenio Marques da Costa Fri, 06 Nov 2020 22:59:43 +0100 + libemail-mime-contenttype-perl (1.022-1) unstable; urgency=medium [ Salvatore Bonaccorso ] diff -Nru libemail-mime-contenttype-perl-1.022/debian/compat libemail-mime-contenttype-perl-1.024/debian/compat --- libemail-mime-contenttype-perl-1.022/debian/compat 2017-09-18 21:08:12.000000000 +0000 +++ libemail-mime-contenttype-perl-1.024/debian/compat 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -9 diff -Nru libemail-mime-contenttype-perl-1.022/debian/control libemail-mime-contenttype-perl-1.024/debian/control --- libemail-mime-contenttype-perl-1.022/debian/control 2017-09-18 21:09:23.000000000 +0000 +++ libemail-mime-contenttype-perl-1.024/debian/control 2020-11-06 21:59:43.000000000 +0000 @@ -5,17 +5,20 @@ Section: perl Testsuite: autopkgtest-pkg-perl Priority: optional -Build-Depends: debhelper (>= 9) -Build-Depends-Indep: perl -Standards-Version: 4.1.0 -Vcs-Browser: https://anonscm.debian.org/cgit/pkg-perl/packages/libemail-mime-contenttype-perl.git -Vcs-Git: https://anonscm.debian.org/git/pkg-perl/packages/libemail-mime-contenttype-perl.git +Build-Depends: debhelper-compat (= 13) +Build-Depends-Indep: libtext-unidecode-perl , + perl +Standards-Version: 4.5.0 +Vcs-Browser: https://salsa.debian.org/perl-team/modules/packages/libemail-mime-contenttype-perl +Vcs-Git: https://salsa.debian.org/perl-team/modules/packages/libemail-mime-contenttype-perl.git Homepage: https://metacpan.org/module/Email::MIME::ContentType +Rules-Requires-Root: no Package: libemail-mime-contenttype-perl Architecture: all Depends: ${misc:Depends}, - ${perl:Depends} + ${perl:Depends}, + libtext-unidecode-perl Description: Perl module to parse a MIME Content-Type header Email::MIME::ContentType provides a method for parsing email Content- Type headers according to section 5.1 of RFC 2045. The method returns diff -Nru libemail-mime-contenttype-perl-1.022/debian/copyright libemail-mime-contenttype-perl-1.024/debian/copyright --- libemail-mime-contenttype-perl-1.022/debian/copyright 2017-09-18 21:05:42.000000000 +0000 +++ libemail-mime-contenttype-perl-1.024/debian/copyright 2020-11-06 21:59:43.000000000 +0000 @@ -12,6 +12,7 @@ 2005-2008, Ernesto Hernández-Novich (USB) 2007-2008, other members of the Debian Perl Group, cf. debian/changelog 2013-2017, Florian Schlichting + 2020, Joenio Marques da Costa License: Artistic or GPL-1+ License: Artistic diff -Nru libemail-mime-contenttype-perl-1.022/debian/upstream/metadata libemail-mime-contenttype-perl-1.024/debian/upstream/metadata --- libemail-mime-contenttype-perl-1.022/debian/upstream/metadata 2017-09-18 20:58:38.000000000 +0000 +++ libemail-mime-contenttype-perl-1.024/debian/upstream/metadata 2020-11-06 21:59:43.000000000 +0000 @@ -1,8 +1,6 @@ --- Archive: CPAN Bug-Database: https://github.com/rjbs/Email-MIME-ContentType/issues -Contact: Simon Cozens , Casey West , Ricardo SIGNES - -Name: Email-MIME-ContentType +Bug-Submit: https://github.com/rjbs/Email-MIME-ContentType/issues/new Repository: https://github.com/rjbs/Email-MIME-ContentType.git Repository-Browse: https://github.com/rjbs/Email-MIME-ContentType diff -Nru libemail-mime-contenttype-perl-1.022/debian/watch libemail-mime-contenttype-perl-1.024/debian/watch --- libemail-mime-contenttype-perl-1.022/debian/watch 2014-03-04 10:38:03.000000000 +0000 +++ libemail-mime-contenttype-perl-1.024/debian/watch 2020-11-06 21:59:43.000000000 +0000 @@ -1,3 +1,2 @@ -# format version number, currently 3; this line is compulsory! -version=3 -https://metacpan.org/release/Email-MIME-ContentType .+/Email-MIME-ContentType-([\d\.]+)\.(?:tar\.gz|tar|tgz) +version=4 +https://metacpan.org/release/Email-MIME-ContentType .*/Email-MIME-ContentType-v?@ANY_VERSION@@ARCHIVE_EXT@$ diff -Nru libemail-mime-contenttype-perl-1.022/lib/Email/MIME/ContentType.pm libemail-mime-contenttype-perl-1.024/lib/Email/MIME/ContentType.pm --- libemail-mime-contenttype-perl-1.022/lib/Email/MIME/ContentType.pm 2017-08-31 13:17:02.000000000 +0000 +++ libemail-mime-contenttype-perl-1.024/lib/Email/MIME/ContentType.pm 2020-05-24 14:19:22.000000000 +0000 @@ -1,12 +1,14 @@ use strict; use warnings; package Email::MIME::ContentType; -# ABSTRACT: Parse a MIME Content-Type or Content-Disposition Header -$Email::MIME::ContentType::VERSION = '1.022'; +# ABSTRACT: Parse and build a MIME Content-Type or Content-Disposition Header +$Email::MIME::ContentType::VERSION = '1.024'; use Carp; -use Encode 2.87 qw(find_mime_encoding); +use Encode 2.87 qw(encode find_mime_encoding); use Exporter 5.57 'import'; -our @EXPORT = qw(parse_content_type parse_content_disposition); +use Text::Unidecode; + +our @EXPORT = qw(parse_content_type parse_content_disposition build_content_type build_content_disposition); #pod =head1 SYNOPSIS #pod @@ -25,6 +27,9 @@ #pod } #pod }; #pod +#pod my $ct_new = build_content_type($data); +#pod # text/plain; charset=us-ascii; format=flowed +#pod #pod #pod # Content-Type: application/x-stuff; #pod # title*0*=us-ascii'en'This%20is%20even%20more%20; @@ -44,6 +49,7 @@ #pod } #pod }; #pod +#pod #pod # Content-Disposition: attachment; filename=genome.jpeg; #pod # modification-date="Wed, 12 Feb 1997 16:29:51 -0500" #pod my $cd = q(attachment; filename=genome.jpeg; @@ -58,6 +64,9 @@ #pod } #pod }; #pod +#pod my $cd_new = build_content_disposition($data); +#pod # attachment; filename=genome.jpeg; modification-date="Wed, 12 Feb 1997 16:29:51 -0500" +#pod #pod =cut our $STRICT_PARAMS = 1; @@ -80,223 +89,368 @@ my $re_exvalue = qr/($re_charset)?'(?:$re_language)?'(.*)/; sub parse_content_type { - my $ct = shift; + my $ct = shift; - # If the header isn't there or is empty, give default answer. - return parse_content_type($ct_default) unless defined $ct and length $ct; + # If the header isn't there or is empty, give default answer. + return parse_content_type($ct_default) unless defined $ct and length $ct; - _unfold_lines($ct); - _clean_comments($ct); + _unfold_lines($ct); + _clean_comments($ct); - # It is also recommend (sic.) that this default be assumed when a - # syntactically invalid Content-Type header field is encountered. - unless ($ct =~ s/^($re_token)\/($re_token)//) { - unless ($STRICT_PARAMS and $ct =~ s/^($re_token_non_strict)\/($re_token_non_strict)//) { - carp "Invalid Content-Type '$ct'"; - return parse_content_type($ct_default); - } - } + # It is also recommend (sic.) that this default be assumed when a + # syntactically invalid Content-Type header field is encountered. + unless ($ct =~ s/^($re_token)\/($re_token)//) { + unless ($STRICT_PARAMS and $ct =~ s/^($re_token_non_strict)\/($re_token_non_strict)//) { + carp "Invalid Content-Type '$ct'"; + return parse_content_type($ct_default); + } + } + + my ($type, $subtype) = (lc $1, lc $2); + + _clean_comments($ct); + $ct =~ s/\s+$//; + + my $attributes = {}; + if ($STRICT_PARAMS and length $ct and $ct !~ /^;/) { + carp "Missing semicolon before first Content-Type parameter '$ct'"; + } else { + $attributes = _process_rfc2231(_parse_attributes($ct)); + } + + return { + type => $type, + subtype => $subtype, + attributes => $attributes, + + # This is dumb. Really really dumb. For backcompat. -- rjbs, + # 2013-08-10 + discrete => $type, + composite => $subtype, + }; +} + +my $cd_default = 'attachment'; - my ($type, $subtype) = (lc $1, lc $2); +sub parse_content_disposition { + my $cd = shift; - _clean_comments($ct); - $ct =~ s/\s+$//; + return parse_content_disposition($cd_default) unless defined $cd and length $cd; - my $attributes = {}; - if ($STRICT_PARAMS and length $ct and $ct !~ /^;/) { - carp "Missing semicolon before first Content-Type parameter '$ct'"; - } else { - $attributes = _process_rfc2231(_parse_attributes($ct)); + _unfold_lines($cd); + _clean_comments($cd); + + unless ($cd =~ s/^($re_token)//) { + unless ($STRICT_PARAMS and $cd =~ s/^($re_token_non_strict)//) { + carp "Invalid Content-Disposition '$cd'"; + return parse_content_disposition($cd_default); } + } - return { - type => $type, - subtype => $subtype, - attributes => $attributes, - - # This is dumb. Really really dumb. For backcompat. -- rjbs, - # 2013-08-10 - discrete => $type, - composite => $subtype, - }; + my $type = lc $1; + + _clean_comments($cd); + $cd =~ s/\s+$//; + + my $attributes = {}; + if ($STRICT_PARAMS and length $cd and $cd !~ /^;/) { + carp "Missing semicolon before first Content-Disposition parameter '$cd'"; + } else { + $attributes = _process_rfc2231(_parse_attributes($cd)); + } + + return { + type => $type, + attributes => $attributes, + }; } -my $cd_default = 'attachment'; +my $re_invalid_for_quoted_value = qr/[\x00-\x08\x0A-\x1F\x7F-\xFF]/; # non-US-ASCII and CTLs without SPACE and TAB +my $re_escape_extended_value = qr/[\x00-\x20\x7F-\xFF\*'%()<>@,;:\\"\/\[\]?=]/; # non-US-ASCII, SPACE, CTLs, *'% and tspecials ()<>@,;:\\"/[]?= -sub parse_content_disposition { - my $cd = shift; +sub build_content_type { + my $ct = shift; - return parse_content_disposition($cd_default) unless defined $cd and length $cd; + croak 'Missing Content-Type \'type\' parameter' unless exists $ct->{type}; + croak 'Missing Content-Type \'subtype\' parameter' unless exists $ct->{subtype}; - _unfold_lines($cd); - _clean_comments($cd); + croak 'Invalid Content-Type \'type\' parameter' if $ct->{type} !~ /^(?:$re_token)*$/; + croak 'Invalid Content-Type \'subtype\' parameter' if $ct->{subtype} !~ /^(?:$re_token)*$/; - unless ($cd =~ s/^($re_token)//) { - unless ($STRICT_PARAMS and $cd =~ s/^($re_token_non_strict)//) { - carp "Invalid Content-Disposition '$cd'"; - return parse_content_disposition($cd_default); - } - } + croak 'Too long Content-Type \'type\' and \'subtype\' parameters' if length($ct->{type}) + length($ct->{subtype}) > 76; - my $type = lc $1; + my ($extra) = grep !/(?:type|subtype|attributes)/, sort keys %{$ct}; + croak "Extra Content-Type '$extra' parameter" if defined $extra; - _clean_comments($cd); - $cd =~ s/\s+$//; + my $ret = $ct->{type} . '/' . $ct->{subtype}; + my $attrs = exists $ct->{attributes} ? _build_attributes($ct->{attributes}) : ''; + $ret .= "; $attrs" if length($attrs); + return $ret; +} - my $attributes = {}; - if ($STRICT_PARAMS and length $cd and $cd !~ /^;/) { - carp "Missing semicolon before first Content-Disposition parameter '$cd'"; - } else { - $attributes = _process_rfc2231(_parse_attributes($cd)); +sub build_content_disposition { + my $cd = shift; + + croak 'Missing Content-Type \'type\' parameter' unless exists $cd->{type}; + + croak 'Invalid Content-Type \'type\' parameter' if $cd->{type} !~ /^(?:$re_token)*$/; + + croak 'Too long Content-Type \'type\' parameter' if length($cd->{type}) > 77; + + my ($extra) = grep !/(?:type|attributes)/, sort keys %{$cd}; + croak "Extra Content-Type '$extra' parameter" if defined $extra; + + my $ret = $cd->{type}; + my $attrs = exists $cd->{attributes} ? _build_attributes($cd->{attributes}) : ''; + $ret .= "; $attrs" if length($attrs); + return $ret; +} + +sub _build_attributes { + my $attributes = shift; + + my $ret = ''; + + foreach my $key (sort keys %{$attributes}) { + my $value = $attributes->{$key}; + my $ascii_value = $value; + my @continuous_value; + my $extended_value_charset; + + croak "Invalid attribute '$key'" if $key =~ /$re_escape_extended_value/; # complement to attribute-char in 8bit space + croak "Undefined attribute '$key'" unless defined $value; + + if ($value =~ /\P{ASCII}/) { + $ascii_value = unidecode($value); + $ascii_value =~ s/\P{ASCII}/_/g; + @continuous_value = map { encode('UTF-8', $_) } split //, $value; + $extended_value_charset = 'UTF-8'; + } + + if ($ascii_value !~ /^(?:$re_token)*$/ or $ascii_value =~ /'/) { + if ($ascii_value =~ /$re_invalid_for_quoted_value/) { + @continuous_value = split //, $value unless @continuous_value; + $ascii_value =~ s/[\n\r]/ /g; + $ascii_value =~ s/$re_invalid_for_quoted_value/_/g; + } + $ascii_value =~ s/(["\\])/\\$1/g; + $ascii_value = "\"$ascii_value\""; + } + + if (length($key) + length($ascii_value) > 75) { # length(" $key=$ascii_value;") > 78 + croak "Too long attribute '$key'" if length($key) > 71; # length(" $key=...;") > 78 + my $pos = $ascii_value =~ /"$/ ? 71 : 72; + substr($ascii_value, $pos - length($key), length($ascii_value) + length($key) - 72, '...'); + @continuous_value = split //, $value unless @continuous_value; + } + + if (@continuous_value) { + my $needs_quote; + unless (defined $extended_value_charset) { + $needs_quote = 1 if grep { $_ !~ /^(?:$re_token)*$/ or $_ =~ /'/ } @continuous_value; + $extended_value_charset = 'US-ASCII' if $needs_quote and grep /$re_invalid_for_quoted_value/, @continuous_value; + } + + my $add_param_len = 4; # for '; *=' + if (defined $extended_value_charset) { + $_ =~ s/($re_escape_extended_value)/sprintf('%%%02X', ord($1))/eg foreach @continuous_value; + substr($continuous_value[0], 0, 0, "$extended_value_charset''"); + $add_param_len += 1; # for '*' - charset + } elsif ($needs_quote) { + $_ =~ s/(["\\])/\\$1/g foreach @continuous_value; + $add_param_len += 2; # for quotes + } + + if ($value =~ /\P{ASCII}/ and length(my $oneparameter = "; $key*=" . join '', @continuous_value) <= 78) { + $ret .= $oneparameter; + } else { + my $buf = ''; + my $count = 0; + foreach (@continuous_value) { + if (length($key) + length($count) + length($buf) + length($_) + $add_param_len > 78) { + $buf = "\"$buf\"" if $needs_quote; + my $parameter = "; $key*$count"; + $parameter .= '*' if defined $extended_value_charset; + $parameter .= "=$buf"; + croak "Too long attribute '$key'" if length($parameter) > 78; + $ret .= $parameter; + $buf = ''; + $count++; + } + $buf .= $_; + } + if (length($buf)) { + $buf = "\"$buf\"" if $needs_quote; + my $parameter = "; $key*$count"; + $parameter .= '*' if defined $extended_value_charset; + $parameter .= "=$buf"; + croak "Too long attribute '$key'" if length($parameter) > 78; + $ret .= $parameter; + } + } } - return { - type => $type, - attributes => $attributes, - }; + $ret .= "; $key=$ascii_value"; + } + + substr($ret, 0, 2, '') if length $ret; + return $ret; } sub _unfold_lines { - $_[0] =~ s/(?:\r\n|[\r\n])(?=[ \t])//g; + $_[0] =~ s/(?:\r\n|[\r\n])(?=[ \t])//g; } sub _clean_comments { - my $ret = ($_[0] =~ s/^\s+//); + my $ret = ($_[0] =~ s/^\s+//); + while (length $_[0]) { + last unless $_[0] =~ s/^\(//; + my $level = 1; while (length $_[0]) { - last unless $_[0] =~ s/^\(//; - my $level = 1; - while (length $_[0]) { - my $ch = substr $_[0], 0, 1, ''; - if ($ch eq '(') { - $level++; - } elsif ($ch eq ')') { - $level--; - last if $level == 0; - } elsif ($ch eq '\\') { - substr $_[0], 0, 1, ''; - } - } - carp "Unbalanced comment" if $level != 0 and $STRICT_PARAMS; - $ret |= ($_[0] =~ s/^\s+//); - } - return $ret; + my $ch = substr $_[0], 0, 1, ''; + if ($ch eq '(') { + $level++; + } elsif ($ch eq ')') { + $level--; + last if $level == 0; + } elsif ($ch eq '\\') { + substr $_[0], 0, 1, ''; + } + } + carp "Unbalanced comment" if $level != 0 and $STRICT_PARAMS; + $ret |= ($_[0] =~ s/^\s+//); + } + return $ret; } sub _process_rfc2231 { - my ($attribs) = @_; - my %cont; - my %encoded; - foreach (keys %{$attribs}) { - next unless $_ =~ m/^(.*)\*(\d+)\*?$/; - my ($attr, $sec) = ($1, $2); - $cont{$attr}->[$sec] = $attribs->{$_}; - $encoded{$attr}->[$sec] = 1 if $_ =~ m/\*$/; - delete $attribs->{$_}; - } - foreach (keys %cont) { - my $key = $_; - $key .= '*' if $encoded{$_}; - $attribs->{$key} = join '', @{$cont{$_}}; - } - foreach (keys %{$attribs}) { - next unless $_ =~ m/^(.*)\*$/; - my $key = $1; - next unless $attribs->{$_} =~ m/^$re_exvalue$/; - my ($charset, $value) = ($1, $2); - $value =~ s/%([0-9A-Fa-f]{2})/pack('C', hex($1))/eg; - if (length $charset) { - my $enc = find_mime_encoding($charset); - if (defined $enc) { - $value = $enc->decode($value); - } else { - carp "Unknown charset '$charset' in attribute '$key' value"; - } - } - $attribs->{$key} = $value; - delete $attribs->{$_}; - } - return $attribs; + my ($attribs) = @_; + my %cont; + my %encoded; + + foreach (keys %{$attribs}) { + next unless $_ =~ m/^(.*)\*([0-9]+)\*?$/; + my ($attr, $sec) = ($1, $2); + $cont{$attr}->[$sec] = $attribs->{$_}; + $encoded{$attr}->[$sec] = 1 if $_ =~ m/\*$/; + delete $attribs->{$_}; + } + + foreach (keys %cont) { + my $key = $_; + $key .= '*' if $encoded{$_}; + $attribs->{$key} = join '', @{$cont{$_}}; + } + + foreach (keys %{$attribs}) { + next unless $_ =~ m/^(.*)\*$/; + my $key = $1; + next unless defined $attribs->{$_} and $attribs->{$_} =~ m/^$re_exvalue$/; + my ($charset, $value) = ($1, $2); + $value =~ s/%([0-9A-Fa-f]{2})/pack('C', hex($1))/eg; + if (length $charset) { + my $enc = find_mime_encoding($charset); + if (defined $enc) { + $value = $enc->decode($value); + } else { + carp "Unknown charset '$charset' in attribute '$key' value"; + } + } + $attribs->{$key} = $value; + delete $attribs->{$_}; + } + + return $attribs; } sub _parse_attributes { - local $_ = shift; - substr($_, 0, 0, '; ') if length $_ and $_ !~ /^;/; - my $attribs = {}; - while (length $_) { - s/^;// or $STRICT_PARAMS and do { - carp "Missing semicolon before parameter '$_'"; - return $attribs; - }; - _clean_comments($_); - unless (length $_) { - # Some mail software generates a Content-Type like this: - # "Content-Type: text/plain;" - # RFC 1521 section 3 says a parameter must exist if there is a - # semicolon. - carp "Extra semicolon after last parameter" if $STRICT_PARAMS; - return $attribs; - } - my $attribute; - if (s/^($re_token)=//) { - $attribute = lc $1; - } else { - if ($STRICT_PARAMS) { - carp "Illegal parameter '$_'"; - return $attribs; - } - if (s/^($re_token_non_strict)=//) { - $attribute = lc $1; - } else { - unless (s/^([^;=\s]+)\s*=//) { - carp "Cannot parse parameter '$_'"; - return $attribs; - } - $attribute = lc $1; - } + local $_ = shift; + substr($_, 0, 0, '; ') if length $_ and $_ !~ /^;/; + my $attribs = {}; + + while (length $_) { + s/^;// or $STRICT_PARAMS and do { + carp "Missing semicolon before parameter '$_'"; + return $attribs; + }; + + _clean_comments($_); + + unless (length $_) { + # Some mail software generates a Content-Type like this: + # "Content-Type: text/plain;" + # RFC 1521 section 3 says a parameter must exist if there is a + # semicolon. + carp "Extra semicolon after last parameter" if $STRICT_PARAMS; + return $attribs; + } + + my $attribute; + if (s/^($re_token)=//) { + $attribute = lc $1; + } else { + if ($STRICT_PARAMS) { + carp "Illegal parameter '$_'"; + return $attribs; + } + if (s/^($re_token_non_strict)=//) { + $attribute = lc $1; + } else { + unless (s/^([^;=\s]+)\s*=//) { + carp "Cannot parse parameter '$_'"; + return $attribs; } - _clean_comments($_); - my $value = _extract_attribute_value(); - $attribs->{$attribute} = $value; - _clean_comments($_); + $attribute = lc $1; + } } - return $attribs; + + _clean_comments($_); + my $value = _extract_attribute_value(); + $attribs->{$attribute} = $value; + _clean_comments($_); + } + + return $attribs; } sub _extract_attribute_value { # EXPECTS AND MODIFIES $_ - my $value; - while (length $_) { - if (s/^($re_token)//) { - $value .= $1; - } elsif (s/^$re_quoted_string//) { - my $sub = $1; - $sub =~ s/\\(.)/$1/g; - $value .= $sub; - } elsif ($STRICT_PARAMS) { - my $char = substr $_, 0, 1; - carp "Unquoted '$char' not allowed"; - return; - } elsif (s/^($re_token_non_strict)//) { - $value .= $1; - } elsif (s/^$re_quoted_string_non_strict//) { - my $sub = $1; - $sub =~ s/\\(.)/$1/g; - $value .= $sub; - } - my $erased = _clean_comments($_); - last if !length $_ or /^;/; - if ($STRICT_PARAMS) { - my $char = substr $_, 0, 1; - carp "Extra '$char' found after parameter"; - return; - } - if ($erased) { - # Sometimes semicolon is missing, so check for = char - last if m/^$re_token_non_strict=/; - $value .= ' '; - } - $value .= substr $_, 0, 1, ''; - } - return $value; + my $value; + while (length $_) { + if (s/^($re_token)//) { + $value .= $1; + } elsif (s/^$re_quoted_string//) { + my $sub = $1; + $sub =~ s/\\(.)/$1/g; + $value .= $sub; + } elsif ($STRICT_PARAMS) { + my $char = substr $_, 0, 1; + carp "Unquoted '$char' not allowed"; + return; + } elsif (s/^($re_token_non_strict)//) { + $value .= $1; + } elsif (s/^$re_quoted_string_non_strict//) { + my $sub = $1; + $sub =~ s/\\(.)/$1/g; + $value .= $sub; + } + + my $erased = _clean_comments($_); + last if !length $_ or /^;/; + if ($STRICT_PARAMS) { + my $char = substr $_, 0, 1; + carp "Extra '$char' found after parameter"; + return; + } + + if ($erased) { + # Sometimes semicolon is missing, so check for = char + last if m/^$re_token_non_strict=/; + $value .= ' '; + } + + $value .= substr $_, 0, 1, ''; + } + return $value; } 1; @@ -323,6 +477,30 @@ #pod RFC 2231. It returns a hash as above, with entries for the C, and a hash #pod of C. #pod +#pod =func build_content_type +#pod +#pod This routine is exported by default. +#pod +#pod This routine builds email Content-Type header according to RFC 2045 and RFC 2231. +#pod It takes a hash as above, with entries for the C, the C, and +#pod optionally also a hash of C. It returns a string representing +#pod Content-Type header. Non-ASCII attributes are encoded to UTF-8 according to +#pod Character Set section of RFC 2231. Attribute which has more then 78 ASCII +#pod characters is split into more attributes accorrding to Parameter Continuations +#pod of RFC 2231. For compatibility reasons with clients which do not support +#pod RFC 2231, output string contains also truncated ASCII version of any too long or +#pod non-ASCII attribute. Encoding to ASCII is done via Text::Unidecode module. +#pod +#pod =func build_content_disposition +#pod +#pod This routine is exported by default. +#pod +#pod This routine builds email Content-Disposition header according to RFC 2182 and +#pod RFC 2231. It takes a hash as above, with entries for the C, and +#pod optionally also a hash of C. It returns a string representing +#pod Content-Disposition header. Non-ASCII or too long attributes are handled in +#pod the same way like in L. +#pod #pod =head1 WARNINGS #pod #pod This is not a valid content-type header, according to both RFC 1521 and RFC @@ -347,11 +525,11 @@ =head1 NAME -Email::MIME::ContentType - Parse a MIME Content-Type or Content-Disposition Header +Email::MIME::ContentType - Parse and build a MIME Content-Type or Content-Disposition Header =head1 VERSION -version 1.022 +version 1.024 =head1 SYNOPSIS @@ -370,6 +548,9 @@ } }; + my $ct_new = build_content_type($data); + # text/plain; charset=us-ascii; format=flowed + # Content-Type: application/x-stuff; # title*0*=us-ascii'en'This%20is%20even%20more%20; @@ -389,6 +570,7 @@ } }; + # Content-Disposition: attachment; filename=genome.jpeg; # modification-date="Wed, 12 Feb 1997 16:29:51 -0500" my $cd = q(attachment; filename=genome.jpeg; @@ -403,6 +585,9 @@ } }; + my $cd_new = build_content_disposition($data); + # attachment; filename=genome.jpeg; modification-date="Wed, 12 Feb 1997 16:29:51 -0500" + =head1 FUNCTIONS =head2 parse_content_type @@ -427,6 +612,30 @@ RFC 2231. It returns a hash as above, with entries for the C, and a hash of C. +=head2 build_content_type + +This routine is exported by default. + +This routine builds email Content-Type header according to RFC 2045 and RFC 2231. +It takes a hash as above, with entries for the C, the C, and +optionally also a hash of C. It returns a string representing +Content-Type header. Non-ASCII attributes are encoded to UTF-8 according to +Character Set section of RFC 2231. Attribute which has more then 78 ASCII +characters is split into more attributes accorrding to Parameter Continuations +of RFC 2231. For compatibility reasons with clients which do not support +RFC 2231, output string contains also truncated ASCII version of any too long or +non-ASCII attribute. Encoding to ASCII is done via Text::Unidecode module. + +=head2 build_content_disposition + +This routine is exported by default. + +This routine builds email Content-Disposition header according to RFC 2182 and +RFC 2231. It takes a hash as above, with entries for the C, and +optionally also a hash of C. It returns a string representing +Content-Disposition header. Non-ASCII or too long attributes are handled in +the same way like in L. + =head1 WARNINGS This is not a valid content-type header, according to both RFC 1521 and RFC @@ -461,7 +670,7 @@ =head1 CONTRIBUTORS -=for stopwords Matthew Green Pali Thomas Szukala +=for stopwords Matthew Green Pali Ricardo Signes Thomas Szukala =over 4 @@ -475,6 +684,10 @@ =item * +Ricardo Signes + +=item * + Thomas Szukala =back diff -Nru libemail-mime-contenttype-perl-1.022/Makefile.PL libemail-mime-contenttype-perl-1.024/Makefile.PL --- libemail-mime-contenttype-perl-1.022/Makefile.PL 2017-08-31 13:17:02.000000000 +0000 +++ libemail-mime-contenttype-perl-1.024/Makefile.PL 2020-05-24 14:19:22.000000000 +0000 @@ -1,4 +1,4 @@ -# This file was automatically generated by Dist::Zilla::Plugin::MakeMaker v6.010. +# This file was automatically generated by Dist::Zilla::Plugin::MakeMaker v6.014. use strict; use warnings; @@ -7,7 +7,7 @@ use ExtUtils::MakeMaker; my %WriteMakefileArgs = ( - "ABSTRACT" => "Parse a MIME Content-Type or Content-Disposition Header", + "ABSTRACT" => "Parse and build a MIME Content-Type or Content-Disposition Header", "AUTHOR" => "Simon Cozens , Casey West , Ricardo SIGNES ", "CONFIGURE_REQUIRES" => { "ExtUtils::MakeMaker" => 0 @@ -19,6 +19,7 @@ "Carp" => 0, "Encode" => "2.87", "Exporter" => "5.57", + "Text::Unidecode" => 0, "strict" => 0, "warnings" => 0 }, @@ -27,7 +28,7 @@ "File::Spec" => 0, "Test::More" => "0.96" }, - "VERSION" => "1.022", + "VERSION" => "1.024", "test" => { "TESTS" => "t/*.t" } @@ -41,6 +42,7 @@ "ExtUtils::MakeMaker" => 0, "File::Spec" => 0, "Test::More" => "0.96", + "Text::Unidecode" => 0, "strict" => 0, "warnings" => 0 ); diff -Nru libemail-mime-contenttype-perl-1.022/MANIFEST libemail-mime-contenttype-perl-1.024/MANIFEST --- libemail-mime-contenttype-perl-1.022/MANIFEST 2017-08-31 13:17:02.000000000 +0000 +++ libemail-mime-contenttype-perl-1.024/MANIFEST 2020-05-24 14:19:22.000000000 +0000 @@ -1,4 +1,4 @@ -# This file was automatically generated by Dist::Zilla::Plugin::Manifest v6.010. +# This file was automatically generated by Dist::Zilla::Plugin::Manifest v6.014. Changes LICENSE MANIFEST @@ -10,7 +10,9 @@ lib/Email/MIME/ContentType.pm t/00-report-prereqs.dd t/00-report-prereqs.t -t/1.t +t/build_content_disposition.t +t/build_content_type.t t/parse_content_disposition.t +t/parse_content_type.t xt/author/pod-syntax.t xt/release/changes_has_content.t diff -Nru libemail-mime-contenttype-perl-1.022/META.json libemail-mime-contenttype-perl-1.024/META.json --- libemail-mime-contenttype-perl-1.022/META.json 2017-08-31 13:17:02.000000000 +0000 +++ libemail-mime-contenttype-perl-1.024/META.json 2020-05-24 14:19:22.000000000 +0000 @@ -1,12 +1,12 @@ { - "abstract" : "Parse a MIME Content-Type or Content-Disposition Header", + "abstract" : "Parse and build a MIME Content-Type or Content-Disposition Header", "author" : [ "Simon Cozens ", "Casey West ", "Ricardo SIGNES " ], "dynamic_config" : 0, - "generated_by" : "Dist::Zilla version 6.010, CPAN::Meta::Converter version 2.150005", + "generated_by" : "Dist::Zilla version 6.014, CPAN::Meta::Converter version 2.150010", "license" : [ "perl_5" ], @@ -32,6 +32,7 @@ "Carp" : "0", "Encode" : "2.87", "Exporter" : "5.57", + "Text::Unidecode" : "0", "strict" : "0", "warnings" : "0" } @@ -59,10 +60,10 @@ "web" : "https://github.com/rjbs/Email-MIME-ContentType" } }, - "version" : "1.022", + "version" : "1.024", "x_Dist_Zilla" : { "perl" : { - "version" : "5.024000" + "version" : "5.030002" }, "plugins" : [ { @@ -82,7 +83,7 @@ } }, "name" : "@RJBS/Git::GatherDir", - "version" : "2.042" + "version" : "2.046" }, { "class" : "Dist::Zilla::Plugin::CheckPrereqsIndexed", @@ -109,7 +110,7 @@ } }, "name" : "@RJBS/RJBS-Outdated", - "version" : "0.054" + "version" : "0.057" }, { "class" : "Dist::Zilla::Plugin::PromptIfStale", @@ -124,62 +125,62 @@ } }, "name" : "@RJBS/CPAN-Outdated", - "version" : "0.054" + "version" : "0.057" }, { "class" : "Dist::Zilla::Plugin::PruneCruft", "name" : "@RJBS/@Filter/PruneCruft", - "version" : "6.010" + "version" : "6.014" }, { "class" : "Dist::Zilla::Plugin::ManifestSkip", "name" : "@RJBS/@Filter/ManifestSkip", - "version" : "6.010" + "version" : "6.014" }, { "class" : "Dist::Zilla::Plugin::MetaYAML", "name" : "@RJBS/@Filter/MetaYAML", - "version" : "6.010" + "version" : "6.014" }, { "class" : "Dist::Zilla::Plugin::License", "name" : "@RJBS/@Filter/License", - "version" : "6.010" + "version" : "6.014" }, { "class" : "Dist::Zilla::Plugin::Readme", "name" : "@RJBS/@Filter/Readme", - "version" : "6.010" + "version" : "6.014" }, { "class" : "Dist::Zilla::Plugin::ExecDir", "name" : "@RJBS/@Filter/ExecDir", - "version" : "6.010" + "version" : "6.014" }, { "class" : "Dist::Zilla::Plugin::ShareDir", "name" : "@RJBS/@Filter/ShareDir", - "version" : "6.010" + "version" : "6.014" }, { "class" : "Dist::Zilla::Plugin::Manifest", "name" : "@RJBS/@Filter/Manifest", - "version" : "6.010" + "version" : "6.014" }, { "class" : "Dist::Zilla::Plugin::TestRelease", "name" : "@RJBS/@Filter/TestRelease", - "version" : "6.010" + "version" : "6.014" }, { "class" : "Dist::Zilla::Plugin::ConfirmRelease", "name" : "@RJBS/@Filter/ConfirmRelease", - "version" : "6.010" + "version" : "6.014" }, { "class" : "Dist::Zilla::Plugin::UploadToCPAN", "name" : "@RJBS/@Filter/UploadToCPAN", - "version" : "6.010" + "version" : "6.014" }, { "class" : "Dist::Zilla::Plugin::MakeMaker", @@ -189,58 +190,58 @@ } }, "name" : "@RJBS/MakeMaker", - "version" : "6.010" + "version" : "6.014" }, { "class" : "Dist::Zilla::Plugin::AutoPrereqs", "name" : "@RJBS/AutoPrereqs", - "version" : "6.010" + "version" : "6.014" }, { "class" : "Dist::Zilla::Plugin::Git::NextVersion", "config" : { "Dist::Zilla::Plugin::Git::NextVersion" : { "first_version" : "0.001", - "version_by_branch" : 1, + "version_by_branch" : 0, "version_regexp" : "(?^:^([0-9]+\\.[0-9]+)$)" }, "Dist::Zilla::Role::Git::Repo" : { - "git_version" : "2.13.0", + "git_version" : "2.24.3 (Apple Git-128)", "repo_root" : "." } }, "name" : "@RJBS/Git::NextVersion", - "version" : "2.042" + "version" : "2.046" }, { "class" : "Dist::Zilla::Plugin::PkgVersion", "name" : "@RJBS/PkgVersion", - "version" : "6.010" + "version" : "6.014" }, { "class" : "Dist::Zilla::Plugin::MetaConfig", "name" : "@RJBS/MetaConfig", - "version" : "6.010" + "version" : "6.014" }, { "class" : "Dist::Zilla::Plugin::MetaJSON", "name" : "@RJBS/MetaJSON", - "version" : "6.010" + "version" : "6.014" }, { "class" : "Dist::Zilla::Plugin::NextRelease", "name" : "@RJBS/NextRelease", - "version" : "6.010" + "version" : "6.014" }, { "class" : "Dist::Zilla::Plugin::Test::ChangesHasContent", "name" : "@RJBS/Test::ChangesHasContent", - "version" : "0.010" + "version" : "0.011" }, { "class" : "Dist::Zilla::Plugin::PodSyntaxTests", "name" : "@RJBS/PodSyntaxTests", - "version" : "6.010" + "version" : "6.014" }, { "class" : "Dist::Zilla::Plugin::Test::ReportPrereqs", @@ -256,7 +257,7 @@ } }, "name" : "@RJBS/TestMoreWithSubtests", - "version" : "6.010" + "version" : "6.014" }, { "class" : "Dist::Zilla::Plugin::PodWeaver", @@ -374,7 +375,7 @@ { "class" : "Dist::Zilla::Plugin::GithubMeta", "name" : "@RJBS/GithubMeta", - "version" : "0.54" + "version" : "0.58" }, { "class" : "Dist::Zilla::Plugin::Git::Check", @@ -391,19 +392,19 @@ "changelog" : "Changes" }, "Dist::Zilla::Role::Git::Repo" : { - "git_version" : "2.13.0", + "git_version" : "2.24.3 (Apple Git-128)", "repo_root" : "." } }, "name" : "@RJBS/@Git/Check", - "version" : "2.042" + "version" : "2.046" }, { "class" : "Dist::Zilla::Plugin::Git::Commit", "config" : { "Dist::Zilla::Plugin::Git::Commit" : { "add_files_in" : [], - "commit_msg" : "v%v%n%n%c" + "commit_msg" : "v%V%n%n%c" }, "Dist::Zilla::Role::Git::DirtyFiles" : { "allow_dirty" : [ @@ -414,7 +415,7 @@ "changelog" : "Changes" }, "Dist::Zilla::Role::Git::Repo" : { - "git_version" : "2.13.0", + "git_version" : "2.24.3 (Apple Git-128)", "repo_root" : "." }, "Dist::Zilla::Role::Git::StringFormatter" : { @@ -422,7 +423,7 @@ } }, "name" : "@RJBS/@Git/Commit", - "version" : "2.042" + "version" : "2.046" }, { "class" : "Dist::Zilla::Plugin::Git::Tag", @@ -431,12 +432,12 @@ "branch" : null, "changelog" : "Changes", "signed" : 0, - "tag" : "1.022", + "tag" : "1.024", "tag_format" : "%v", - "tag_message" : "v%v" + "tag_message" : "v%V" }, "Dist::Zilla::Role::Git::Repo" : { - "git_version" : "2.13.0", + "git_version" : "2.24.3 (Apple Git-128)", "repo_root" : "." }, "Dist::Zilla::Role::Git::StringFormatter" : { @@ -444,31 +445,31 @@ } }, "name" : "@RJBS/@Git/Tag", - "version" : "2.042" + "version" : "2.046" }, { "class" : "Dist::Zilla::Plugin::Git::Push", "config" : { "Dist::Zilla::Plugin::Git::Push" : { "push_to" : [ - "rjbs :", + "origin :", "github :" ], "remotes_must_exist" : 0 }, "Dist::Zilla::Role::Git::Repo" : { - "git_version" : "2.13.0", + "git_version" : "2.24.3 (Apple Git-128)", "repo_root" : "." } }, "name" : "@RJBS/@Git/Push", - "version" : "2.042" + "version" : "2.046" }, { "class" : "Dist::Zilla::Plugin::Git::Contributors", "config" : { "Dist::Zilla::Plugin::Git::Contributors" : { - "git_version" : "2.13.0", + "git_version" : "2.24.3 (Apple Git-128)", "include_authors" : 0, "include_releaser" : 1, "order_by" : "name", @@ -476,72 +477,75 @@ } }, "name" : "@RJBS/Git::Contributors", - "version" : "0.030" + "version" : "0.035" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":InstallModules", - "version" : "6.010" + "version" : "6.014" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":IncModules", - "version" : "6.010" + "version" : "6.014" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":TestFiles", - "version" : "6.010" + "version" : "6.014" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":ExtraTestFiles", - "version" : "6.010" + "version" : "6.014" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":ExecFiles", - "version" : "6.010" + "version" : "6.014" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":PerlExecFiles", - "version" : "6.010" + "version" : "6.014" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":ShareFiles", - "version" : "6.010" + "version" : "6.014" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":MainModule", - "version" : "6.010" + "version" : "6.014" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":AllFiles", - "version" : "6.010" + "version" : "6.014" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":NoFiles", - "version" : "6.010" + "version" : "6.014" } ], "zilla" : { "class" : "Dist::Zilla::Dist::Builder", "config" : { - "is_trial" : "0" + "is_trial" : 0 }, - "version" : "6.010" + "version" : "6.014" } }, "x_contributors" : [ "Matthew Green ", "Pali ", + "Ricardo Signes ", "Thomas Szukala " ], - "x_serialization_backend" : "Cpanel::JSON::XS version 3.0237" + "x_generated_by_perl" : "v5.30.2", + "x_serialization_backend" : "Cpanel::JSON::XS version 4.19", + "x_spdx_expression" : "Artistic-1.0-Perl OR GPL-1.0-or-later" } diff -Nru libemail-mime-contenttype-perl-1.022/META.yml libemail-mime-contenttype-perl-1.024/META.yml --- libemail-mime-contenttype-perl-1.022/META.yml 2017-08-31 13:17:02.000000000 +0000 +++ libemail-mime-contenttype-perl-1.024/META.yml 2020-05-24 14:19:22.000000000 +0000 @@ -1,5 +1,5 @@ --- -abstract: 'Parse a MIME Content-Type or Content-Disposition Header' +abstract: 'Parse and build a MIME Content-Type or Content-Disposition Header' author: - 'Simon Cozens ' - 'Casey West ' @@ -11,7 +11,7 @@ configure_requires: ExtUtils::MakeMaker: '0' dynamic_config: 0 -generated_by: 'Dist::Zilla version 6.010, CPAN::Meta::Converter version 2.150005' +generated_by: 'Dist::Zilla version 6.014, CPAN::Meta::Converter version 2.150010' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html @@ -21,16 +21,17 @@ Carp: '0' Encode: '2.87' Exporter: '5.57' + Text::Unidecode: '0' strict: '0' warnings: '0' resources: bugtracker: https://github.com/rjbs/Email-MIME-ContentType/issues homepage: https://github.com/rjbs/Email-MIME-ContentType repository: https://github.com/rjbs/Email-MIME-ContentType.git -version: '1.022' +version: '1.024' x_Dist_Zilla: perl: - version: '5.024000' + version: '5.030002' plugins: - class: Dist::Zilla::Plugin::Git::GatherDir @@ -46,7 +47,7 @@ Dist::Zilla::Plugin::Git::GatherDir: include_untracked: 0 name: '@RJBS/Git::GatherDir' - version: '2.042' + version: '2.046' - class: Dist::Zilla::Plugin::CheckPrereqsIndexed name: '@RJBS/CheckPrereqsIndexed' @@ -67,7 +68,7 @@ run_under_travis: 0 skip: [] name: '@RJBS/RJBS-Outdated' - version: '0.054' + version: '0.057' - class: Dist::Zilla::Plugin::PromptIfStale config: @@ -79,98 +80,98 @@ run_under_travis: 0 skip: [] name: '@RJBS/CPAN-Outdated' - version: '0.054' + version: '0.057' - class: Dist::Zilla::Plugin::PruneCruft name: '@RJBS/@Filter/PruneCruft' - version: '6.010' + version: '6.014' - class: Dist::Zilla::Plugin::ManifestSkip name: '@RJBS/@Filter/ManifestSkip' - version: '6.010' + version: '6.014' - class: Dist::Zilla::Plugin::MetaYAML name: '@RJBS/@Filter/MetaYAML' - version: '6.010' + version: '6.014' - class: Dist::Zilla::Plugin::License name: '@RJBS/@Filter/License' - version: '6.010' + version: '6.014' - class: Dist::Zilla::Plugin::Readme name: '@RJBS/@Filter/Readme' - version: '6.010' + version: '6.014' - class: Dist::Zilla::Plugin::ExecDir name: '@RJBS/@Filter/ExecDir' - version: '6.010' + version: '6.014' - class: Dist::Zilla::Plugin::ShareDir name: '@RJBS/@Filter/ShareDir' - version: '6.010' + version: '6.014' - class: Dist::Zilla::Plugin::Manifest name: '@RJBS/@Filter/Manifest' - version: '6.010' + version: '6.014' - class: Dist::Zilla::Plugin::TestRelease name: '@RJBS/@Filter/TestRelease' - version: '6.010' + version: '6.014' - class: Dist::Zilla::Plugin::ConfirmRelease name: '@RJBS/@Filter/ConfirmRelease' - version: '6.010' + version: '6.014' - class: Dist::Zilla::Plugin::UploadToCPAN name: '@RJBS/@Filter/UploadToCPAN' - version: '6.010' + version: '6.014' - class: Dist::Zilla::Plugin::MakeMaker config: Dist::Zilla::Role::TestRunner: default_jobs: 9 name: '@RJBS/MakeMaker' - version: '6.010' + version: '6.014' - class: Dist::Zilla::Plugin::AutoPrereqs name: '@RJBS/AutoPrereqs' - version: '6.010' + version: '6.014' - class: Dist::Zilla::Plugin::Git::NextVersion config: Dist::Zilla::Plugin::Git::NextVersion: first_version: '0.001' - version_by_branch: 1 + version_by_branch: 0 version_regexp: (?^:^([0-9]+\.[0-9]+)$) Dist::Zilla::Role::Git::Repo: - git_version: 2.13.0 + git_version: '2.24.3 (Apple Git-128)' repo_root: . name: '@RJBS/Git::NextVersion' - version: '2.042' + version: '2.046' - class: Dist::Zilla::Plugin::PkgVersion name: '@RJBS/PkgVersion' - version: '6.010' + version: '6.014' - class: Dist::Zilla::Plugin::MetaConfig name: '@RJBS/MetaConfig' - version: '6.010' + version: '6.014' - class: Dist::Zilla::Plugin::MetaJSON name: '@RJBS/MetaJSON' - version: '6.010' + version: '6.014' - class: Dist::Zilla::Plugin::NextRelease name: '@RJBS/NextRelease' - version: '6.010' + version: '6.014' - class: Dist::Zilla::Plugin::Test::ChangesHasContent name: '@RJBS/Test::ChangesHasContent' - version: '0.010' + version: '0.011' - class: Dist::Zilla::Plugin::PodSyntaxTests name: '@RJBS/PodSyntaxTests' - version: '6.010' + version: '6.014' - class: Dist::Zilla::Plugin::Test::ReportPrereqs name: '@RJBS/Test::ReportPrereqs' @@ -182,7 +183,7 @@ phase: test type: requires name: '@RJBS/TestMoreWithSubtests' - version: '6.010' + version: '6.014' - class: Dist::Zilla::Plugin::PodWeaver config: @@ -274,7 +275,7 @@ - class: Dist::Zilla::Plugin::GithubMeta name: '@RJBS/GithubMeta' - version: '0.54' + version: '0.58' - class: Dist::Zilla::Plugin::Git::Check config: @@ -287,16 +288,16 @@ allow_dirty_match: [] changelog: Changes Dist::Zilla::Role::Git::Repo: - git_version: 2.13.0 + git_version: '2.24.3 (Apple Git-128)' repo_root: . name: '@RJBS/@Git/Check' - version: '2.042' + version: '2.046' - class: Dist::Zilla::Plugin::Git::Commit config: Dist::Zilla::Plugin::Git::Commit: add_files_in: [] - commit_msg: v%v%n%n%c + commit_msg: v%V%n%n%c Dist::Zilla::Role::Git::DirtyFiles: allow_dirty: - Changes @@ -304,12 +305,12 @@ allow_dirty_match: [] changelog: Changes Dist::Zilla::Role::Git::Repo: - git_version: 2.13.0 + git_version: '2.24.3 (Apple Git-128)' repo_root: . Dist::Zilla::Role::Git::StringFormatter: time_zone: local name: '@RJBS/@Git/Commit' - version: '2.042' + version: '2.046' - class: Dist::Zilla::Plugin::Git::Tag config: @@ -317,87 +318,90 @@ branch: ~ changelog: Changes signed: 0 - tag: '1.022' + tag: '1.024' tag_format: '%v' - tag_message: v%v + tag_message: v%V Dist::Zilla::Role::Git::Repo: - git_version: 2.13.0 + git_version: '2.24.3 (Apple Git-128)' repo_root: . Dist::Zilla::Role::Git::StringFormatter: time_zone: local name: '@RJBS/@Git/Tag' - version: '2.042' + version: '2.046' - class: Dist::Zilla::Plugin::Git::Push config: Dist::Zilla::Plugin::Git::Push: push_to: - - 'rjbs :' + - 'origin :' - 'github :' remotes_must_exist: 0 Dist::Zilla::Role::Git::Repo: - git_version: 2.13.0 + git_version: '2.24.3 (Apple Git-128)' repo_root: . name: '@RJBS/@Git/Push' - version: '2.042' + version: '2.046' - class: Dist::Zilla::Plugin::Git::Contributors config: Dist::Zilla::Plugin::Git::Contributors: - git_version: 2.13.0 + git_version: '2.24.3 (Apple Git-128)' include_authors: 0 include_releaser: 1 order_by: name paths: [] name: '@RJBS/Git::Contributors' - version: '0.030' + version: '0.035' - class: Dist::Zilla::Plugin::FinderCode name: ':InstallModules' - version: '6.010' + version: '6.014' - class: Dist::Zilla::Plugin::FinderCode name: ':IncModules' - version: '6.010' + version: '6.014' - class: Dist::Zilla::Plugin::FinderCode name: ':TestFiles' - version: '6.010' + version: '6.014' - class: Dist::Zilla::Plugin::FinderCode name: ':ExtraTestFiles' - version: '6.010' + version: '6.014' - class: Dist::Zilla::Plugin::FinderCode name: ':ExecFiles' - version: '6.010' + version: '6.014' - class: Dist::Zilla::Plugin::FinderCode name: ':PerlExecFiles' - version: '6.010' + version: '6.014' - class: Dist::Zilla::Plugin::FinderCode name: ':ShareFiles' - version: '6.010' + version: '6.014' - class: Dist::Zilla::Plugin::FinderCode name: ':MainModule' - version: '6.010' + version: '6.014' - class: Dist::Zilla::Plugin::FinderCode name: ':AllFiles' - version: '6.010' + version: '6.014' - class: Dist::Zilla::Plugin::FinderCode name: ':NoFiles' - version: '6.010' + version: '6.014' zilla: class: Dist::Zilla::Dist::Builder config: is_trial: '0' - version: '6.010' + version: '6.014' x_contributors: - 'Matthew Green ' - 'Pali ' + - 'Ricardo Signes ' - 'Thomas Szukala ' -x_serialization_backend: 'YAML::Tiny version 1.70' +x_generated_by_perl: v5.30.2 +x_serialization_backend: 'YAML::Tiny version 1.73' +x_spdx_expression: 'Artistic-1.0-Perl OR GPL-1.0-or-later' diff -Nru libemail-mime-contenttype-perl-1.022/README libemail-mime-contenttype-perl-1.024/README --- libemail-mime-contenttype-perl-1.022/README 2017-08-31 13:17:02.000000000 +0000 +++ libemail-mime-contenttype-perl-1.024/README 2020-05-24 14:19:22.000000000 +0000 @@ -1,9 +1,7 @@ - - This archive contains the distribution Email-MIME-ContentType, -version 1.022: +version 1.024: - Parse a MIME Content-Type or Content-Disposition Header + Parse and build a MIME Content-Type or Content-Disposition Header This software is copyright (c) 2004 by Simon Cozens. @@ -11,5 +9,4 @@ the same terms as the Perl 5 programming language system itself. -This README file was generated by Dist::Zilla::Plugin::Readme v6.010. - +This README file was generated by Dist::Zilla::Plugin::Readme v6.014. diff -Nru libemail-mime-contenttype-perl-1.022/t/00-report-prereqs.dd libemail-mime-contenttype-perl-1.024/t/00-report-prereqs.dd --- libemail-mime-contenttype-perl-1.022/t/00-report-prereqs.dd 2017-08-31 13:17:02.000000000 +0000 +++ libemail-mime-contenttype-perl-1.024/t/00-report-prereqs.dd 2020-05-24 14:19:22.000000000 +0000 @@ -15,6 +15,7 @@ 'Carp' => '0', 'Encode' => '2.87', 'Exporter' => '5.57', + 'Text::Unidecode' => '0', 'strict' => '0', 'warnings' => '0' } diff -Nru libemail-mime-contenttype-perl-1.022/t/1.t libemail-mime-contenttype-perl-1.024/t/1.t --- libemail-mime-contenttype-perl-1.022/t/1.t 2017-08-31 13:17:02.000000000 +0000 +++ libemail-mime-contenttype-perl-1.024/t/1.t 1970-01-01 00:00:00.000000000 +0000 @@ -1,182 +0,0 @@ -# vim:ft=perl -use Test::More 'no_plan'; -BEGIN { use_ok("Email::MIME::ContentType"); } - -my %ct_tests = ( - '' => { type => "text", subtype => "plain", - attributes => { charset => "us-ascii" } }, - - "text/plain" => { type => "text", subtype => "plain", attributes=>{} }, - - 'text/plain; charset=us-ascii' => { type => "text", subtype => "plain", attributes => { charset => "us-ascii" } }, - 'text/plain; charset="us-ascii"' => { type => "text", subtype => "plain", attributes => { charset => "us-ascii" } }, - "text/plain; charset=us-ascii (Plain text)" => { type => "text", subtype => "plain", attributes => { charset => "us-ascii" } }, - - 'text/plain; charset=ISO-8859-1' => { type => "text", subtype => "plain", attributes => { charset => "ISO-8859-1" } }, - 'text/plain; charset="ISO-8859-1"' => { type => "text", subtype => "plain", attributes => { charset => "ISO-8859-1" } }, - 'text/plain; charset="ISO-8859-1" (comment)' => { type => "text", subtype => "plain", attributes => { charset => "ISO-8859-1" } }, - - '(comment) text/plain (comment); (comment) charset=ISO-8859-1 (comment)' => { type => "text", subtype => "plain", attributes => { charset => "ISO-8859-1" } }, - '(comment \( \\\\) (comment) text/plain (comment) (comment) ; (comment) (comment) charset=ISO-8859-1 (comment)' => { type => "text", subtype => "plain", attributes => { charset => "ISO-8859-1" } }, - 'text/plain; (comment (nested ()comment)another comment)() charset=ISO-8859-1' => { type => "text", subtype => "plain", attributes => { charset => "ISO-8859-1" } }, - 'text/plain (comment \(not nested ()comment\)\)(nested\(comment())); charset=ISO-8859-1' => { type => "text", subtype => "plain", attributes => { charset => "ISO-8859-1" } }, - - "application/foo" => - { type => "application", subtype => "foo", attributes=>{} }, - "multipart/mixed; boundary=unique-boundary-1" => - { type => "multipart", subtype => "mixed", - attributes => { boundary => "unique-boundary-1" } - }, - 'message/external-body; access-type=local-file; name="/u/nsb/Me.jpeg"' => - { type => "message", subtype => "external-body", - attributes => { "access-type" => "local-file", - "name" => "/u/nsb/Me.jpeg" } - }, - 'multipart/mixed; boundary="----------=_1026452699-10321-0" ' => { - 'type' => 'multipart', - 'subtype' => 'mixed', - 'attributes' => { - 'boundary' => '----------=_1026452699-10321-0' - } - }, - 'multipart/report; boundary= "=_0c5bb6a163fe08545fb49e4a=73e476c3-cd5a-5ba3-b910-2e1563f157b8_="' => { - 'type' => 'multipart', - 'subtype' => 'report', - 'attributes' => { - 'boundary' => '=_0c5bb6a163fe08545fb49e4a=73e476c3-cd5a-5ba3-b910-2e1563f157b8_=' - } - }, - 'multipart/report; boundary=' . " \t" . '"=_0c5bb6a163fe08545fb49e4a=73e476c3-cd5a-5ba3-b910-2e1563f157b8_="' => { - 'type' => 'multipart', - 'subtype' => 'report', - 'attributes' => { - 'boundary' => '=_0c5bb6a163fe08545fb49e4a=73e476c3-cd5a-5ba3-b910-2e1563f157b8_=' - } - }, - - 'message/external-body; access-type=URL; URL*0="ftp://"; URL*1="cs.utk.edu/pub/moore/bulk-mailer/bulk-mailer.tar"' => { - 'type' => 'message', - 'subtype' => 'external-body', - 'attributes' => { - 'access-type' => 'URL', - 'url' => 'ftp://cs.utk.edu/pub/moore/bulk-mailer/bulk-mailer.tar', - } - }, - 'message/external-body; access-type=URL; URL="ftp://cs.utk.edu/pub/moore/bulk-mailer/bulk-mailer.tar"' => { - 'type' => 'message', - 'subtype' => 'external-body', - 'attributes' => { - 'access-type' => 'URL', - 'url' => 'ftp://cs.utk.edu/pub/moore/bulk-mailer/bulk-mailer.tar', - } - }, - - "application/x-stuff; title*=us-ascii'en-us'This%20is%20%2A%2A%2Afun%2A%2A%2A" => { - 'type' => 'application', - 'subtype' => 'x-stuff', - 'attributes' => { - 'title' => 'This is ***fun***' - } - }, - "application/x-stuff; title*=us-ascii''This%20is%20%2A%2A%2Afun%2A%2A%2A" => { - 'type' => 'application', - 'subtype' => 'x-stuff', - 'attributes' => { - 'title' => 'This is ***fun***' - } - }, - "application/x-stuff; title*=''This%20is%20%2A%2A%2Afun%2A%2A%2A" => { - 'type' => 'application', - 'subtype' => 'x-stuff', - 'attributes' => { - 'title' => 'This is ***fun***' - } - }, - "application/x-stuff; title*='en-us'This%20is%20%2A%2A%2Afun%2A%2A%2A" => { - 'type' => 'application', - 'subtype' => 'x-stuff', - 'attributes' => { - 'title' => 'This is ***fun***' - } - }, - - q(application/x-stuff; title*0*=us-ascii'en'This%20is%20even%20more%20; title*1*=%2A%2A%2Afun%2A%2A%2A%20; title*2="isn't it!") => { - 'type' => 'application', - 'subtype' => 'x-stuff', - 'attributes' => { - 'title' => "This is even more ***fun*** isn't it!" - } - }, - q(application/x-stuff; title*0*='en'This%20is%20even%20more%20; title*1*=%2A%2A%2Afun%2A%2A%2A%20; title*2="isn't it!") => { - 'type' => 'application', - 'subtype' => 'x-stuff', - 'attributes' => { - 'title' => "This is even more ***fun*** isn't it!" - } - }, - q(application/x-stuff; title*0*=''This%20is%20even%20more%20; title*1*=%2A%2A%2Afun%2A%2A%2A%20; title*2="isn't it!") => { - 'type' => 'application', - 'subtype' => 'x-stuff', - 'attributes' => { - 'title' => "This is even more ***fun*** isn't it!" - } - }, - q(application/x-stuff; title*0*=us-ascii''This%20is%20even%20more%20; title*1*=%2A%2A%2Afun%2A%2A%2A%20; title*2="isn't it!") => { - 'type' => 'application', - 'subtype' => 'x-stuff', - 'attributes' => { - 'title' => "This is even more ***fun*** isn't it!" - } - }, - - 'text/plain; attribute="value\"value\\\\value\(value\>\<\)\@\,\;\:\/\]\[\?\=value value"; charset=us-ascii' => { - 'type' => 'text', - 'subtype' => 'plain', - 'attributes' => { - 'attribute' => 'value"value\\value(value><)@,;:/][?=value value', - 'charset' => 'us-ascii', - }, - }, - - qq(text/plain;\r\n charset=us-ascii;\r\n attribute="\r\n value1 \r\n value2\r\n value3\r\n value4\r\n "\r\n ) => { - 'type' => 'text', - 'subtype' => 'plain', - 'attributes' => { - 'attribute' => ' value1 value2 value3 value4 ', - 'charset' => 'us-ascii', - }, - }, -); - -my %non_strict_ct_tests = ( - "text/plain;" => { type => "text", subtype => "plain", attributes=>{} }, - "text/plain; " => { type => "text", subtype => "plain", attributes=>{} }, - 'image/jpeg; x-mac-type="3F3F3F3F"; x-mac-creator="3F3F3F3F" name="file name.jpg";' => { type => "image", subtype => "jpeg", attributes => { 'x-mac-type' => "3F3F3F3F", 'x-mac-creator' => "3F3F3F3F", 'name' => "file name.jpg" } }, - "text/plain; key=very long value" => { type => "text", subtype => "plain", attributes => { key => "very long value" } }, - "text/plain; key=very long value key2=value2" => { type => "text", subtype => "plain", attributes => { key => "very long value", key2 => "value2" } }, - 'multipart/mixed; boundary = "--=_Next_Part_24_Nov_2016_08.09.21"' => { type => "multipart", subtype => "mixed", attributes => { boundary => "--=_Next_Part_24_Nov_2016_08.09.21" } }, -); - -sub test { - my ($string, $expect, $info) = @_; - # So stupid. -- rjbs, 2013-08-10 - $expect->{discrete} = $expect->{type}; - $expect->{composite} = $expect->{subtype}; - - local $_; - $info =~ s/\r/\\r/g; - $info =~ s/\n/\\n/g; - is_deeply(parse_content_type($string), $expect, $info); -} - -for (sort keys %ct_tests) { - test($_, $ct_tests{$_}, "Can parse C-T <$_>"); -} - -local $Email::MIME::ContentType::STRICT_PARAMS = 0; -for (sort keys %ct_tests) { - test($_, $ct_tests{$_}, "Can parse non-strict C-T <$_>"); -} -for (sort keys %non_strict_ct_tests) { - test($_, $non_strict_ct_tests{$_}, "Can parse non-strict C-T <$_>"); -} diff -Nru libemail-mime-contenttype-perl-1.022/t/build_content_disposition.t libemail-mime-contenttype-perl-1.024/t/build_content_disposition.t --- libemail-mime-contenttype-perl-1.022/t/build_content_disposition.t 1970-01-01 00:00:00.000000000 +0000 +++ libemail-mime-contenttype-perl-1.024/t/build_content_disposition.t 2020-05-24 14:19:22.000000000 +0000 @@ -0,0 +1,112 @@ +# vim:ft=perl +use strict; +use warnings; + +use Test::More 'no_plan'; +BEGIN { use_ok('Email::MIME::ContentType'); } + +my %cd_tests = ( + 'inline' => { type => 'inline', attributes => {} }, + 'attachment' => { type => 'attachment', attributes => {} }, + + 'attachment; filename=genome.jpeg; modification-date="Wed, 12 Feb 1997 16:29:51 -0500"' => { + type => 'attachment', + attributes => { + filename => 'genome.jpeg', + 'modification-date' => 'Wed, 12 Feb 1997 16:29:51 -0500' + } + }, + + q(attachment; filename*=UTF-8''genom%C3%A9.jpeg; filename=genome.jpeg; modification-date="Wed, 12 Feb 1997 16:29:51 -0500") => { + type => 'attachment', + attributes => { + filename => "genom\x{E9}.jpeg", + 'modification-date' => 'Wed, 12 Feb 1997 16:29:51 -0500' + } + }, + + q(attachment; filename=loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong; modification-date="Wed, 12 Feb 1997 16:29:51 -0500") => { + type => 'attachment', + attributes => { + filename => 'loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong', + 'modification-date' => 'Wed, 12 Feb 1997 16:29:51 -0500' + } + }, + + q(attachment; filename*0=loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo; filename*1=ong; filename=looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo...; modification-date="Wed, 12 Feb 1997 16:29:51 -0500") => { + type => 'attachment', + attributes => { + filename => 'looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong', + 'modification-date' => 'Wed, 12 Feb 1997 16:29:51 -0500' + } + }, + + q(attachment; filename="l\\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong"; modification-date="Wed, 12 Feb 1997 16:29:51 -0500") => { + type => 'attachment', + attributes => { + filename => 'l"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong', + 'modification-date' => 'Wed, 12 Feb 1997 16:29:51 -0500' + } + }, + + q(attachment; filename*0="l\\"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo"; filename*1="ong"; filename="l\"ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo..."; modification-date="Wed, 12 Feb 1997 16:29:51 -0500") => { + type => 'attachment', + attributes => { + filename => 'l"ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong', + 'modification-date' => 'Wed, 12 Feb 1997 16:29:51 -0500' + } + }, + + q(attachment; filename*=UTF-8''%C3%A9loooooooooooooooooooooooooooooooooooooooooooooooooong; filename=eloooooooooooooooooooooooooooooooooooooooooooooooooong; modification-date="Wed, 12 Feb 1997 16:29:51 -0500") => { + type => 'attachment', + attributes => { + filename => "\x{E9}loooooooooooooooooooooooooooooooooooooooooooooooooong", + 'modification-date' => 'Wed, 12 Feb 1997 16:29:51 -0500' + } + }, + + q(attachment; filename*0*=UTF-8''%C3%A9loooooooooooooooooooooooooooooooooooooooooooooooooo; filename*1*=ong; filename=elooooooooooooooooooooooooooooooooooooooooooooooooooong; modification-date="Wed, 12 Feb 1997 16:29:51 -0500") => { + type => 'attachment', + attributes => { + filename => "\x{E9}looooooooooooooooooooooooooooooooooooooooooooooooooong", + 'modification-date' => 'Wed, 12 Feb 1997 16:29:51 -0500' + } + }, + + q(attachment; filename*=UTF-8''%C3%A9%C3%A9%C3%A9%C3%A9%C3%A9%C3%A9%C3%A9%C3%A9%C3%A9; filename=eeeeeeeee) => { + type => 'attachment', + attributes => { + filename => "\x{E9}\x{E9}\x{E9}\x{E9}\x{E9}\x{E9}\x{E9}\x{E9}\x{E9}" + } + }, + + q(attachment; filename*0*=UTF-8''%C3%A9%C3%A9%C3%A9%C3%A9%C3%A9%C3%A9%C3%A9%C3%A9%C3%A9; filename*1*=%C3%A9; filename=eeeeeeeeee) => { + type => 'attachment', + attributes => { + filename => "\x{E9}\x{E9}\x{E9}\x{E9}\x{E9}\x{E9}\x{E9}\x{E9}\x{E9}\x{E9}" + } + }, + + q(attachment; filename="UTF-8''name") => { + type => 'attachment', + attributes => { + filename => "UTF-8''name" + } + }, +); + +sub test { + my ($expect, $struct) = @_; + local $_; + my $info = $expect; + $info =~ s/\r/\\r/g; + $info =~ s/\n/\\n/g; + my $got = build_content_disposition($struct); + is($got, $expect, "Can build C-D <$info>"); + my $parsed = parse_content_disposition($got); + is_deeply($parsed, $struct, "Can parse C-D <$info>"); +} + +for (sort keys %cd_tests) { + test($_, $cd_tests{$_}); +} diff -Nru libemail-mime-contenttype-perl-1.022/t/build_content_type.t libemail-mime-contenttype-perl-1.024/t/build_content_type.t --- libemail-mime-contenttype-perl-1.022/t/build_content_type.t 1970-01-01 00:00:00.000000000 +0000 +++ libemail-mime-contenttype-perl-1.024/t/build_content_type.t 2020-05-24 14:19:22.000000000 +0000 @@ -0,0 +1,107 @@ +# vim:ft=perl +use strict; +use warnings; + +use Test::More 'no_plan'; +BEGIN { use_ok('Email::MIME::ContentType'); } + +my %ct_tests = ( + 'text/plain' => { type => 'text', subtype => 'plain', attributes => {} }, + 'text/plain; charset=us-ascii' => { type => 'text', subtype => 'plain', attributes => { charset => 'us-ascii' } }, + 'text/plain; charset=ISO-8859-1' => { type => 'text', subtype => 'plain', attributes => { charset => 'ISO-8859-1' } }, + 'text/plain; charset=us-ascii; format=flowed' => { type => 'text', subtype => 'plain', attributes => { charset => 'us-ascii', format => 'flowed' } }, + 'application/foo' => { type => 'application', subtype => 'foo', attributes => {} }, + 'multipart/mixed; boundary=unique-boundary-1' => { type => 'multipart', subtype => 'mixed', attributes => { boundary => 'unique-boundary-1' } }, + + 'message/external-body; access-type=local-file; name="/u/nsb/Me.jpeg"' => { + type => 'message', + subtype => 'external-body', + attributes => { + 'access-type' => 'local-file', + 'name' => '/u/nsb/Me.jpeg' + } + }, + 'multipart/mixed; boundary="----------=_1026452699-10321-0"' => { + 'type' => 'multipart', + 'subtype' => 'mixed', + 'attributes' => { + 'boundary' => '----------=_1026452699-10321-0' + } + }, + 'multipart/report; boundary="=_0c5bb6a163fe08545fb49e4a=73e476c3-cd5a-5ba3-b910-2e1563f157b8_="' => { + 'type' => 'multipart', + 'subtype' => 'report', + 'attributes' => { + 'boundary' => '=_0c5bb6a163fe08545fb49e4a=73e476c3-cd5a-5ba3-b910-2e1563f157b8_=' + } + }, + + 'message/external-body; access-type=URL; url="ftp://cs.utk.edu/pub/moore/bulk-mailer/looooooooooong/bulk-mailer.tar"' => { + 'type' => 'message', + 'subtype' => 'external-body', + 'attributes' => { + 'access-type' => 'URL', + 'url' => 'ftp://cs.utk.edu/pub/moore/bulk-mailer/looooooooooong/bulk-mailer.tar', + } + }, + q(message/external-body; access-type=URL; url*0="ftp://cs.utk.edu/pub/moore/bulk-mailer/looooooooooooong/bulk-mailer."; url*1="tar"; url="ftp://cs.utk.edu/pub/moore/bulk-mailer/looooooooooooong/bulk-mailer...") => { + 'type' => 'message', + 'subtype' => 'external-body', + 'attributes' => { + 'access-type' => 'URL', + 'url' => 'ftp://cs.utk.edu/pub/moore/bulk-mailer/looooooooooooong/bulk-mailer.tar', + } + }, + 'message/external-body; access-type=URL; url="ftp://cs.utk.edu/pub/moore/bulk-mailer/bulk-mailer.tar"' => { + 'type' => 'message', + 'subtype' => 'external-body', + 'attributes' => { + 'access-type' => 'URL', + 'url' => 'ftp://cs.utk.edu/pub/moore/bulk-mailer/bulk-mailer.tar', + } + }, + + q(application/x-stuff; title*=UTF-8''This%20is%20%2A%2A%2Afun%2A%2A%2A%20%C2%A9; title="This is ***fun*** (c)") => { + 'type' => 'application', + 'subtype' => 'x-stuff', + 'attributes' => { + 'title' => "This is ***fun*** \N{U+A9}" + } + }, + + q(application/x-stuff; title*0*=UTF-8''This%20is%20even%20more%20%2A%2A%2Afun%2A%2A%2A%20%C2%A9%20i; title*1*=sn%27t%20it!; title="This is even more ***fun*** (c) isn't it!") => { + 'type' => 'application', + 'subtype' => 'x-stuff', + 'attributes' => { + 'title' => "This is even more ***fun*** \N{U+A9} isn't it!" + } + }, + + 'text/plain; attribute="value\"value\\\\value(value><)@,;:/][?=value value"; charset=us-ascii' => { + 'type' => 'text', + 'subtype' => 'plain', + 'attributes' => { + 'attribute' => 'value"value\\value(value><)@,;:/][?=value value', + 'charset' => 'us-ascii', + }, + }, + +); + +sub test { + my ($expect, $struct) = @_; + local $_; + my $info = $expect; + $info =~ s/\r/\\r/g; + $info =~ s/\n/\\n/g; + my $got = build_content_type($struct); + is($got, $expect, "Can build C-T <$info>"); + my $parsed = parse_content_type($got); + delete $parsed->{discrete}; + delete $parsed->{composite}; + is_deeply($parsed, $struct, "Can parse C-T <$info>"); +} + +for (sort keys %ct_tests) { + test($_, $ct_tests{$_}); +} diff -Nru libemail-mime-contenttype-perl-1.022/t/parse_content_type.t libemail-mime-contenttype-perl-1.024/t/parse_content_type.t --- libemail-mime-contenttype-perl-1.022/t/parse_content_type.t 1970-01-01 00:00:00.000000000 +0000 +++ libemail-mime-contenttype-perl-1.024/t/parse_content_type.t 2020-05-24 14:19:22.000000000 +0000 @@ -0,0 +1,182 @@ +# vim:ft=perl +use Test::More 'no_plan'; +BEGIN { use_ok("Email::MIME::ContentType"); } + +my %ct_tests = ( + '' => { type => "text", subtype => "plain", + attributes => { charset => "us-ascii" } }, + + "text/plain" => { type => "text", subtype => "plain", attributes=>{} }, + + 'text/plain; charset=us-ascii' => { type => "text", subtype => "plain", attributes => { charset => "us-ascii" } }, + 'text/plain; charset="us-ascii"' => { type => "text", subtype => "plain", attributes => { charset => "us-ascii" } }, + "text/plain; charset=us-ascii (Plain text)" => { type => "text", subtype => "plain", attributes => { charset => "us-ascii" } }, + + 'text/plain; charset=ISO-8859-1' => { type => "text", subtype => "plain", attributes => { charset => "ISO-8859-1" } }, + 'text/plain; charset="ISO-8859-1"' => { type => "text", subtype => "plain", attributes => { charset => "ISO-8859-1" } }, + 'text/plain; charset="ISO-8859-1" (comment)' => { type => "text", subtype => "plain", attributes => { charset => "ISO-8859-1" } }, + + '(comment) text/plain (comment); (comment) charset=ISO-8859-1 (comment)' => { type => "text", subtype => "plain", attributes => { charset => "ISO-8859-1" } }, + '(comment \( \\\\) (comment) text/plain (comment) (comment) ; (comment) (comment) charset=ISO-8859-1 (comment)' => { type => "text", subtype => "plain", attributes => { charset => "ISO-8859-1" } }, + 'text/plain; (comment (nested ()comment)another comment)() charset=ISO-8859-1' => { type => "text", subtype => "plain", attributes => { charset => "ISO-8859-1" } }, + 'text/plain (comment \(not nested ()comment\)\)(nested\(comment())); charset=ISO-8859-1' => { type => "text", subtype => "plain", attributes => { charset => "ISO-8859-1" } }, + + "application/foo" => + { type => "application", subtype => "foo", attributes=>{} }, + "multipart/mixed; boundary=unique-boundary-1" => + { type => "multipart", subtype => "mixed", + attributes => { boundary => "unique-boundary-1" } + }, + 'message/external-body; access-type=local-file; name="/u/nsb/Me.jpeg"' => + { type => "message", subtype => "external-body", + attributes => { "access-type" => "local-file", + "name" => "/u/nsb/Me.jpeg" } + }, + 'multipart/mixed; boundary="----------=_1026452699-10321-0" ' => { + 'type' => 'multipart', + 'subtype' => 'mixed', + 'attributes' => { + 'boundary' => '----------=_1026452699-10321-0' + } + }, + 'multipart/report; boundary= "=_0c5bb6a163fe08545fb49e4a=73e476c3-cd5a-5ba3-b910-2e1563f157b8_="' => { + 'type' => 'multipart', + 'subtype' => 'report', + 'attributes' => { + 'boundary' => '=_0c5bb6a163fe08545fb49e4a=73e476c3-cd5a-5ba3-b910-2e1563f157b8_=' + } + }, + 'multipart/report; boundary=' . " \t" . '"=_0c5bb6a163fe08545fb49e4a=73e476c3-cd5a-5ba3-b910-2e1563f157b8_="' => { + 'type' => 'multipart', + 'subtype' => 'report', + 'attributes' => { + 'boundary' => '=_0c5bb6a163fe08545fb49e4a=73e476c3-cd5a-5ba3-b910-2e1563f157b8_=' + } + }, + + 'message/external-body; access-type=URL; URL*0="ftp://"; URL*1="cs.utk.edu/pub/moore/bulk-mailer/bulk-mailer.tar"' => { + 'type' => 'message', + 'subtype' => 'external-body', + 'attributes' => { + 'access-type' => 'URL', + 'url' => 'ftp://cs.utk.edu/pub/moore/bulk-mailer/bulk-mailer.tar', + } + }, + 'message/external-body; access-type=URL; URL="ftp://cs.utk.edu/pub/moore/bulk-mailer/bulk-mailer.tar"' => { + 'type' => 'message', + 'subtype' => 'external-body', + 'attributes' => { + 'access-type' => 'URL', + 'url' => 'ftp://cs.utk.edu/pub/moore/bulk-mailer/bulk-mailer.tar', + } + }, + + "application/x-stuff; title*=us-ascii'en-us'This%20is%20%2A%2A%2Afun%2A%2A%2A" => { + 'type' => 'application', + 'subtype' => 'x-stuff', + 'attributes' => { + 'title' => 'This is ***fun***' + } + }, + "application/x-stuff; title*=us-ascii''This%20is%20%2A%2A%2Afun%2A%2A%2A" => { + 'type' => 'application', + 'subtype' => 'x-stuff', + 'attributes' => { + 'title' => 'This is ***fun***' + } + }, + "application/x-stuff; title*=''This%20is%20%2A%2A%2Afun%2A%2A%2A" => { + 'type' => 'application', + 'subtype' => 'x-stuff', + 'attributes' => { + 'title' => 'This is ***fun***' + } + }, + "application/x-stuff; title*='en-us'This%20is%20%2A%2A%2Afun%2A%2A%2A" => { + 'type' => 'application', + 'subtype' => 'x-stuff', + 'attributes' => { + 'title' => 'This is ***fun***' + } + }, + + q(application/x-stuff; title*0*=us-ascii'en'This%20is%20even%20more%20; title*1*=%2A%2A%2Afun%2A%2A%2A%20; title*2="isn't it!") => { + 'type' => 'application', + 'subtype' => 'x-stuff', + 'attributes' => { + 'title' => "This is even more ***fun*** isn't it!" + } + }, + q(application/x-stuff; title*0*='en'This%20is%20even%20more%20; title*1*=%2A%2A%2Afun%2A%2A%2A%20; title*2="isn't it!") => { + 'type' => 'application', + 'subtype' => 'x-stuff', + 'attributes' => { + 'title' => "This is even more ***fun*** isn't it!" + } + }, + q(application/x-stuff; title*0*=''This%20is%20even%20more%20; title*1*=%2A%2A%2Afun%2A%2A%2A%20; title*2="isn't it!") => { + 'type' => 'application', + 'subtype' => 'x-stuff', + 'attributes' => { + 'title' => "This is even more ***fun*** isn't it!" + } + }, + q(application/x-stuff; title*0*=us-ascii''This%20is%20even%20more%20; title*1*=%2A%2A%2Afun%2A%2A%2A%20; title*2="isn't it!") => { + 'type' => 'application', + 'subtype' => 'x-stuff', + 'attributes' => { + 'title' => "This is even more ***fun*** isn't it!" + } + }, + + 'text/plain; attribute="value\"value\\\\value\(value\>\<\)\@\,\;\:\/\]\[\?\=value value"; charset=us-ascii' => { + 'type' => 'text', + 'subtype' => 'plain', + 'attributes' => { + 'attribute' => 'value"value\\value(value><)@,;:/][?=value value', + 'charset' => 'us-ascii', + }, + }, + + qq(text/plain;\r\n charset=us-ascii;\r\n attribute="\r\n value1 \r\n value2\r\n value3\r\n value4\r\n "\r\n ) => { + 'type' => 'text', + 'subtype' => 'plain', + 'attributes' => { + 'attribute' => ' value1 value2 value3 value4 ', + 'charset' => 'us-ascii', + }, + }, +); + +my %non_strict_ct_tests = ( + "text/plain;" => { type => "text", subtype => "plain", attributes=>{} }, + "text/plain; " => { type => "text", subtype => "plain", attributes=>{} }, + 'image/jpeg; x-mac-type="3F3F3F3F"; x-mac-creator="3F3F3F3F" name="file name.jpg";' => { type => "image", subtype => "jpeg", attributes => { 'x-mac-type' => "3F3F3F3F", 'x-mac-creator' => "3F3F3F3F", 'name' => "file name.jpg" } }, + "text/plain; key=very long value" => { type => "text", subtype => "plain", attributes => { key => "very long value" } }, + "text/plain; key=very long value key2=value2" => { type => "text", subtype => "plain", attributes => { key => "very long value", key2 => "value2" } }, + 'multipart/mixed; boundary = "--=_Next_Part_24_Nov_2016_08.09.21"' => { type => "multipart", subtype => "mixed", attributes => { boundary => "--=_Next_Part_24_Nov_2016_08.09.21" } }, +); + +sub test { + my ($string, $expect, $info) = @_; + # So stupid. -- rjbs, 2013-08-10 + $expect->{discrete} = $expect->{type}; + $expect->{composite} = $expect->{subtype}; + + local $_; + $info =~ s/\r/\\r/g; + $info =~ s/\n/\\n/g; + is_deeply(parse_content_type($string), $expect, $info); +} + +for (sort keys %ct_tests) { + test($_, $ct_tests{$_}, "Can parse C-T <$_>"); +} + +local $Email::MIME::ContentType::STRICT_PARAMS = 0; +for (sort keys %ct_tests) { + test($_, $ct_tests{$_}, "Can parse non-strict C-T <$_>"); +} +for (sort keys %non_strict_ct_tests) { + test($_, $non_strict_ct_tests{$_}, "Can parse non-strict C-T <$_>"); +} diff -Nru libemail-mime-contenttype-perl-1.022/xt/release/changes_has_content.t libemail-mime-contenttype-perl-1.024/xt/release/changes_has_content.t --- libemail-mime-contenttype-perl-1.022/xt/release/changes_has_content.t 2017-08-31 13:17:02.000000000 +0000 +++ libemail-mime-contenttype-perl-1.024/xt/release/changes_has_content.t 2020-05-24 14:19:22.000000000 +0000 @@ -1,11 +1,10 @@ -#!perl - use Test::More tests => 2; note 'Checking Changes'; my $changes_file = 'Changes'; -my $newver = '1.022'; +my $newver = '1.024'; my $trial_token = '-TRIAL'; +my $encoding = 'UTF-8'; SKIP: { ok(-e $changes_file, "$changes_file file exists") @@ -16,8 +15,6 @@ done_testing; -# _get_changes copied and adapted from Dist::Zilla::Plugin::Git::Commit -# by Jerome Quelin sub _get_changes { my $newver = shift; @@ -25,6 +22,10 @@ # parse changelog to find commit message open(my $fh, '<', $changes_file) or die "cannot open $changes_file: $!"; my $changelog = join('', <$fh>); + if ($encoding) { + require Encode; + $changelog = Encode::decode($encoding, $changelog, Encode::FB_CROAK()); + } close $fh; my @content =