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

Wallace Reis wreis at bestpractical.com
Tue Nov 11 16:01:24 EST 2014


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

- Log -----------------------------------------------------------------
commit b312f51558df0f962da73a56d3414ed2d95254f8
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..27fb258 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 'encode_utf8';
+use URI;
 
 sub _OverlayAccessible {
   {
@@ -469,6 +471,34 @@ recursively added to the entity.
 
 =cut
 
+sub _EncodeHeaderToMIME {
+    my ( $self, $header_name, $header_val ) = @_;
+    my $encode_header = sub { URI->new( encode_utf8(shift) )->as_string };
+    if ($header_name =~ /^Content-/i) {
+        my $params = MIME::Field::ParamVal->parse_params($header_val);
+        foreach my $v ( values %$params ) {
+            $v = $encode_header->($v);
+        }
+        $header_val = bless({}, 'MIME::Field::ParamVal')->set($params)->stringify;
+    }
+    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 = $encode_header->($v);
+                $address->$field($v);
+            }
+        }
+        $header_val = join ', ', map $_->format, @addresses;
+    }
+    else {
+        $header_val = RT::Interface::Email::EncodeToMIME(
+            String => $header_val
+        );
+    }
+}
+
 sub ContentAsMIME {
     my $self = shift;
     my %opts = (
@@ -479,7 +509,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..275a4fe 100644
--- a/t/web/ticket_forward.t
+++ b/t/web/ticket_forward.t
@@ -1,6 +1,8 @@
 use strict;
 use warnings;
-
+use utf8;
+use Encode 'encode_utf8';
+    
 use RT::Test tests => undef;
 use File::Spec;
 my $att_file = File::Spec->catfile( RT::Test->temp_directory, 'attachment' );
@@ -36,18 +38,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 +110,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(encode_utf8("awesome.pátch"));
     $attach->headers('Content-Type' => 'text/x-diff');
     $m->set_fields(
         Subject => 'test forward, empty content but attachments',
@@ -123,8 +125,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 +145,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/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 +155,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    => encode_utf8('"Tést" <test at example.com>'),
         Subject => 'attachments for everyone',
         Type    => 'multipart/mixed',
     );
@@ -214,6 +216,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: \"T\%C3\%A9st/ );
 
     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