[Rt-commit] rt branch, 4.2/rt-forward-encoding, created. rt-4.2.9-6-gf5f4e55

Wallace Reis wreis at bestpractical.com
Thu Nov 13 11:25:47 EST 2014


The branch, 4.2/rt-forward-encoding has been created
        at  f5f4e55d03b70e7b1c57d3e58080113c051f847a (commit)

- Log -----------------------------------------------------------------
commit f5f4e55d03b70e7b1c57d3e58080113c051f847a
Author: Wallace Reis <wreis at bestpractical.com>
Date:   Tue Nov 4 19:32:23 2014 -0200

    Forwarded messages break attachments with non-ASCII filenames
    
    On RT 4.2.3, forwarded messages lost header info cause RT takes every
    header from DB and apply MIME transfer encoding to each as a full line,
    thus losing information about the internal structure of the header, if
    it has any.
    
    This aim to fix by applying the correct encoding according to rfc2231
    before assemblying the MIME object.
    
    Fixes: #29753.

diff --git a/lib/RT/Attachment.pm b/lib/RT/Attachment.pm
index 4f1763c..1b9738d 100644
--- a/lib/RT/Attachment.pm
+++ b/lib/RT/Attachment.pm
@@ -80,6 +80,8 @@ use MIME::Base64;
 use MIME::QuotedPrint;
 use MIME::Body;
 use RT::Util 'mime_recommended_filename';
+use Encode ();
+use URI;
 
 sub _OverlayAccessible {
   {
@@ -469,6 +471,44 @@ recursively added to the entity.
 
 =cut
 
+sub _EncodeHeaderToMIME {
+    my ( $self, $header_name, $header_val ) = @_;
+    my $encode_header = sub {
+        return q{UTF-8''} . URI->new( Encode::encode('UTF-8', shift) );
+    };
+    if ($header_name =~ /^Content-/i) {
+        my $params = MIME::Field::ParamVal->parse_params($header_val);
+        $header_val = delete $params->{'_'};
+        foreach my $key ( sort keys %$params ) {
+            my $value = $params->{$key};
+            if ( $value =~ /[^\x00-\x7f]/ ) { # check for non-ASCII
+                $value = $encode_header->($value);
+                $header_val .= qq{; ${key}*="$value"};
+            }
+            else {
+                $header_val .= qq{; $key="$value"};
+            }
+        }
+    }
+    elsif ( $header_name =~ /^(?:Resent-)?(?:To|From|B?Cc|Sender|Reply-To)$/i ) {
+        my @addresses = RT::EmailParser->ParseEmailAddress( $header_val );
+        foreach my $address ( @addresses ) {
+            foreach my $field (qw(phrase comment)) {
+                my $v = $address->$field() or next;
+                $v = RT::Interface::Email::EncodeToMIME( String => $v );
+                $address->$field($v);
+            }
+        }
+        $header_val = join ', ', map $_->format, @addresses;
+    }
+    else {
+        $header_val = RT::Interface::Email::EncodeToMIME(
+            String => $header_val
+        );
+    }
+    return $header_val;
+}
+
 sub ContentAsMIME {
     my $self = shift;
     my %opts = (
@@ -479,7 +519,9 @@ sub ContentAsMIME {
     my $entity = MIME::Entity->new();
     foreach my $header ($self->SplitHeaders) {
         my ($h_key, $h_val) = split /:/, $header, 2;
-        $entity->head->add( $h_key, RT::Interface::Email::EncodeToMIME( String => $h_val ) );
+        $entity->head->add(
+            $h_key, $self->_EncodeHeaderToMIME($h_key, $h_val)
+        );
     }
     
     # since we want to return original content, let's use original encoding
diff --git a/t/web/ticket_forward.t b/t/web/ticket_forward.t
index a298b3c..8339e1a 100644
--- a/t/web/ticket_forward.t
+++ b/t/web/ticket_forward.t
@@ -36,18 +36,18 @@ diag "Forward Ticket" if $ENV{TEST_VERBOSE};
     $m->submit_form(
         form_name => 'ForwardMessage',
         fields    => {
-            To  => 'rt-to at example.com, rt-too at example.com',
+            To  => '"Foo" <rt-foo at example.com>, rt-too at example.com',
             Cc  => 'rt-cc at example.com',
             Bcc => 'root',
         },
         button => 'ForwardAndReturn'
     );
     $m->content_contains(
-        'Forwarded Ticket to <rt-to at example.com>, <rt-too at example.com>, <rt-cc at example.com>, root (Enoch Root)',
+        'Forwarded Ticket to Foo <rt-foo at example.com>, <rt-too at example.com>, <rt-cc at example.com>, root (Enoch Root)',
         'txn msg' );
     my ($mail) = RT::Test->fetch_caught_mails;
     like( $mail, qr!Subject: test forward!,           'Subject field' );
-    like( $mail, qr!To: .*?rt-to\@example.com!i,      'To field' );
+    like( $mail, qr!To: .*?rt-foo\@example.com!i,     'To field' );
     like( $mail, qr!To: .*?rt-too\@example.com!i,     'To field' );
     like( $mail, qr!Cc: rt-cc\@example.com!i,         'Cc field' );
     like( $mail, qr!Bcc: root\@localhost!i,  'Bcc field' );
@@ -108,7 +108,7 @@ diag "Forward Transaction with attachments but empty content" if $ENV{TEST_VERBO
 
     $m->form_name('TicketCreate');
     my $attach = $m->current_form->find_input('Attach');
-    $attach->filename("awesome.patch");
+    $attach->filename('awesome.pátch');
     $attach->headers('Content-Type' => 'text/x-diff');
     $m->set_fields(
         Subject => 'test forward, empty content but attachments',
@@ -123,8 +123,8 @@ diag "Forward Transaction with attachments but empty content" if $ENV{TEST_VERBO
         Attach  => RT::Test::get_relocatable_file('bpslogo.png', '..', 'data'), # an image!
     );
     $m->submit;
-    $m->content_like( qr/Ticket \d+ created/i, 'created the ticket' );
-    $m->content_like( qr/awesome\.patch/,   'uploaded patch file' );
+    $m->content_like( qr/Ticket \d+ created/i,  'created the ticket' );
+    $m->content_like( qr/awesome.p\%C3\%A1tch/, 'uploaded patch file' );
     $m->content_like( qr/text\/x-diff/,     'uploaded patch file content type' );
     $m->content_like( qr/bpslogo\.png/,     'uploaded image file' );
     $m->content_like( qr/image\/png/,       'uploaded image file content type' );
@@ -143,7 +143,7 @@ diag "Forward Transaction with attachments but empty content" if $ENV{TEST_VERBO
     like( $mail, qr/Subject: test forward, empty content but attachments/, 'Subject field' );
     like( $mail, qr/To: rt-test\@example.com/,         'To field' );
     like( $mail, qr/This is a forward of transaction/, 'content' );
-    like( $mail, qr/awesome\.patch/,                   'att file name' );
+    like( $mail, qr/filename\*\=\"UTF\-8\'\'awesome.p\%C3\%A1tch\"/, 'att file name' );
     like( $mail, qr/this is an attachment/,            'att content' );
     like( $mail, qr/text\/x-diff/,                     'att content type' );
     like( $mail, qr/bpslogo\.png/,                     'att image file name' );
@@ -153,7 +153,7 @@ diag "Forward Transaction with attachments but empty content" if $ENV{TEST_VERBO
 diag "Forward Transaction with attachments but no 'content' part" if $ENV{TEST_VERBOSE};
 {
     my $mime = MIME::Entity->build(
-        From    => 'test at example.com',
+        From    => '"Tést" <test at example.com>',
         Subject => 'attachments for everyone',
         Type    => 'multipart/mixed',
     );
@@ -214,6 +214,7 @@ diag "Forward Transaction with attachments but no 'content' part" if $ENV{TEST_V
     like( $forward_txn, qr/This is a forward of transaction/, 'forward description' );
     like( $forward_ticket, qr/Subject: $tag test forward, attachments but no "content"/, 'Subject field is from ticket' );
     like( $forward_ticket, qr/This is a forward of ticket/, 'forward description' );
+    like( $forward_ticket, qr/From: \=\?UTF-8\?.* \<test\@example\.com\>/i );
 
     for my $mail ($forward_txn, $forward_ticket) {
         like( $mail, qr/To: rt-test\@example.com/,         'To field' );

-----------------------------------------------------------------------


More information about the rt-commit mailing list