diff --git a/src/com/fsck/k9/mail/internet/BinaryTempFileBody.java b/src/com/fsck/k9/mail/internet/BinaryTempFileBody.java index 677739bbf..17870c140 100644 --- a/src/com/fsck/k9/mail/internet/BinaryTempFileBody.java +++ b/src/com/fsck/k9/mail/internet/BinaryTempFileBody.java @@ -15,7 +15,7 @@ import java.io.*; * and writeTo one time. After writeTo is called, or the InputStream returned from * getInputStream is closed the file is deleted and the Body should be considered disposed of. */ -public class BinaryTempFileBody implements Body { +public class BinaryTempFileBody implements RawDataBody { private static File mTempDirectory; private File mFile; @@ -26,6 +26,11 @@ public class BinaryTempFileBody implements Body { mTempDirectory = tempDirectory; } + @Override + public String getEncoding() { + return mEncoding; + } + public void setEncoding(String encoding) throws MessagingException { if (mEncoding != null && mEncoding.equalsIgnoreCase(encoding)) { return; diff --git a/src/com/fsck/k9/mail/internet/MimeUtility.java b/src/com/fsck/k9/mail/internet/MimeUtility.java index b78f8e378..da3dca5bd 100644 --- a/src/com/fsck/k9/mail/internet/MimeUtility.java +++ b/src/com/fsck/k9/mail/internet/MimeUtility.java @@ -2,6 +2,7 @@ package com.fsck.k9.mail.internet; import android.content.Context; +import android.util.Base64; import android.util.Log; import com.fsck.k9.K9; import com.fsck.k9.R; @@ -10,6 +11,7 @@ import com.fsck.k9.mail.*; import com.fsck.k9.mail.Message.RecipientType; import com.fsck.k9.mail.internet.BinaryTempFileBody.BinaryTempFileBodyInputStream; +import com.fsck.k9.view.MessageHeader; import org.apache.commons.io.IOUtils; import org.apache.james.mime4j.codec.Base64InputStream; import org.apache.james.mime4j.codec.QuotedPrintableInputStream; @@ -1026,7 +1028,7 @@ public class MimeUtility { * determine the charset from HTML message. */ if (mimeType.equalsIgnoreCase("text/html") && charset == null) { - InputStream in = part.getBody().getInputStream(); + InputStream in = MimeUtility.decodeBody(part.getBody()); try { byte[] buf = new byte[256]; in.read(buf, 0, buf.length); @@ -1062,7 +1064,7 @@ public class MimeUtility { * Now we read the part into a buffer for further processing. Because * the stream is now wrapped we'll remove any transfer encoding at this point. */ - InputStream in = part.getBody().getInputStream(); + InputStream in = MimeUtility.decodeBody(part.getBody()); try { String text = readToString(in, charset); @@ -1151,6 +1153,49 @@ public class MimeUtility { return tempBody; } + /** + * Get decoded contents of a body. + *

+ * Right now only some classes retain the original encoding of the body contents. Those classes have to implement + * the {@link RawDataBody} interface in order for this method to decode the data delivered by + * {@link Body#getInputStream()}. + *

+ * The ultimate goal is to get to a point where all classes retain the original data and {@code RawDataBody} can be + * merged into {@link Body}. + */ + public static InputStream decodeBody(Body body) throws MessagingException { + InputStream inputStream; + if (body instanceof RawDataBody) { + RawDataBody rawDataBody = (RawDataBody) body; + String encoding = rawDataBody.getEncoding(); + final InputStream rawInputStream = rawDataBody.getInputStream(); + if (MimeUtil.ENC_7BIT.equalsIgnoreCase(encoding) || MimeUtil.ENC_8BIT.equalsIgnoreCase(encoding)) { + inputStream = rawInputStream; + } else if (MimeUtil.ENC_BASE64.equalsIgnoreCase(encoding)) { + inputStream = new Base64InputStream(rawInputStream, false) { + @Override + public void close() throws IOException { + super.close(); + rawInputStream.close(); + } + }; + } else if (MimeUtil.ENC_QUOTED_PRINTABLE.equalsIgnoreCase(encoding)) { + inputStream = new QuotedPrintableInputStream(rawInputStream) { + @Override + public void close() throws IOException { + super.close(); + rawInputStream.close(); + } + }; + } else { + throw new RuntimeException("Encoding for RawDataBody not supported: " + encoding); + } + } else { + inputStream = body.getInputStream(); + } + + return inputStream; + } /** * Empty base class for the class hierarchy used by diff --git a/src/com/fsck/k9/mail/internet/RawDataBody.java b/src/com/fsck/k9/mail/internet/RawDataBody.java new file mode 100644 index 000000000..e3dee616e --- /dev/null +++ b/src/com/fsck/k9/mail/internet/RawDataBody.java @@ -0,0 +1,12 @@ +package com.fsck.k9.mail.internet; + + +import com.fsck.k9.mail.Body; + + +/** + * See {@link MimeUtility#decodeBody(Body)} + */ +public interface RawDataBody extends Body { + String getEncoding(); +} diff --git a/src/com/fsck/k9/mail/store/local/LocalFolder.java b/src/com/fsck/k9/mail/store/local/LocalFolder.java index e84098183..e264ef877 100644 --- a/src/com/fsck/k9/mail/store/local/LocalFolder.java +++ b/src/com/fsck/k9/mail/store/local/LocalFolder.java @@ -1561,7 +1561,7 @@ public class LocalFolder extends Folder implements Serializable { * If the attachment has a body we're expected to save it into the local store * so we copy the data into a cached attachment file. */ - InputStream in = attachment.getBody().getInputStream(); + InputStream in = MimeUtility.decodeBody(attachment.getBody()); try { tempAttachmentFile = File.createTempFile("att", null, attachmentDirectory); FileOutputStream out = new FileOutputStream(tempAttachmentFile); diff --git a/tests/src/com/fsck/k9/mail/internet/MimeMessageParseTest.java b/tests/src/com/fsck/k9/mail/internet/MimeMessageParseTest.java index 4558d4264..4107a7490 100644 --- a/tests/src/com/fsck/k9/mail/internet/MimeMessageParseTest.java +++ b/tests/src/com/fsck/k9/mail/internet/MimeMessageParseTest.java @@ -63,7 +63,7 @@ public class MimeMessageParseTest extends AndroidTestCase { private static void checkLeafParts(MimeMessage msg, String... expectedParts) throws Exception { List actual = new ArrayList(); for (Body leaf : getLeafParts(msg.getBody())) { - actual.add(streamToString(leaf.getInputStream())); + actual.add(streamToString(MimeUtility.decodeBody(leaf))); } assertEquals(Arrays.asList(expectedParts), actual); } @@ -83,7 +83,7 @@ public class MimeMessageParseTest extends AndroidTestCase { checkAddresses(msg.getRecipients(RecipientType.TO), "eva@example.org"); assertEquals("Testmail", msg.getSubject()); assertEquals("text/plain", msg.getContentType()); - assertEquals("this is some test text.", streamToString(msg.getBody().getInputStream())); + assertEquals("this is some test text.", streamToString(MimeUtility.decodeBody(msg.getBody()))); } public static void testSinglePart8BitRecurse() throws Exception { @@ -101,7 +101,7 @@ public class MimeMessageParseTest extends AndroidTestCase { checkAddresses(msg.getRecipients(RecipientType.TO), "eva@example.org"); assertEquals("Testmail", msg.getSubject()); assertEquals("text/plain; encoding=ISO-8859-1", msg.getContentType()); - assertEquals("gefährliche Umlaute", streamToString(msg.getBody().getInputStream())); + assertEquals("gefährliche Umlaute", streamToString(MimeUtility.decodeBody(msg.getBody()))); } public static void testSinglePartBase64NoRecurse() throws Exception { @@ -119,7 +119,7 @@ public class MimeMessageParseTest extends AndroidTestCase { checkAddresses(msg.getRecipients(RecipientType.TO), "eva@example.org"); assertEquals("Testmail", msg.getSubject()); assertEquals("text/plain", msg.getContentType()); - assertEquals("this is some more test text.", streamToString(msg.getBody().getInputStream())); + assertEquals("this is some more test text.", streamToString(MimeUtility.decodeBody(msg.getBody()))); } public static void testMultipartSingleLayerNoRecurse() throws Exception {