From 39121c758dcc919b5fde4c893d488916e26d3140 Mon Sep 17 00:00:00 2001 From: Todd Kennedy Date: Mon, 7 Mar 2011 10:26:15 -0800 Subject: [PATCH] Fix display of inline images Inline images can be specified in two different ways -- explicitly with a Content-Disposition of "inline" or implicitly with no Content-Disposition. We correctly handled the former. For the later, we now default to an "inline" disposition if one was not specified. This is acceptable per RFC 822 which states: Content-Disposition is an optional header field. In its absence, the MUA may use whatever presentation method it deems suitable. Additionally, if the disposition is not specified by the server, we need to look at the Content-Type header for the file name. bug 2824698 Change-Id: I146f7a67197b4e737e5f82a3d570e0f74e23fa35 --- .../emailcommon/internet/MimeUtility.java | 11 +++- .../emailcommon/internet/MimeUtilityTest.java | 54 +++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/emailcommon/src/com/android/emailcommon/internet/MimeUtility.java b/emailcommon/src/com/android/emailcommon/internet/MimeUtility.java index 69330d76b..51b333573 100644 --- a/emailcommon/src/com/android/emailcommon/internet/MimeUtility.java +++ b/emailcommon/src/com/android/emailcommon/internet/MimeUtility.java @@ -412,8 +412,17 @@ public class MimeUtility { dispositionType = MimeUtility.getHeaderParameter(disposition, null); dispositionFilename = MimeUtility.getHeaderParameter(disposition, "filename"); } + // An attachment filename can be defined in either the Content-Disposition header + // or the Content-Type header. Content-Disposition is preferred, so we only try + // the Content-Type header as a last resort. + if (dispositionFilename == null) { + String contentType = part.getContentType(); + dispositionFilename = MimeUtility.getHeaderParameter(contentType, "name"); + } boolean attachmentDisposition = "attachment".equalsIgnoreCase(dispositionType); - boolean inlineDisposition = "inline".equalsIgnoreCase(dispositionType); + // If a disposition is not specified, default to "inline" + boolean inlineDisposition = dispositionType == null + || "inline".equalsIgnoreCase(dispositionType); // A guess that this part is intended to be an attachment boolean attachment = attachmentDisposition diff --git a/tests/src/com/android/emailcommon/internet/MimeUtilityTest.java b/tests/src/com/android/emailcommon/internet/MimeUtilityTest.java index b49a211b7..9942511fa 100644 --- a/tests/src/com/android/emailcommon/internet/MimeUtilityTest.java +++ b/tests/src/com/android/emailcommon/internet/MimeUtilityTest.java @@ -30,6 +30,8 @@ import com.android.emailcommon.mail.MessageTestUtils.MultipartBuilder; import android.test.suitebuilder.annotation.SmallTest; +import java.util.ArrayList; + import junit.framework.TestCase; /** @@ -345,6 +347,58 @@ public class MimeUtilityTest extends TestCase { final Part actual2_2 = MimeUtility.findPartByContentId(msg2, cid2); assertEquals("found part from mixed multipart", cid2bp, actual2_2); } + + /** Tests for findPartByContentId(Part part, String contentId) */ + public void testCollectParts() throws MessagingException, Exception { + // golden cases; these will marked as attachments + final String cid1 = ""; + final Part cid1bp = MessageTestUtils.bodyPart("image/gif; name=\"im1.gif\"", cid1); + final String cid2 = ""; + final Part cid2bp = MessageTestUtils.bodyPart("image/gif", cid2); + cid2bp.addHeader(MimeHeader.HEADER_CONTENT_DISPOSITION, "inline; filename=\"im2.gif\""); + final String cid3 = ""; + final Part cid3bp = MessageTestUtils.bodyPart("image/gif", cid3); + cid3bp.addHeader(MimeHeader.HEADER_CONTENT_DISPOSITION, "attachment; filename=\"im3.gif\""); + // error cases; these will NOT be marked as attachments + final String cid4 = ""; + final Part cid4bp = MessageTestUtils.bodyPart("image/gif", cid4); // no name attr + final String cid5 = ""; + final Part cid5bp = MessageTestUtils.bodyPart("image/gif", cid5); + cid5bp.addHeader(MimeHeader.HEADER_CONTENT_DISPOSITION, "inline"); // no filename attr + + // Default content disposition + final ArrayList view1 = new ArrayList(); + final ArrayList attach1 = new ArrayList(); + MimeUtility.collectParts(cid1bp, view1, attach1); + assertEquals(1, attach1.size()); + assertEquals(attach1.get(0), cid1bp); + + // Explicit content disposition of "inline" + final ArrayList view2 = new ArrayList(); + final ArrayList attach2 = new ArrayList(); + MimeUtility.collectParts(cid2bp, view2, attach2); + assertEquals(1, attach2.size()); + assertEquals(attach2.get(0), cid2bp); + + // Explicit content disposition of "attachment" + final ArrayList view3 = new ArrayList(); + final ArrayList attach3 = new ArrayList(); + MimeUtility.collectParts(cid3bp, view3, attach3); + assertEquals(1, attach3.size()); + assertEquals(attach3.get(0), cid3bp); + + // Default content disposition; missing name attribute on content-type + final ArrayList view4 = new ArrayList(); + final ArrayList attach4 = new ArrayList(); + MimeUtility.collectParts(cid4bp, view4, attach4); + assertEquals(0, attach4.size()); + + // Content disposition of "inline"; missing filename attribute + final ArrayList view5 = new ArrayList(); + final ArrayList attach5 = new ArrayList(); + MimeUtility.collectParts(cid5bp, view5, attach5); + assertEquals(0, attach5.size()); + } /** Tests for getTextFromPart(Part part) */ public void testGetTextFromPartContentTypeCase() throws MessagingException {