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

Wallace Reis wreis at bestpractical.com
Thu Nov 13 17:13:18 EST 2014


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

- Log -----------------------------------------------------------------
commit 7c95ce15e07a4614638916e5d33828f3c6bef830
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 assembling the MIME object. It worths mentioning that we are not
    using MIME::Field::ParamVal to assemble the parts, because at the moment
    it doesn't know how to do so correctly.
    
    Fixes: #29753.

diff --git a/lib/RT/Attachment.pm b/lib/RT/Attachment.pm
index 4f1763c..b3428f7 100644
--- a/lib/RT/Attachment.pm
+++ b/lib/RT/Attachment.pm
@@ -80,6 +80,7 @@ use MIME::Base64;
 use MIME::QuotedPrint;
 use MIME::Body;
 use RT::Util 'mime_recommended_filename';
+use URI;
 
 sub _OverlayAccessible {
   {
@@ -469,6 +470,44 @@ recursively added to the entity.
 
 =cut
 
+sub _EncodeHeaderToMIME {
+    my ( $self, $header_name, $header_val ) = @_;
+    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 = q{UTF-8''} . URI->new(
+                    Encode::encode('UTF-8', $value)
+                );
+                $value =~ s/(["\\])/\\$1/g;
+                $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 +518,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