Search in sources :

Example 1 with MessageHeader

use of com.fsck.k9.mail.internet.Viewable.MessageHeader in project k-9 by k9mail.

the class MessageViewInfoExtractorTest method testMultipartDigestWithMessages.

@Test
public void testMultipartDigestWithMessages() throws Exception {
    String data = "Content-Type: multipart/digest; boundary=\"bndry\"\r\n" + "\r\n" + "--bndry\r\n" + "\r\n" + "Content-Type: text/plain\r\n" + "\r\n" + "text body of first message\r\n" + "\r\n" + "--bndry\r\n" + "\r\n" + "Subject: subject of second message\r\n" + "Content-Type: multipart/alternative; boundary=\"bndry2\"\r\n" + "\r\n" + "--bndry2\r\n" + "Content-Type: text/plain\r\n" + "\r\n" + "text part of second message\r\n" + "\r\n" + "--bndry2\r\n" + "Content-Type: text/html\"\r\n" + "\r\n" + "html part of second message\r\n" + "\r\n" + "--bndry2--\r\n" + "\r\n" + "--bndry--\r\n";
    MimeMessage message = MimeMessage.parseMimeMessage(new ByteArrayInputStream(data.getBytes()), false);
    // Extract text
    List<Part> outputNonViewableParts = new ArrayList<>();
    ArrayList<Viewable> outputViewableParts = new ArrayList<>();
    MessageExtractor.findViewablesAndAttachments(message, outputViewableParts, outputNonViewableParts);
    String expectedExtractedText = "Subject: (No subject)\r\n" + "\r\n" + "text body of first message\r\n" + "\r\n" + "\r\n" + "------------------------------------------------------------------------\r\n" + "\r\n" + "Subject: subject of second message\r\n" + "\r\n" + "text part of second message\r\n";
    String expectedHtmlText = "<table style=\"border: 0\">" + "<tr><th style=\"text-align: left; vertical-align: top;\">Subject:</th><td>(No subject)</td></tr>" + "</table>" + "<pre class=\"k9mail\">text body of first message<br /></pre>" + "<p style=\"margin-top: 2.5em; margin-bottom: 1em; border-bottom: 1px solid #000\"></p>" + "<table style=\"border: 0\">" + "<tr><th style=\"text-align: left; vertical-align: top;\">Subject:</th><td>subject of second message</td></tr>" + "</table>" + "<pre class=\"k9mail\">text part of second message<br /></pre>";
    assertEquals(4, outputViewableParts.size());
    assertEquals("subject of second message", ((MessageHeader) outputViewableParts.get(2)).getMessage().getSubject());
    ViewableExtractedText firstMessageExtractedText = messageViewInfoExtractor.extractTextFromViewables(outputViewableParts);
    assertEquals(expectedExtractedText, firstMessageExtractedText.text);
    assertEquals(expectedHtmlText, getHtmlBodyText(firstMessageExtractedText.html));
}
Also used : MimeMessage(com.fsck.k9.mail.internet.MimeMessage) ByteArrayInputStream(java.io.ByteArrayInputStream) Part(com.fsck.k9.mail.Part) MimeBodyPart(com.fsck.k9.mail.internet.MimeBodyPart) ArrayList(java.util.ArrayList) Viewable(com.fsck.k9.mail.internet.Viewable) ViewableExtractedText(com.fsck.k9.mailstore.MessageViewInfoExtractor.ViewableExtractedText) MessageHeader(com.fsck.k9.mail.internet.Viewable.MessageHeader) Test(org.junit.Test)

Example 2 with MessageHeader

use of com.fsck.k9.mail.internet.Viewable.MessageHeader in project k-9 by k9mail.

the class MessageExtractor method findViewablesAndAttachments.

/** Traverse the MIME tree of a message and extract viewable parts. */
public static void findViewablesAndAttachments(Part part, @Nullable List<Viewable> outputViewableParts, @Nullable List<Part> outputNonViewableParts) throws MessagingException {
    boolean skipSavingNonViewableParts = outputNonViewableParts == null;
    boolean skipSavingViewableParts = outputViewableParts == null;
    if (skipSavingNonViewableParts && skipSavingViewableParts) {
        throw new IllegalArgumentException("method was called but no output is to be collected - this a bug!");
    }
    Body body = part.getBody();
    if (body instanceof Multipart) {
        Multipart multipart = (Multipart) body;
        if (isSameMimeType(part.getMimeType(), "multipart/alternative")) {
            /*
                 * For multipart/alternative parts we try to find a text/plain and a text/html
                 * child. Everything else we find is put into 'attachments'.
                 */
            List<Viewable> text = findTextPart(multipart, true);
            Set<Part> knownTextParts = getParts(text);
            List<Viewable> html = findHtmlPart(multipart, knownTextParts, outputNonViewableParts, true);
            if (skipSavingViewableParts) {
                return;
            }
            if (!text.isEmpty() || !html.isEmpty()) {
                Alternative alternative = new Alternative(text, html);
                outputViewableParts.add(alternative);
            }
        } else {
            // For all other multipart parts we recurse to grab all viewable children.
            for (Part bodyPart : multipart.getBodyParts()) {
                findViewablesAndAttachments(bodyPart, outputViewableParts, outputNonViewableParts);
            }
        }
    } else if (body instanceof Message && !("attachment".equalsIgnoreCase(getContentDisposition(part)))) {
        if (skipSavingViewableParts) {
            return;
        }
        /*
             * We only care about message/rfc822 parts whose Content-Disposition header has a value
             * other than "attachment".
             */
        Message message = (Message) body;
        // We add the Message object so we can extract the filename later.
        outputViewableParts.add(new MessageHeader(part, message));
        // Recurse to grab all viewable parts and attachments from that message.
        findViewablesAndAttachments(message, outputViewableParts, outputNonViewableParts);
    } else if (isPartTextualBody(part)) {
        if (skipSavingViewableParts) {
            return;
        }
        String mimeType = part.getMimeType();
        Viewable viewable;
        if (isSameMimeType(mimeType, "text/plain")) {
            if (isFormatFlowed(part.getContentType())) {
                viewable = new Flowed(part);
            } else {
                viewable = new Text(part);
            }
        } else {
            viewable = new Html(part);
        }
        outputViewableParts.add(viewable);
    } else if (isSameMimeType(part.getMimeType(), "application/pgp-signature")) {
    // ignore this type explicitly
    } else {
        if (skipSavingNonViewableParts) {
            return;
        }
        // Everything else is treated as attachment.
        outputNonViewableParts.add(part);
    }
}
Also used : Multipart(com.fsck.k9.mail.Multipart) Alternative(com.fsck.k9.mail.internet.Viewable.Alternative) Message(com.fsck.k9.mail.Message) Html(com.fsck.k9.mail.internet.Viewable.Html) Text(com.fsck.k9.mail.internet.Viewable.Text) Flowed(com.fsck.k9.mail.internet.Viewable.Flowed) MimeUtility.isFormatFlowed(com.fsck.k9.mail.internet.MimeUtility.isFormatFlowed) Part(com.fsck.k9.mail.Part) BodyPart(com.fsck.k9.mail.BodyPart) MessageHeader(com.fsck.k9.mail.internet.Viewable.MessageHeader) Body(com.fsck.k9.mail.Body)

Example 3 with MessageHeader

use of com.fsck.k9.mail.internet.Viewable.MessageHeader in project k-9 by k9mail.

the class MessageViewInfoExtractor method extractTextFromViewables.

/**
     * Extract the viewable textual parts of a message and return the rest as attachments.
     *
     * @return A {@link ViewableExtractedText} instance containing the textual parts of the message as
     *         plain text and HTML, and a list of message parts considered attachments.
     *
     * @throws com.fsck.k9.mail.MessagingException
     *          In case of an error.
     */
@VisibleForTesting
ViewableExtractedText extractTextFromViewables(List<Viewable> viewables) throws MessagingException {
    try {
        // Collect all viewable parts
        /*
             * Convert the tree of viewable parts into text and HTML
             */
        // Used to suppress the divider for the first viewable part
        boolean hideDivider = true;
        StringBuilder text = new StringBuilder();
        StringBuilder html = new StringBuilder();
        for (Viewable viewable : viewables) {
            if (viewable instanceof Textual) {
                // This is either a text/plain or text/html part. Fill the variables 'text' and
                // 'html', converting between plain text and HTML as necessary.
                text.append(buildText(viewable, !hideDivider));
                html.append(buildHtml(viewable, !hideDivider));
                hideDivider = false;
            } else if (viewable instanceof MessageHeader) {
                MessageHeader header = (MessageHeader) viewable;
                Part containerPart = header.getContainerPart();
                Message innerMessage = header.getMessage();
                addTextDivider(text, containerPart, !hideDivider);
                addMessageHeaderText(text, innerMessage);
                addHtmlDivider(html, containerPart, !hideDivider);
                addMessageHeaderHtml(html, innerMessage);
                hideDivider = true;
            } else if (viewable instanceof Alternative) {
                // Handle multipart/alternative contents
                Alternative alternative = (Alternative) viewable;
                /*
                     * We made sure at least one of text/plain or text/html is present when
                     * creating the Alternative object. If one part is not present we convert the
                     * other one to make sure 'text' and 'html' always contain the same text.
                     */
                List<Viewable> textAlternative = alternative.getText().isEmpty() ? alternative.getHtml() : alternative.getText();
                List<Viewable> htmlAlternative = alternative.getHtml().isEmpty() ? alternative.getText() : alternative.getHtml();
                // Fill the 'text' variable
                boolean divider = !hideDivider;
                for (Viewable textViewable : textAlternative) {
                    text.append(buildText(textViewable, divider));
                    divider = true;
                }
                // Fill the 'html' variable
                divider = !hideDivider;
                for (Viewable htmlViewable : htmlAlternative) {
                    html.append(buildHtml(htmlViewable, divider));
                    divider = true;
                }
                hideDivider = false;
            }
        }
        String content = HtmlConverter.wrapMessageContent(html);
        String sanitizedHtml = htmlSanitizer.sanitize(content);
        return new ViewableExtractedText(text.toString(), sanitizedHtml);
    } catch (Exception e) {
        throw new MessagingException("Couldn't extract viewable parts", e);
    }
}
Also used : Alternative(com.fsck.k9.mail.internet.Viewable.Alternative) Message(com.fsck.k9.mail.Message) Textual(com.fsck.k9.mail.internet.Viewable.Textual) MessagingException(com.fsck.k9.mail.MessagingException) MessagingException(com.fsck.k9.mail.MessagingException) Part(com.fsck.k9.mail.Part) Viewable(com.fsck.k9.mail.internet.Viewable) MessageHeader(com.fsck.k9.mail.internet.Viewable.MessageHeader) VisibleForTesting(android.support.annotation.VisibleForTesting)

Aggregations

Part (com.fsck.k9.mail.Part)3 MessageHeader (com.fsck.k9.mail.internet.Viewable.MessageHeader)3 Message (com.fsck.k9.mail.Message)2 Viewable (com.fsck.k9.mail.internet.Viewable)2 Alternative (com.fsck.k9.mail.internet.Viewable.Alternative)2 VisibleForTesting (android.support.annotation.VisibleForTesting)1 Body (com.fsck.k9.mail.Body)1 BodyPart (com.fsck.k9.mail.BodyPart)1 MessagingException (com.fsck.k9.mail.MessagingException)1 Multipart (com.fsck.k9.mail.Multipart)1 MimeBodyPart (com.fsck.k9.mail.internet.MimeBodyPart)1 MimeMessage (com.fsck.k9.mail.internet.MimeMessage)1 MimeUtility.isFormatFlowed (com.fsck.k9.mail.internet.MimeUtility.isFormatFlowed)1 Flowed (com.fsck.k9.mail.internet.Viewable.Flowed)1 Html (com.fsck.k9.mail.internet.Viewable.Html)1 Text (com.fsck.k9.mail.internet.Viewable.Text)1 Textual (com.fsck.k9.mail.internet.Viewable.Textual)1 ViewableExtractedText (com.fsck.k9.mailstore.MessageViewInfoExtractor.ViewableExtractedText)1 ByteArrayInputStream (java.io.ByteArrayInputStream)1 ArrayList (java.util.ArrayList)1