diff --git a/k9mail-library/src/main/java/com/fsck/k9/mail/Message.java b/k9mail-library/src/main/java/com/fsck/k9/mail/Message.java index a77e0c282..46ff8302c 100644 --- a/k9mail-library/src/main/java/com/fsck/k9/mail/Message.java +++ b/k9mail-library/src/main/java/com/fsck/k9/mail/Message.java @@ -150,55 +150,6 @@ public abstract class Message implements Part, CompositeBody { public abstract int getSize(); - /* - * calculateContentPreview - * Takes a plain text message body as a string. - * Returns a message summary as a string suitable for showing in a message list - * - * A message summary should be about the first 160 characters - * of unique text written by the message sender - * Quoted text, "On $date" and so on will be stripped out. - * All newlines and whitespace will be compressed. - * - */ - public static String calculateContentPreview(String text) { - if (text == null) { - return null; - } - - // Only look at the first 8k of a message when calculating - // the preview. This should avoid unnecessary - // memory usage on large messages - if (text.length() > 8192) { - text = text.substring(0, 8192); - } - - // Remove (correctly delimited by '-- \n') signatures - text = text.replaceAll("(?ms)^-- [\\r\\n]+.*", ""); - // try to remove lines of dashes in the preview - text = text.replaceAll("(?m)^----.*?$", ""); - // remove quoted text from the preview - text = text.replaceAll("(?m)^[#>].*$", ""); - // Remove a common quote header from the preview - text = text.replaceAll("(?m)^On .*wrote.?$", ""); - // Remove a more generic quote header from the preview - text = text.replaceAll("(?m)^.*\\w+:$", ""); - // Remove horizontal rules. - text = text.replaceAll("\\s*([-=_]{30,}+)\\s*", " "); - - // URLs in the preview should just be shown as "..." - They're not - // clickable and they usually overwhelm the preview - text = text.replaceAll("https?://\\S+", "..."); - // Don't show newlines in the preview - text = text.replaceAll("(\\r|\\n)+", " "); - // Collapse whitespace in the preview - text = text.replaceAll("\\s+", " "); - // Remove any whitespace at the beginning and end of the string. - text = text.trim(); - - return (text.length() <= 512) ? text : text.substring(0, 512); - } - public void delete(String trashFolderName) throws MessagingException {} /* diff --git a/k9mail/src/androidTest/java/com/fsck/k9/mailstore/MessagePreviewExtractorTest.java b/k9mail/src/androidTest/java/com/fsck/k9/mailstore/MessagePreviewExtractorTest.java new file mode 100644 index 000000000..dcbd437cc --- /dev/null +++ b/k9mail/src/androidTest/java/com/fsck/k9/mailstore/MessagePreviewExtractorTest.java @@ -0,0 +1,141 @@ +package com.fsck.k9.mailstore; + + +import android.content.Context; +import android.support.test.InstrumentationRegistry; +import android.support.test.runner.AndroidJUnit4; + +import com.fsck.k9.mail.MessagingException; +import com.fsck.k9.mail.internet.MimeBodyPart; +import com.fsck.k9.mail.internet.MimeMessage; +import com.fsck.k9.mail.internet.MimeMultipart; +import com.fsck.k9.mail.internet.TextBody; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.assertEquals; + + +@RunWith(AndroidJUnit4.class) +public class MessagePreviewExtractorTest { + + @Test + public void shouldExtractPreviewFromSinglePlainTextPart() throws MessagingException { + MimeMessage message = new MimeMessage(); + message.addHeader("Content-Type", "text/plain"); + TextBody body = new TextBody("Message text "); + message.setBody(body); + + String preview = MessagePreviewExtractor.extractPreview(getContext(), message); + + assertEquals("Message text", preview); + } + + @Test + public void shouldLimitPreviewTo512Characters() throws MessagingException { + MimeMessage message = new MimeMessage(); + message.addHeader("Content-Type", "text/plain"); + TextBody body = new TextBody("10--------20--------30--------40--------50--------" + + "60--------70--------80--------90--------100-------" + + "110-------120-------130-------140-------150-------" + + "160-------170-------180-------190-------200-------" + + "210-------220-------230-------240-------250-------" + + "260-------270-------280-------290-------300-------" + + "310-------320-------330-------340-------350-------" + + "360-------370-------380-------390-------400-------" + + "410-------420-------430-------440-------450-------" + + "460-------470-------480-------490-------500-------" + + "510-------520-------530-------540-------550-------" + + "560-------570-------580-------590-------600-------"); + message.setBody(body); + + String preview = MessagePreviewExtractor.extractPreview(getContext(), message); + + assertEquals(512, preview.length()); + assertEquals('…', preview.charAt(511)); + } + + @Test + public void shouldExtractPreviewFromSingleHtmlPart() throws MessagingException { + MimeMessage message = new MimeMessage(); + message.addHeader("Content-Type", "text/html"); + TextBody body = new TextBody("
Message text"); + message.setBody(body); + + String preview = MessagePreviewExtractor.extractPreview(getContext(), message); + + assertEquals("Message text", preview); + } + + @Test + public void shouldExtractPreviewFromMultipartAlternative() throws MessagingException { + MimeMessage message = new MimeMessage(); + message.addHeader("Content-Type", "multipart/alternative"); + MimeMultipart multipart = new MimeMultipart(); + multipart.setSubType("alternative"); + message.setBody(multipart); + + TextBody textBody = new TextBody("text"); + MimeBodyPart textPart = new MimeBodyPart(textBody, "text/plain"); + multipart.addBodyPart(textPart); + + TextBody htmlBody = new TextBody("html"); + MimeBodyPart htmlPart = new MimeBodyPart(htmlBody, "text/html"); + multipart.addBodyPart(htmlPart); + + String preview = MessagePreviewExtractor.extractPreview(getContext(), message); + + assertEquals("text", preview); + } + + @Test + public void shouldExtractPreviewFromMultipartMixed() throws MessagingException { + MimeMessage message = new MimeMessage(); + message.addHeader("Content-Type", "multipart/mixed"); + MimeMultipart multipart = new MimeMultipart(); + multipart.setSubType("mixed"); + message.setBody(multipart); + + TextBody textBody = new TextBody("text"); + MimeBodyPart textPart = new MimeBodyPart(textBody, "text/plain"); + multipart.addBodyPart(textPart); + + TextBody htmlBody = new TextBody("html"); + MimeBodyPart htmlPart = new MimeBodyPart(htmlBody, "text/html"); + multipart.addBodyPart(htmlPart); + + String preview = MessagePreviewExtractor.extractPreview(getContext(), message); + + assertEquals("text / html", preview); + } + + @Test + public void shouldExtractPreviewFromMultipartMixedWithInnerMesssage() throws MessagingException { + MimeMessage message = new MimeMessage(); + message.addHeader("Content-Type", "multipart/mixed"); + MimeMultipart multipart = new MimeMultipart(); + multipart.setSubType("mixed"); + message.setBody(multipart); + + TextBody textBody = new TextBody("text"); + MimeBodyPart textPart = new MimeBodyPart(textBody, "text/plain"); + multipart.addBodyPart(textPart); + + MimeMessage innerMessage = new MimeMessage(); + innerMessage.addHeader("Content-Type", "text/html"); + innerMessage.addHeader("Subject", "inner message"); + TextBody htmlBody = new TextBody("html"); + innerMessage.setBody(htmlBody); + + MimeBodyPart messagePart = new MimeBodyPart(innerMessage, "message/rfc822"); + multipart.addBodyPart(messagePart); + + String preview = MessagePreviewExtractor.extractPreview(getContext(), message); + + assertEquals("text / Includes message titled \"inner message\" containing: html", preview); + } + + private Context getContext() { + return InstrumentationRegistry.getTargetContext(); + } +} diff --git a/k9mail/src/main/java/com/fsck/k9/mailstore/MessagePreviewExtractor.java b/k9mail/src/main/java/com/fsck/k9/mailstore/MessagePreviewExtractor.java new file mode 100644 index 000000000..60be77618 --- /dev/null +++ b/k9mail/src/main/java/com/fsck/k9/mailstore/MessagePreviewExtractor.java @@ -0,0 +1,168 @@ +package com.fsck.k9.mailstore; + + +import java.util.ArrayList; +import java.util.List; + +import android.content.Context; +import android.text.TextUtils; + +import com.fsck.k9.R; +import com.fsck.k9.helper.HtmlConverter; +import com.fsck.k9.mail.Message; +import com.fsck.k9.mail.MessagingException; +import com.fsck.k9.mail.Part; +import com.fsck.k9.mail.internet.MessageExtractor; +import com.fsck.k9.mail.internet.Viewable; +import com.fsck.k9.mail.internet.Viewable.Alternative; +import com.fsck.k9.mail.internet.Viewable.Html; +import com.fsck.k9.mail.internet.Viewable.MessageHeader; +import com.fsck.k9.mail.internet.Viewable.Textual; + + +public class MessagePreviewExtractor { + private static final int MAX_PREVIEW_LENGTH = 512; + private static final int MAX_CHARACTERS_CHECKED_FOR_PREVIEW = 8192; + + public static String extractPreview(Context context, Message message) throws MessagingException { + try { + List