Search in sources :

Example 1 with Textual

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

the class MessageViewInfoExtractor method buildText.

private StringBuilder buildText(Viewable viewable, boolean prependDivider) {
    StringBuilder text = new StringBuilder();
    if (viewable instanceof Textual) {
        Part part = ((Textual) viewable).getPart();
        addTextDivider(text, part, prependDivider);
        String t = getTextFromPart(part);
        if (t == null) {
            t = "";
        } else if (viewable instanceof Html) {
            t = HtmlConverter.htmlToText(t);
        } else if (!(viewable instanceof Text)) {
            throw new IllegalStateException("unhandled case!");
        }
        text.append(t);
    } else if (viewable instanceof Alternative) {
        // That's odd - an Alternative as child of an Alternative; go ahead and try to use the
        // text/plain child; fall-back to the text/html part.
        Alternative alternative = (Alternative) viewable;
        List<Viewable> textAlternative = alternative.getText().isEmpty() ? alternative.getHtml() : alternative.getText();
        boolean divider = prependDivider;
        for (Viewable textViewable : textAlternative) {
            text.append(buildText(textViewable, divider));
            divider = true;
        }
    }
    return text;
}
Also used : Alternative(com.fsck.k9.mail.internet.Viewable.Alternative) Textual(com.fsck.k9.mail.internet.Viewable.Textual) Part(com.fsck.k9.mail.Part) Viewable(com.fsck.k9.mail.internet.Viewable) Html(com.fsck.k9.mail.internet.Viewable.Html) Text(com.fsck.k9.mail.internet.Viewable.Text) ArrayList(java.util.ArrayList) List(java.util.List)

Example 2 with Textual

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

the class MigrationTo51 method db51MigrateMessageFormat.

/**
     * This method converts from the old message table structure to the new one.
     *
     * This is a complex migration, and ultimately we do not have enough
     * information to recreate the mime structure of the original mails.
     * What we have:
     *  - general mail info
     *  - html_content and text_content data, which is the squashed readable content of the mail
     *  - a table with message headers
     *  - attachments
     *
     * What we need to do:
     *  - migrate general mail info as-is
     *  - flag mails as migrated for re-download
     *  - for each message, recreate a mime structure from its message content and attachments:
     *    + insert one or both of textContent and htmlContent, depending on mimeType
     *    + if mimeType is text/plain, text/html or multipart/alternative and no
     *      attachments are present, just insert that.
     *    + otherwise, use multipart/mixed, adding attachments after textual content
     *    + revert content:// URIs in htmlContent to original cid: URIs.
     */
public static void db51MigrateMessageFormat(SQLiteDatabase db, MigrationsHelper migrationsHelper) {
    renameOldMessagesTableAndCreateNew(db);
    copyMessageMetadataToNewTable(db);
    File attachmentDirNew, attachmentDirOld;
    Account account = migrationsHelper.getAccount();
    attachmentDirNew = StorageManager.getInstance(K9.app).getAttachmentDirectory(account.getUuid(), account.getLocalStorageProviderId());
    attachmentDirOld = renameOldAttachmentDirAndCreateNew(account, attachmentDirNew);
    Cursor msgCursor = db.query("messages_old", new String[] { "id", "flags", "html_content", "text_content", "mime_type", "attachment_count" }, null, null, null, null, null);
    try {
        Timber.d("migrating %d messages", msgCursor.getCount());
        ContentValues cv = new ContentValues();
        while (msgCursor.moveToNext()) {
            long messageId = msgCursor.getLong(0);
            String messageFlags = msgCursor.getString(1);
            String htmlContent = msgCursor.getString(2);
            String textContent = msgCursor.getString(3);
            String mimeType = msgCursor.getString(4);
            int attachmentCount = msgCursor.getInt(5);
            try {
                updateFlagsForMessage(db, messageId, messageFlags, migrationsHelper);
                MimeHeader mimeHeader = loadHeaderFromHeadersTable(db, messageId);
                MimeStructureState structureState = MimeStructureState.getNewRootState();
                boolean messageHadSpecialFormat = false;
                // we do not rely on the protocol parameter here but guess by the multipart structure
                boolean isMaybePgpMimeEncrypted = attachmentCount == 2 && MimeUtil.isSameMimeType(mimeType, "multipart/encrypted");
                if (isMaybePgpMimeEncrypted) {
                    MimeStructureState maybeStructureState = migratePgpMimeEncryptedContent(db, messageId, attachmentDirOld, attachmentDirNew, mimeHeader, structureState);
                    if (maybeStructureState != null) {
                        structureState = maybeStructureState;
                        messageHadSpecialFormat = true;
                    }
                }
                if (!messageHadSpecialFormat) {
                    boolean isSimpleStructured = attachmentCount == 0 && Utility.isAnyMimeType(mimeType, "text/plain", "text/html", "multipart/alternative");
                    if (isSimpleStructured) {
                        structureState = migrateSimpleMailContent(db, htmlContent, textContent, mimeType, mimeHeader, structureState);
                    } else {
                        mimeType = "multipart/mixed";
                        structureState = migrateComplexMailContent(db, attachmentDirOld, attachmentDirNew, messageId, htmlContent, textContent, mimeHeader, structureState);
                    }
                }
                cv.clear();
                cv.put("mime_type", mimeType);
                cv.put("message_part_id", structureState.rootPartId);
                cv.put("attachment_count", attachmentCount);
                db.update("messages", cv, "id = ?", new String[] { Long.toString(messageId) });
            } catch (IOException e) {
                Timber.e(e, "error inserting into database");
            }
        }
    } finally {
        msgCursor.close();
    }
    cleanUpOldAttachmentDirectory(attachmentDirOld);
    dropOldMessagesTable(db);
}
Also used : ContentValues(android.content.ContentValues) Account(com.fsck.k9.Account) MimeHeader(com.fsck.k9.mail.internet.MimeHeader) IOException(java.io.IOException) Cursor(android.database.Cursor) File(java.io.File)

Example 3 with Textual

use of com.fsck.k9.mail.internet.Viewable.Textual 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 sanitizedHtml = htmlProcessor.processForDisplay(html.toString());
        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(androidx.annotation.VisibleForTesting)

Example 4 with Textual

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

the class MessageViewInfoExtractor method buildHtml.

/**
 * Use the contents of a {@link com.fsck.k9.mail.internet.Viewable} to create the HTML to be displayed.
 *
 * <p>
 * This will use {@link HtmlConverter#textToHtml(String)} to convert plain text parts
 * to HTML if necessary.
 * </p>
 *
 * @param viewable
 *         The viewable part to build the HTML from.
 * @param prependDivider
 *         {@code true}, if the HTML divider should be inserted as first element.
 *         {@code false}, otherwise.
 *
 * @return The contents of the supplied viewable instance as HTML.
 */
private StringBuilder buildHtml(Viewable viewable, boolean prependDivider) {
    StringBuilder html = new StringBuilder();
    if (viewable instanceof Textual) {
        Part part = ((Textual) viewable).getPart();
        addHtmlDivider(html, part, prependDivider);
        String t = getTextFromPart(part);
        if (t == null) {
            t = "";
        } else if (viewable instanceof Text) {
            t = HtmlConverter.textToHtml(t);
        } else if (!(viewable instanceof Html)) {
            throw new IllegalStateException("unhandled case!");
        }
        html.append(t);
    } else if (viewable instanceof Alternative) {
        // That's odd - an Alternative as child of an Alternative; go ahead and try to use the
        // text/html child; fall-back to the text/plain part.
        Alternative alternative = (Alternative) viewable;
        List<Viewable> htmlAlternative = alternative.getHtml().isEmpty() ? alternative.getText() : alternative.getHtml();
        boolean divider = prependDivider;
        for (Viewable htmlViewable : htmlAlternative) {
            html.append(buildHtml(htmlViewable, divider));
            divider = true;
        }
    }
    return html;
}
Also used : Alternative(com.fsck.k9.mail.internet.Viewable.Alternative) Textual(com.fsck.k9.mail.internet.Viewable.Textual) Part(com.fsck.k9.mail.Part) Viewable(com.fsck.k9.mail.internet.Viewable) Html(com.fsck.k9.mail.internet.Viewable.Html) Text(com.fsck.k9.mail.internet.Viewable.Text) ArrayList(java.util.ArrayList) List(java.util.List)

Aggregations

Part (com.fsck.k9.mail.Part)3 Viewable (com.fsck.k9.mail.internet.Viewable)3 Alternative (com.fsck.k9.mail.internet.Viewable.Alternative)3 Textual (com.fsck.k9.mail.internet.Viewable.Textual)3 Html (com.fsck.k9.mail.internet.Viewable.Html)2 Text (com.fsck.k9.mail.internet.Viewable.Text)2 ArrayList (java.util.ArrayList)2 List (java.util.List)2 ContentValues (android.content.ContentValues)1 Cursor (android.database.Cursor)1 VisibleForTesting (androidx.annotation.VisibleForTesting)1 Account (com.fsck.k9.Account)1 Message (com.fsck.k9.mail.Message)1 MessagingException (com.fsck.k9.mail.MessagingException)1 MimeHeader (com.fsck.k9.mail.internet.MimeHeader)1 MessageHeader (com.fsck.k9.mail.internet.Viewable.MessageHeader)1 File (java.io.File)1 IOException (java.io.IOException)1