@@ -247,4 +247,86 @@ This is the original forwarded email
247247</div></blockquote></div><hr class="clear"></div></div>
248248EOF
249249
250+ diag " multipart/related with a text/plain root (no text/html) must still display the body" ;
251+ {
252+ my $path
253+ = RT::Test::get_relocatable_file( ' multipart-related-text-plain' , ( File::Spec-> updir(), ' data' , ' emails' ) );
254+ my $email = RT::Test-> file_content($path );
255+
256+ my ( $status , $id ) = RT::Test-> send_via_mailgate($email );
257+ is( $status >> 8, 0, ' mail gateway exited normally' );
258+ ok( $id , " created ticket #$id from multipart/related message" );
259+
260+ my $ticket = RT::Ticket-> new( RT-> SystemUser );
261+ $ticket -> Load($id );
262+ is( $ticket -> Id, $id , " loaded ticket #$id " );
263+
264+ # Confirm the message really has the structure under test before asserting
265+ # on how it is displayed.
266+ my $txn = $ticket -> Transactions-> First;
267+ my $top = $txn -> Attachments-> First;
268+ is( lc $top -> ContentType, ' multipart/related' , ' top-level part is multipart/related' );
269+
270+ my %child_types = map { lc ( $_ -> ContentType ) => 1 }
271+ grep { $_ -> Parent == $top -> Id } @{ $txn -> Attachments-> ItemsArrayRef };
272+ ok( $child_types {' text/plain' }, ' has a text/plain child part' );
273+ ok( !$child_types {' text/html' }, ' has no text/html child part' );
274+
275+ $m -> get_ok( " /Ticket/History.html?id=$id " , ' fetched ticket history' );
276+
277+ my @bodies = $m -> dom-> find(' div.messagebody' )-> map (' all_text' )-> each ;
278+ ok( ( grep {/ UNIQUEPLAINBODY/ } @bodies ), ' text/plain body of the multipart/related message is displayed inline' )
279+ or diag " Rendered message bodies: " . join ( ' ||' , @bodies );
280+ }
281+
282+ # Returns the concatenated text of every rendered message body for a ticket.
283+ sub history_bodies {
284+ my $tid = shift ;
285+ $m -> get_ok( " /Ticket/History.html?id=$tid " , " fetched history for #$tid " );
286+ return join ' ||' , $m -> dom-> find(' div.messagebody' )-> map (' all_text' )-> each ;
287+ }
288+
289+ # Used by both the PreferRichText on/off cases below.
290+ my $alt_id ;
291+
292+ diag " nested multipart/alternative -> multipart/related(html): exactly one textual part renders" ;
293+ {
294+ # The common MUA structure (Outlook, Apple Mail, Gmail):
295+ # multipart/alternative
296+ # text/plain # plain downgrade
297+ # multipart/related
298+ # text/html # composed rich body
299+ # image/png # inline CID image
300+ # The text/html part's direct parent is the multipart/related. RT must
301+ # show exactly one textual part, never both (the "duplicate message"
302+ # regression fixed in 4a38585f75) and never neither. With PreferRichText
303+ # on (the default) the rich body wins.
304+ my $path = RT::Test::get_relocatable_file( ' multipart-alternative-related-html' ,
305+ ( File::Spec-> updir(), ' data' , ' emails' ) );
306+ my $email = RT::Test-> file_content($path );
307+
308+ my ( $status , $id ) = RT::Test-> send_via_mailgate($email );
309+ is( $status >> 8, 0, ' mail gateway exited normally' );
310+ ok( $id , " created ticket #$id from nested alternative/related message" );
311+ $alt_id = $id ;
312+
313+ my $bodies = history_bodies($id );
314+ like( $bodies , qr / HTMLBODYMARKER/ , ' PreferRichText on: text/html body is displayed' );
315+ unlike( $bodies , qr / PLAINDOWNGRADEMARKER/ , ' PreferRichText on: text/plain downgrade is suppressed (no duplicate)' );
316+ }
317+
318+ diag " same message with PreferRichText off: the plain downgrade wins" ;
319+ {
320+ # PreferRichText is overridable, so flip it via the user preference rather
321+ # than restarting the server with a new system config.
322+ my $root = RT::User-> new( RT-> SystemUser );
323+ $root -> Load(' root' );
324+ my ( $ok , $msg ) = $root -> SetPreferences( RT-> System, { PreferRichText => 0 } );
325+ ok( $ok , " set root's PreferRichText preference to 0" ) or diag $msg ;
326+
327+ my $bodies = history_bodies($alt_id );
328+ like( $bodies , qr / PLAINDOWNGRADEMARKER/ , ' PreferRichText off: text/plain downgrade is displayed' );
329+ unlike( $bodies , qr / HTMLBODYMARKER/ , ' PreferRichText off: text/html body is suppressed (no duplicate)' );
330+ }
331+
250332done_testing;
0 commit comments