#!/usr/bin/perl -w -T ### ### UTF-8 CONTENT, edit with UTF-8 locale/editor ### use strict; use lib '.'; use lib 't'; use SATest; sa_t_init("get_headers"); use Test::More; use Mail::SpamAssassin; use constant HAS_EMAIL_ADDRESS_XS => eval { require Email::Address::XS; }; my $tests = 52; $tests *= 2 if (HAS_EMAIL_ADDRESS_XS); plan tests => $tests; ############################################## # initialize SpamAssassin my ($sa,$mail,$pms); sub new_saobj { $pms->finish() if $pms; $mail->finish() if $mail; $sa->finish() if $sa; undef $sa; undef $mail; undef $pms; $sa = create_saobj({'dont_copy_prefs' => 1}); $sa->init(0); $mail = $sa->parse( get_raw_headers()."\n\nBlah\n" ); $pms = Mail::SpamAssassin::PerMsgStatus->new($sa, $mail); } sub try { my ($try, $expect) = @_; my $parser = $Mail::SpamAssassin::Util::header_address_parser == 1 ? 'internal' : 'Email::Address::XS'; my $result; my @results = $pms->get($try); if (!@results) { $result = undef; } else { $result = join("\\n", @results); } # Verify that legacy non-list and new list context get() are the same # non-list will return only first value which we compare my $result2 = $pms->get($try, undef); if (!defined $result2 && !defined $result) { # Ok } elsif (defined $result2 && !defined $result) { my $lr2 = $result2; $lr2 =~ s/\t/\\t/gs; $lr2 =~ s/\n/\\n/gs; warn "try: $parser: '$try' get() context differs! list: undef non-list: '$lr2'\n"; return 0; } elsif (!defined $result2 && defined $result) { my $lr = $results[0]; $lr =~ s/\t/\\t/gs; $lr =~ s/\n/\\n/gs; warn "try: $parser: '$try' get() context differs! list: '$lr' non-list: undef\n"; return 0; } elsif ($result2 ne $results[0]) { my $lr = $results[0]; $lr =~ s/\t/\\t/gs; $lr =~ s/\n/\\n/gs; my $lr2 = $result2; $lr2 =~ s/\t/\\t/gs; $lr2 =~ s/\n/\\n/gs; warn "try: $parser: '$try' get() context differs! list: '$lr' non-list: '$lr2'\n"; return 0; } # Whitelist some differences if ($parser eq 'Email::Address::XS') { # try: Email::Address::XS: 'From5:addr' failed! expect: 'noreply@foobar.com\ninfo=foobar.com@mlsend.com' got: 'noreply@foobar.com' return 1 if $try eq 'From5:addr' && $result eq 'noreply@foobar.com'; # try: Email::Address::XS: 'From5:name' failed! expect: undef got: '=?UTF-8?Q? Foobar _' return 1 if $try eq 'From5:name' && $result eq '=?UTF-8?Q? Foobar _'; # try: Email::Address::XS: 'From9:name' failed! expect: 'Mr\nSpam' got: 'Mr, Spam \nSpam' return 1 if $try eq 'From9:name' && $result eq 'Mr, Spam \nSpam'; } if (!defined $expect) { if (defined $result) { my $lr=$result;$lr=~s/\t/\\t/gs;$lr =~s/\n/\\n/gs; warn "try: $parser: '$try' failed! expect: undef got: '$lr'\n"; return 0; } else { return 1; } } elsif (!defined $result) { if (defined $expect) { my $le=$expect;$le=~s/\t/\\t/gs;$le =~s/\n/\\n/gs; warn "try: $parser: '$try' failed! expect: '$le' got: undef\n"; return 0; } else { return 1; } } if ($expect eq $result) { return 1; } else { my $le=$expect;$le=~s/\t/\\t/gs;$le =~s/\n/\\n/gs; my $lr=$result;$lr=~s/\t/\\t/gs;$lr =~s/\n/\\n/gs; warn "try: $parser: '$try' failed! expect: '$le' got: '$lr'\n"; return 0; } } ############################################## sub get_raw_headers { return q{To1: To2: jm@foo To3: jm@foo (Foo Blah) To4: jm@foo, jm@bar To5: display: jm@foo (Foo Blah), jm@bar ; To6: Foo Blah To7: "Foo Blah" To8: "'Foo Blah'" To9: "_$B!z8=6b$=$N>l$GEv$?$j!*!zEv_(B_$B$?$k!*!)$/$8!z7|>^%\%s%P! To10: "Some User" <"Another User"@foo> To11: "Some User"@foo To12: "Some User " To13: "Some User <\"Some User\"@bar>" Hdr1: foo bar baz To_bug5201_a: =?ISO-2022-JP?B?GyRCQjw+ZRsoQiAbJEI1V0JlGyhC?= To_bug5201_b: =?ISO-2022-JP?B?GyRCNiVHTyM3JSQlcyU1JSQlQCE8PnBKcxsoQg==?= To_bug5201_c: "joe+foobar@example.com" From1: Foo Blah From2: , "'Foo Blah'" , =?utf-8?Q?'Baz Bl=C3=A4h'?= From3: =?utf-8?Q?"B=C3=A4z=C3=A4=C3=A4_=28baz=40blah.?= =?utf-8?Q?com=29"?= From4: "Mr., Spam"(comment) From5: =?UTF-8?Q?"Foobar"_?=, =?utf-8?Q?"Foobar"?= X-Note: From6 is really \\\" - escaped perl backslashes.. From6: "Mr. (foo@bar)\\\\\\"" (comment) From7: "Mr. \(foo\@bar)\\\\\\\\\\"" (comment) From8: "Foo Blah \(via Foobar\)" , "Foo Blah (via Foobar)" From9: Mr, Spam }; } ############################################## for (1 .. 2) { ## parser loop if ($_ == 2 && !HAS_EMAIL_ADDRESS_XS) { warn "Not running Email::Address::XS tests, module missing\n"; next; } $Mail::SpamAssassin::Util::header_address_parser = $_; new_saobj(); ok(try('To1:addr', 'jm@foo')); ok(try('To1:name', undef)); ok(try('To2:addr', 'jm@foo')); ok(try('To2:name', undef)); ok(try('To3:addr', 'jm@foo')); ok(try('To3:name', 'Foo Blah')); ok(try('To4:addr', 'jm@foo\njm@bar')); ok(try('To4:name', undef)); ok(try('To5:addr', 'jm@foo\njm@bar')); ok(try('To5:name', 'Foo Blah')); ok(try('To6:addr', 'jm@foo')); ok(try('To6:name', 'Foo Blah')); ok(try('To7:addr', 'jm@foo')); ok(try('To7:name', 'Foo Blah')); ok(try('To8:addr', 'jm@foo')); ok(try('To8:name', 'Foo Blah')); ok(try('To9:addr', 'jm@foo')); ok(try('To9:name', '_$B!z8=6b$=$N>l$GEv$?$j!*!zEv_(B_$B$?$k!*!)$/$8!z7|>^%%s%P!')); ok(try('To13:addr', 'jm@foo')); ok(try('To13:name', 'Some User <"Some User"@bar>')); ok(try('Hdr1', "foo bar baz\n")); ok(try('Hdr1:raw', " foo \n bar\n\tbaz \n \n")); ok(try('To_bug5201_a:addr', 'jm@foo')); ok(try('To_bug5201_a:name', '村上 久代')); ok(try('To_bug5201_b:addr', 'jm@foo')); ok(try('To_bug5201_b:name', '競馬7インサイダー情報')); ok(try('To_bug5201_c:addr', 'joe+foobar@example.com')); ok(try('To_bug5201_c:name', undef)); ok(try('From1:addr', undef)); ok(try('From1:name', 'Foo Blah')); ok(try('From2:addr', 'jm@foo\njm@bar\nbaz@blaeh')); ok(try('From2:name', 'Foo Blah\nBaz Bläh')); ok(try('From3:addr', 'jm@foo')); ok(try('From3:name', 'Bäzää (baz@blah.com)')); ok(try('From4:addr', 'spam@blah.com')); ok(try('From4:name', 'Mr., Spam')); ok(try('From5:addr', 'noreply@foobar.com\ninfo=foobar.com@mlsend.com')); ok(try('From5:name', undef)); ok(try('From6:addr', 'spam@blah.com')); ok(try('From6:name', 'Mr. (foo@bar)"')); ok(try('From7:addr', 'spam@blah.com')); ok(try('From7:name', 'Mr. (foo@bar)"')); ok(try('From8:addr', 'no-reply@foobar.com\nno-reply@foobar.com')); ok(try('From8:name', 'Foo Blah (via Foobar)\nFoo Blah (via Foobar)')); ok(try('From9:addr', 'spam@blah.com')); ok(try('From9:name', 'Mr\nSpam')); } ## end parser loop $pms->finish() if $pms; $mail->finish() if $mail; $sa->finish() if $sa;