diff options
-rw-r--r-- | src/com/android/email/LegacyConversions.java | 77 | ||||
-rw-r--r-- | tests/src/com/android/email/LegacyConversionsTest.java | 88 |
2 files changed, 138 insertions, 27 deletions
diff --git a/src/com/android/email/LegacyConversions.java b/src/com/android/email/LegacyConversions.java index 76f757634..528358497 100644 --- a/src/com/android/email/LegacyConversions.java +++ b/src/com/android/email/LegacyConversions.java @@ -45,6 +45,7 @@ import com.android.emailcommon.provider.Mailbox; import com.android.emailcommon.utility.AttachmentUtilities; import com.android.mail.providers.UIProvider; import com.android.mail.utils.LogUtils; +import com.google.common.annotations.VisibleForTesting; import org.apache.commons.io.IOUtils; @@ -184,29 +185,19 @@ public class LegacyConversions { } /** - * Add a single attachment part to the message - * - * This will skip adding attachments if they are already found in the attachments table. - * The heuristic for this will fail (false-positive) if two identical attachments are - * included in a single POP3 message. - * TODO: Fix that, by (elsewhere) simulating an mLocation value based on the attachments - * position within the list of multipart/mixed elements. This would make every POP3 attachment - * unique, and might also simplify the code (since we could just look at the positions, and - * ignore the filename, etc.) + * Convert a MIME Part object into an Attachment object. Separated for unit testing. * - * TODO: Take a closer look at encoding and deal with it if necessary. - * - * @param context a context for file operations - * @param localMessage the attachments will be built against this message - * @param part a single attachment part from POP or IMAP + * @param part MIME part object to convert + * @return Populated Account object + * @throws MessagingException */ - public static void addOneAttachment(final Context context, - final EmailContent.Message localMessage, final Part part) - throws MessagingException, IOException { + @VisibleForTesting + protected static Attachment mimePartToAttachment(final Part part) throws MessagingException { // Transfer fields from mime format to provider format final String contentType = MimeUtility.unfoldAndDecode(part.getContentType()); + String name = MimeUtility.getHeaderParameter(contentType, "name"); - if (name == null) { + if (TextUtils.isEmpty(name)) { final String contentDisposition = MimeUtility.unfoldAndDecode(part.getDisposition()); name = MimeUtility.getHeaderParameter(contentDisposition, "filename"); } @@ -214,10 +205,15 @@ public class LegacyConversions { // Incoming attachment: Try to pull size from disposition (if not downloaded yet) long size = 0; final String disposition = part.getDisposition(); - if (disposition != null) { + if (!TextUtils.isEmpty(disposition)) { String s = MimeUtility.getHeaderParameter(disposition, "size"); - if (s != null) { - size = Long.parseLong(s); + if (!TextUtils.isEmpty(s)) { + try { + size = Long.parseLong(s); + } catch (final NumberFormatException e) { + LogUtils.d(LogUtils.TAG, e, "Could not decode size \"%s\" from attachment part", + size); + } } } @@ -226,17 +222,43 @@ public class LegacyConversions { final String[] partIds = part.getHeader(MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA); final String partId = partIds != null ? partIds[0] : null; + final Attachment localAttachment = new Attachment(); + // Run the mime type through inferMimeType in case we have something generic and can do // better using the filename extension - final Attachment localAttachment = new Attachment(); localAttachment.mMimeType = AttachmentUtilities.inferMimeType(name, part.getMimeType()); localAttachment.mFileName = name; - localAttachment.mSize = size; // May be reset below if file handled + localAttachment.mSize = size; localAttachment.mContentId = part.getContentId(); - localAttachment.setContentUri(null); // Will be rewritten by saveAttachmentBody - localAttachment.mMessageKey = localMessage.mId; + localAttachment.setContentUri(null); // Will be rewritten by saveAttachmentBody localAttachment.mLocation = partId; - localAttachment.mEncoding = "B"; // TODO - convert other known encodings + localAttachment.mEncoding = "B"; // TODO - convert other known encodings + + return localAttachment; + } + + /** + * Add a single attachment part to the message + * + * This will skip adding attachments if they are already found in the attachments table. + * The heuristic for this will fail (false-positive) if two identical attachments are + * included in a single POP3 message. + * TODO: Fix that, by (elsewhere) simulating an mLocation value based on the attachments + * position within the list of multipart/mixed elements. This would make every POP3 attachment + * unique, and might also simplify the code (since we could just look at the positions, and + * ignore the filename, etc.) + * + * TODO: Take a closer look at encoding and deal with it if necessary. + * + * @param context a context for file operations + * @param localMessage the attachments will be built against this message + * @param part a single attachment part from POP or IMAP + */ + public static void addOneAttachment(final Context context, + final EmailContent.Message localMessage, final Part part) + throws MessagingException, IOException { + final Attachment localAttachment = mimePartToAttachment(part); + localAttachment.mMessageKey = localMessage.mId; localAttachment.mAccountKey = localMessage.mAccountKey; if (DEBUG_ATTACHMENTS) { @@ -469,7 +491,8 @@ public class LegacyConversions { * @param contentId as referenced from cid: uris in the message body (if applicable) * @param content unencoded bytes */ - private static void addAttachmentPart(final Multipart mp, final String contentType, + @VisibleForTesting + protected static void addAttachmentPart(final Multipart mp, final String contentType, final Long contentSize, final String filename, final String contentId, final InputStream content) throws MessagingException { final Base64Body body = new Base64Body(content); diff --git a/tests/src/com/android/email/LegacyConversionsTest.java b/tests/src/com/android/email/LegacyConversionsTest.java index d3e7dcd6a..1656f4b3d 100644 --- a/tests/src/com/android/email/LegacyConversionsTest.java +++ b/tests/src/com/android/email/LegacyConversionsTest.java @@ -16,23 +16,41 @@ package com.android.email; +import android.content.Context; import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; +import com.android.emailcommon.TempDirectory; import com.android.emailcommon.internet.MimeBodyPart; import com.android.emailcommon.internet.MimeMessage; +import com.android.emailcommon.internet.MimeMultipart; import com.android.emailcommon.mail.Address; import com.android.emailcommon.mail.Message.RecipientType; import com.android.emailcommon.mail.MessagingException; +import com.android.emailcommon.mail.Multipart; import com.android.emailcommon.mail.Part; import com.android.emailcommon.provider.EmailContent; +import com.android.emailcommon.provider.EmailContent.Attachment; import com.android.emailcommon.utility.ConversionUtilities; import com.android.emailcommon.utility.ConversionUtilities.BodyFieldData; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; import java.util.ArrayList; import java.util.Date; +@SmallTest public class LegacyConversionsTest extends AndroidTestCase { + @Override + protected void setUp() throws Exception { + super.setUp(); + TempDirectory.setTempDirectory(getContext()); + } + /** * Test basic fields conversion from Store message to Provider message. */ @@ -172,4 +190,74 @@ public class LegacyConversionsTest extends AndroidTestCase { final BodyFieldData data = ConversionUtilities.parseBodyFields(viewables); assertNull(data.textContent); } + + /** + * Test adding an attachment to a message, and then parsing it back out. + * @throws MessagingException + */ + public void testAttachmentRoundTrip() throws Exception { + final Context context = getContext(); + final MimeMultipart mp = new MimeMultipart(); + mp.setSubType("mixed"); + + final long size; + + final File tempDir = context.getCacheDir(); + if (!tempDir.isDirectory() && !tempDir.mkdirs()) { + fail("Could not create temporary directory"); + } + + final File tempAttachmentFile = File.createTempFile("testAttachmentRoundTrip", ".txt", + tempDir); + + try { + final OutputStream attOut = new FileOutputStream(tempAttachmentFile); + try { + attOut.write("TestData".getBytes()); + } finally { + attOut.close(); + } + size = tempAttachmentFile.length(); + final InputStream attIn = new FileInputStream(tempAttachmentFile); + LegacyConversions.addAttachmentPart(mp, "text/plain", size, "test.txt", + "testContentId", attIn); + } finally { + if (!tempAttachmentFile.delete()) { + fail("Setup failure: Could not clean up temp file"); + } + } + + final MimeMessage outMessage = new MimeMessage(); + outMessage.setBody(mp); + + final MimeMessage inMessage; + + final File tempBodyFile = File.createTempFile("testAttachmentRoundTrip", ".eml", + context.getCacheDir()); + try { + final OutputStream bodyOut = new FileOutputStream(tempBodyFile); + try { + outMessage.writeTo(bodyOut); + } finally { + bodyOut.close(); + } + final InputStream bodyIn = new FileInputStream(tempBodyFile); + try { + inMessage = new MimeMessage(bodyIn); + } finally { + bodyIn.close(); + } + } finally { + if (!tempBodyFile.delete()) { + fail("Setup failure: Could not clean up temp file"); + } + } + final Multipart inBody = (Multipart) inMessage.getBody(); + final Part attPart = inBody.getBodyPart(0); + final Attachment att = LegacyConversions.mimePartToAttachment(attPart); + assertEquals(att.mFileName, "test.txt"); + assertEquals(att.mMimeType, "text/plain"); + assertEquals(att.mSize, size); + assertEquals(att.mContentId, "testContentId"); + } } |