Merge pull request #1378 from k9mail/for-cketti

Refactorings for #1299
This commit is contained in:
cketti 2016-05-19 14:49:29 +02:00
commit 471aed586a
21 changed files with 457 additions and 549 deletions

View file

@ -1,5 +1,7 @@
package com.fsck.k9.mail.internet;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
import com.fsck.k9.mail.Body;
@ -110,22 +112,15 @@ public class MessageExtractor {
}
}
/**
* Traverse the MIME tree of a message an extract viewable parts.
*
* @param part
* The message part to start from.
* @param attachments
* A list that will receive the parts that are considered attachments.
*
* @return A list of {@link Viewable}s.
*
* @throws MessagingException
* In case of an error.
*/
public static List<Viewable> getViewables(Part part, List<Part> attachments) throws MessagingException {
List<Viewable> viewables = new ArrayList<Viewable>();
/** Traverse the MIME tree of a message an 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) {
@ -138,20 +133,26 @@ public class MessageExtractor {
List<Viewable> text = findTextPart(multipart, true);
Set<Part> knownTextParts = getParts(text);
List<Viewable> html = findHtmlPart(multipart, knownTextParts, attachments, true);
List<Viewable> html = findHtmlPart(multipart, knownTextParts, outputNonViewableParts, true);
if (skipSavingViewableParts) {
return;
}
if (!text.isEmpty() || !html.isEmpty()) {
Alternative alternative = new Alternative(text, html);
viewables.add(alternative);
outputViewableParts.add(alternative);
}
} else {
// For all other multipart parts we recurse to grab all viewable children.
for (Part bodyPart : multipart.getBodyParts()) {
viewables.addAll(getViewables(bodyPart, attachments));
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".
@ -159,35 +160,38 @@ public class MessageExtractor {
Message message = (Message) body;
// We add the Message object so we can extract the filename later.
viewables.add(new MessageHeader(part, message));
outputViewableParts.add(new MessageHeader(part, message));
// Recurse to grab all viewable parts and attachments from that message.
viewables.addAll(getViewables(message, attachments));
findViewablesAndAttachments(message, outputViewableParts, outputNonViewableParts);
} else if (isPartTextualBody(part)) {
/*
* Save text/plain and text/html
*/
if (skipSavingViewableParts) {
return;
}
String mimeType = part.getMimeType();
if (isSameMimeType(mimeType, "text/plain")) {
Text text = new Text(part);
viewables.add(text);
outputViewableParts.add(text);
} else {
Html html = new Html(part);
viewables.add(html);
outputViewableParts.add(html);
}
} else if (isSameMimeType(part.getMimeType(), "application/pgp-signature")) {
// ignore this type explicitly
} else {
if (skipSavingNonViewableParts) {
return;
}
// Everything else is treated as attachment.
attachments.add(part);
outputNonViewableParts.add(part);
}
return viewables;
}
public static Set<Part> getTextParts(Part part) throws MessagingException {
List<Part> attachments = new ArrayList<Part>();
return getParts(getViewables(part, attachments));
List<Viewable> viewableParts = new ArrayList<>();
List<Part> nonViewableParts = new ArrayList<>();
findViewablesAndAttachments(part, viewableParts, nonViewableParts);
return getParts(viewableParts);
}
/**
@ -197,8 +201,8 @@ public class MessageExtractor {
*/
public static List<Part> collectAttachments(Message message) throws MessagingException {
try {
List<Part> attachments = new ArrayList<Part>();
getViewables(message, attachments);
List<Part> attachments = new ArrayList<>();
findViewablesAndAttachments(message, new ArrayList<Viewable>(), attachments);
return attachments;
} catch (Exception e) {
throw new MessagingException("Couldn't collect attachment parts", e);
@ -292,7 +296,7 @@ public class MessageExtractor {
*
* @param multipart The {@code Multipart} to search through.
* @param knownTextParts A set of {@code text/plain} parts that shouldn't be added to 'attachments'.
* @param attachments A list that will receive the parts that are considered attachments.
* @param outputNonViewableParts A list that will receive the parts that are considered attachments.
* @param directChild If {@code true}, this method will add all {@code text/html} parts except the first
* found to 'attachments'.
*
@ -301,8 +305,9 @@ public class MessageExtractor {
* @throws MessagingException In case of an error.
*/
private static List<Viewable> findHtmlPart(Multipart multipart, Set<Part> knownTextParts,
List<Part> attachments, boolean directChild) throws MessagingException {
List<Viewable> viewables = new ArrayList<Viewable>();
@Nullable List<Part> outputNonViewableParts, boolean directChild) throws MessagingException {
boolean saveNonViewableParts = outputNonViewableParts != null;
List<Viewable> viewables = new ArrayList<>();
boolean partFound = false;
for (Part part : multipart.getBodyParts()) {
@ -311,8 +316,10 @@ public class MessageExtractor {
Multipart innerMultipart = (Multipart) body;
if (directChild && partFound) {
// We already found our text/html part. Now we're only looking for attachments.
findAttachments(innerMultipart, knownTextParts, attachments);
if (saveNonViewableParts) {
// We already found our text/html part. Now we're only looking for attachments.
findAttachments(innerMultipart, knownTextParts, outputNonViewableParts);
}
} else {
/*
* Recurse to find HTML parts. Since this is a multipart that is a child of a
@ -327,7 +334,7 @@ public class MessageExtractor {
* 1.3. image/jpeg
*/
List<Viewable> htmlViewables = findHtmlPart(innerMultipart, knownTextParts,
attachments, false);
outputNonViewableParts, false);
if (!htmlViewables.isEmpty()) {
partFound = true;
@ -340,9 +347,10 @@ public class MessageExtractor {
viewables.add(html);
partFound = true;
} else if (!knownTextParts.contains(part)) {
// Only add this part as attachment if it's not a viewable text/plain part found
// earlier.
attachments.add(part);
if (saveNonViewableParts) {
// Only add this part as attachment if it's not a viewable text/plain part found earlier
outputNonViewableParts.add(part);
}
}
}
@ -360,7 +368,7 @@ public class MessageExtractor {
* A list that will receive the parts that are considered attachments.
*/
private static void findAttachments(Multipart multipart, Set<Part> knownTextParts,
List<Part> attachments) {
@NonNull List<Part> attachments) {
for (Part part : multipart.getBodyParts()) {
Body body = part.getBody();
if (body instanceof Multipart) {
@ -385,7 +393,7 @@ public class MessageExtractor {
* @see MessageExtractor#findAttachments(Multipart, Set, List)
*/
private static Set<Part> getParts(List<Viewable> viewables) {
Set<Part> parts = new HashSet<Part>();
Set<Part> parts = new HashSet<>();
for (Viewable viewable : viewables) {
if (viewable instanceof Textual) {

View file

@ -7,7 +7,7 @@ import java.util.List;
/**
* Empty marker class interface the class hierarchy used by
* {@link MessageExtractor#getViewables(com.fsck.k9.mail.Part, java.util.List)}
* {@link MessageExtractor#findViewablesAndAttachments(com.fsck.k9.mail.Part, java.util.List)}
*
* @see Viewable.Text
* @see Viewable.Html

View file

@ -1,5 +1,6 @@
package com.fsck.k9.mailstore;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@ -21,15 +22,16 @@ import com.fsck.k9.mail.internet.MimeMessageHelper;
import com.fsck.k9.mail.internet.MimeMultipart;
import com.fsck.k9.mail.internet.TextBody;
import com.fsck.k9.mail.internet.Viewable;
import com.fsck.k9.mailstore.MessageViewInfoExtractor.ViewableExtractedText;
import org.junit.Test;
import org.junit.runner.RunWith;
import static com.fsck.k9.mailstore.LocalMessageExtractor.extractTextAndAttachments;
import static com.fsck.k9.mailstore.MessageViewInfoExtractor.extractTextFromViewables;
import static junit.framework.Assert.assertEquals;
@RunWith(AndroidJUnit4.class)
public class LocalMessageExtractorTest {
public class MessageViewInfoExtractorTest {
@Test
public void testSimplePlainTextMessage() throws MessagingException {
@ -43,10 +45,11 @@ public class LocalMessageExtractorTest {
MimeMessageHelper.setBody(message, body);
// Extract text
List<Part> attachments = new ArrayList<Part>();
List<Viewable> viewables = MessageExtractor.getViewables(message, attachments);
ViewableContainer container = extractTextAndAttachments(InstrumentationRegistry.getTargetContext(),
viewables, attachments);
List<Part> outputNonViewableParts = new ArrayList<Part>();
ArrayList<Viewable> outputViewableParts = new ArrayList<>();
MessageExtractor.findViewablesAndAttachments(message, outputViewableParts, outputNonViewableParts);
ViewableExtractedText container = extractTextFromViewables(InstrumentationRegistry.getTargetContext(),
outputViewableParts);
String expectedText = bodyText;
String expectedHtml =
@ -72,9 +75,10 @@ public class LocalMessageExtractorTest {
// Extract text
List<Part> attachments = new ArrayList<Part>();
List<Viewable> viewables = MessageExtractor.getViewables(message, attachments);
ViewableContainer container = extractTextAndAttachments(InstrumentationRegistry.getTargetContext(),
viewables, attachments);
ArrayList<Viewable> outputViewableParts = new ArrayList<>();
MessageExtractor.findViewablesAndAttachments(message, outputViewableParts, attachments);
ViewableExtractedText container = extractTextFromViewables(InstrumentationRegistry.getTargetContext(),
outputViewableParts);
String expectedText = "K-9 Mail rocks :>";
String expectedHtml =
@ -105,10 +109,11 @@ public class LocalMessageExtractorTest {
MimeMessageHelper.setBody(message, multipart);
// Extract text
List<Part> attachments = new ArrayList<Part>();
List<Viewable> viewables = MessageExtractor.getViewables(message, attachments);
ViewableContainer container = extractTextAndAttachments(InstrumentationRegistry.getTargetContext(),
viewables, attachments);
List<Part> outputNonViewableParts = new ArrayList<Part>();
ArrayList<Viewable> outputViewableParts = new ArrayList<>();
MessageExtractor.findViewablesAndAttachments(message, outputViewableParts, outputNonViewableParts);
ViewableExtractedText container = extractTextFromViewables(InstrumentationRegistry.getTargetContext(),
outputViewableParts);
String expectedText =
bodyText1 + "\r\n\r\n" +
@ -165,10 +170,11 @@ public class LocalMessageExtractorTest {
MimeMessageHelper.setBody(message, multipart);
// Extract text
List<Part> attachments = new ArrayList<Part>();
List<Viewable> viewables = MessageExtractor.getViewables(message, attachments);
ViewableContainer container = extractTextAndAttachments(InstrumentationRegistry.getTargetContext(),
viewables, attachments);
List<Part> outputNonViewableParts = new ArrayList<Part>();
ArrayList<Viewable> outputViewableParts = new ArrayList<>();
MessageExtractor.findViewablesAndAttachments(message, outputViewableParts, outputNonViewableParts);
ViewableExtractedText container = extractTextFromViewables(InstrumentationRegistry.getTargetContext(),
outputViewableParts);
String expectedText =
bodyText +

View file

@ -39,7 +39,6 @@ import com.fsck.k9.activity.misc.SwipeGestureDetector.OnSwipeGestureListener;
import com.fsck.k9.activity.setup.AccountSettings;
import com.fsck.k9.activity.setup.FolderSettings;
import com.fsck.k9.activity.setup.Prefs;
import com.fsck.k9.crypto.PgpData;
import com.fsck.k9.fragment.MessageListFragment;
import com.fsck.k9.fragment.MessageListFragment.MessageListFragmentListener;
import com.fsck.k9.preferences.StorageEditor;
@ -1406,21 +1405,6 @@ public class MessageList extends K9Activity implements MessageListFragmentListen
}
}
@Override
public void onReply(LocalMessage message, PgpData pgpData) {
MessageActions.actionReply(this, message, false, pgpData.getDecryptedData());
}
@Override
public void onReplyAll(LocalMessage message, PgpData pgpData) {
MessageActions.actionReply(this, message, true, pgpData.getDecryptedData());
}
@Override
public void onForward(LocalMessage mMessage, PgpData mPgpData) {
MessageActions.actionForward(this, mMessage, mPgpData.getDecryptedData());
}
@Override
public void showNextMessageOrReturn() {
if (K9.messageViewReturnToList() || !showLogicalNextMessage()) {

View file

@ -1,91 +0,0 @@
package com.fsck.k9.crypto;
import java.io.Serializable;
import org.openintents.openpgp.OpenPgpSignatureResult;
public class PgpData implements Serializable {
private static final long serialVersionUID = 6314045536470848410L;
protected long mEncryptionKeyIds[] = null;
protected long mSignatureKeyId = 0;
protected String mSignatureUserId = null;
protected boolean mSignatureSuccess = false;
protected boolean mSignatureUnknown = false;
protected String mDecryptedData = null;
protected String mEncryptedData = null;
// new API
protected OpenPgpSignatureResult mSignatureResult;
public OpenPgpSignatureResult getSignatureResult() {
return mSignatureResult;
}
public void setSignatureResult(OpenPgpSignatureResult signatureResult) {
this.mSignatureResult = signatureResult;
}
public void setSignatureKeyId(long keyId) {
mSignatureKeyId = keyId;
}
public long getSignatureKeyId() {
return mSignatureKeyId;
}
public void setEncryptionKeys(long keyIds[]) {
mEncryptionKeyIds = keyIds;
}
public long[] getEncryptionKeys() {
return mEncryptionKeyIds;
}
public boolean hasSignatureKey() {
return mSignatureKeyId != 0;
}
public boolean hasEncryptionKeys() {
return (mEncryptionKeyIds != null) && (mEncryptionKeyIds.length > 0);
}
public String getEncryptedData() {
return mEncryptedData;
}
public void setEncryptedData(String data) {
mEncryptedData = data;
}
public String getDecryptedData() {
return mDecryptedData;
}
public void setDecryptedData(String data) {
mDecryptedData = data;
}
public void setSignatureUserId(String userId) {
mSignatureUserId = userId;
}
public String getSignatureUserId() {
return mSignatureUserId;
}
public boolean getSignatureSuccess() {
return mSignatureSuccess;
}
public void setSignatureSuccess(boolean success) {
mSignatureSuccess = success;
}
public boolean getSignatureUnknown() {
return mSignatureUnknown;
}
public void setSignatureUnknown(boolean unknown) {
mSignatureUnknown = unknown;
}
}

View file

@ -8,12 +8,13 @@ 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;
class AttachmentCounter {
public int getAttachmentCount(Message message) throws MessagingException {
List<Part> attachments = new ArrayList<Part>();
MessageExtractor.getViewables(message, attachments);
List<Part> attachments = new ArrayList<>();
MessageExtractor.findViewablesAndAttachments(message, new ArrayList<Viewable>(), attachments);
return attachments.size();
}

View file

@ -0,0 +1,98 @@
package com.fsck.k9.mailstore;
import android.app.PendingIntent;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.fsck.k9.mail.internet.MimeBodyPart;
import org.openintents.openpgp.OpenPgpDecryptionResult;
import org.openintents.openpgp.OpenPgpError;
import org.openintents.openpgp.OpenPgpSignatureResult;
public final class CryptoResultAnnotation {
@NonNull private final CryptoError errorType;
private final MimeBodyPart replacementData;
private final OpenPgpDecryptionResult openPgpDecryptionResult;
private final OpenPgpSignatureResult openPgpSignatureResult;
private final OpenPgpError openPgpError;
private final PendingIntent openPgpPendingIntent;
private CryptoResultAnnotation(@NonNull CryptoError errorType, MimeBodyPart replacementData,
OpenPgpDecryptionResult openPgpDecryptionResult,
OpenPgpSignatureResult openPgpSignatureResult,
PendingIntent openPgpPendingIntent, OpenPgpError openPgpError) {
this.errorType = errorType;
this.replacementData = replacementData;
this.openPgpDecryptionResult = openPgpDecryptionResult;
this.openPgpSignatureResult = openPgpSignatureResult;
this.openPgpPendingIntent = openPgpPendingIntent;
this.openPgpError = openPgpError;
}
public static CryptoResultAnnotation createOpenPgpResultAnnotation(OpenPgpDecryptionResult decryptionResult,
OpenPgpSignatureResult signatureResult, PendingIntent pendingIntent, MimeBodyPart replacementPart) {
return new CryptoResultAnnotation(CryptoError.NONE, replacementPart,
decryptionResult, signatureResult, pendingIntent, null);
}
public static CryptoResultAnnotation createErrorAnnotation(CryptoError error, MimeBodyPart replacementData) {
if (error == CryptoError.NONE) {
throw new AssertionError("CryptoError must be actual error state!");
}
return new CryptoResultAnnotation(error, replacementData, null, null, null, null);
}
public static CryptoResultAnnotation createOpenPgpErrorAnnotation(OpenPgpError error) {
return new CryptoResultAnnotation(CryptoError.OPENPGP_API_RETURNED_ERROR, null, null, null, null, error);
}
@Nullable
public OpenPgpDecryptionResult getOpenPgpDecryptionResult() {
return openPgpDecryptionResult;
}
@Nullable
public OpenPgpSignatureResult getOpenPgpSignatureResult() {
return openPgpSignatureResult;
}
@Nullable
public PendingIntent getOpenPgpPendingIntent() {
return openPgpPendingIntent;
}
@Nullable
public OpenPgpError getOpenPgpError() {
return openPgpError;
}
@NonNull
public CryptoError getErrorType() {
return errorType;
}
public boolean hasReplacementData() {
return replacementData != null;
}
@Nullable
public MimeBodyPart getReplacementData() {
return replacementData;
}
public enum CryptoError {
NONE,
OPENPGP_API_RETURNED_ERROR,
SIGNED_BUT_INCOMPLETE,
ENCRYPTED_BUT_INCOMPLETE,
SIGNED_BUT_UNSUPPORTED,
ENCRYPTED_BUT_UNSUPPORTED,
}
}

View file

@ -53,6 +53,7 @@ import com.fsck.k9.mail.internet.SizeAware;
import com.fsck.k9.mail.message.MessageHeaderParser;
import com.fsck.k9.mailstore.LockableDatabase.DbCallback;
import com.fsck.k9.mailstore.LockableDatabase.WrappedException;
import com.fsck.k9.message.extractors.AttachmentInfoExtractor;
import com.fsck.k9.message.extractors.MessagePreviewCreator;
import com.fsck.k9.message.extractors.PreviewResult;
import com.fsck.k9.message.extractors.PreviewResult.PreviewType;
@ -1400,7 +1401,7 @@ public class LocalFolder extends Folder<LocalMessage> implements Serializable {
}
private void missingPartToContentValues(ContentValues cv, Part part) throws MessagingException {
AttachmentViewInfo attachment = LocalMessageExtractor.extractAttachmentInfo(part);
AttachmentViewInfo attachment = AttachmentInfoExtractor.extractAttachmentInfo(part);
cv.put("display_name", attachment.displayName);
cv.put("data_location", DataLocation.MISSING);
cv.put("decoded_body_size", attachment.size);
@ -1412,7 +1413,7 @@ public class LocalFolder extends Folder<LocalMessage> implements Serializable {
private File leafPartToContentValues(ContentValues cv, Part part, Body body)
throws MessagingException, IOException {
AttachmentViewInfo attachment = LocalMessageExtractor.extractAttachmentInfo(part);
AttachmentViewInfo attachment = AttachmentInfoExtractor.extractAttachmentInfo(part);
cv.put("display_name", attachment.displayName);
String encoding = getTransferEncoding(part);

View file

@ -22,11 +22,11 @@ public class MessageViewInfo {
public final String text;
public final Part rootPart;
public final List<AttachmentViewInfo> attachments;
public final OpenPgpResultAnnotation cryptoAnnotation;
public final CryptoResultAnnotation cryptoAnnotation;
MessageViewContainer(String text, Part rootPart, List<AttachmentViewInfo> attachments,
OpenPgpResultAnnotation cryptoAnnotation) {
CryptoResultAnnotation cryptoAnnotation) {
this.text = text;
this.rootPart = rootPart;
this.attachments = attachments;

View file

@ -1,9 +1,15 @@
package com.fsck.k9.mailstore;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import android.content.Context;
import android.net.Uri;
import android.support.annotation.VisibleForTesting;
import com.fsck.k9.R;
import com.fsck.k9.helper.HtmlConverter;
import com.fsck.k9.mail.Address;
import com.fsck.k9.mail.Body;
import com.fsck.k9.mail.BodyPart;
@ -11,21 +17,13 @@ import com.fsck.k9.mail.Message;
import com.fsck.k9.mail.MessagingException;
import com.fsck.k9.mail.Multipart;
import com.fsck.k9.mail.Part;
import com.fsck.k9.helper.HtmlConverter;
import com.fsck.k9.mail.internet.MessageExtractor;
import com.fsck.k9.mail.internet.MimeHeader;
import com.fsck.k9.mail.internet.MimeUtility;
import com.fsck.k9.mail.internet.Viewable;
import com.fsck.k9.mailstore.MessageViewInfo.MessageViewContainer;
import com.fsck.k9.provider.AttachmentProvider;
import com.fsck.k9.provider.K9FileProvider;
import com.fsck.k9.message.extractors.AttachmentInfoExtractor;
import com.fsck.k9.ui.crypto.MessageCryptoAnnotations;
import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import static com.fsck.k9.mail.internet.MimeUtility.getHeaderParameter;
import static com.fsck.k9.mail.internet.Viewable.Alternative;
import static com.fsck.k9.mail.internet.Viewable.Html;
@ -33,7 +31,7 @@ import static com.fsck.k9.mail.internet.Viewable.MessageHeader;
import static com.fsck.k9.mail.internet.Viewable.Text;
import static com.fsck.k9.mail.internet.Viewable.Textual;
public class LocalMessageExtractor {
public class MessageViewInfoExtractor {
private static final String TEXT_DIVIDER =
"------------------------------------------------------------------------";
private static final int TEXT_DIVIDER_LENGTH = TEXT_DIVIDER.length();
@ -41,23 +39,99 @@ public class LocalMessageExtractor {
private static final int FILENAME_PREFIX_LENGTH = FILENAME_PREFIX.length();
private static final String FILENAME_SUFFIX = " ";
private static final int FILENAME_SUFFIX_LENGTH = FILENAME_SUFFIX.length();
private static final OpenPgpResultAnnotation NO_ANNOTATIONS = null;
private static final CryptoResultAnnotation NO_ANNOTATIONS = null;
private MessageViewInfoExtractor() {}
public static MessageViewInfo extractMessageForView(Context context,
Message message, MessageCryptoAnnotations annotations) throws MessagingException {
// TODO note that we will move away from ViewableContainers, so this method is subject to changes!
// 1. break mime structure on encryption/signature boundaries
List<Part> parts = getCryptPieces(message, annotations);
// 2. extract viewables/attachments of parts
ArrayList<MessageViewContainer> containers = new ArrayList<>();
for (Part part : parts) {
CryptoResultAnnotation pgpAnnotation = annotations.get(part);
// TODO properly handle decrypted data part - this just replaces the part
if (pgpAnnotation != NO_ANNOTATIONS && pgpAnnotation.hasReplacementData()) {
part = pgpAnnotation.getReplacementData();
}
ArrayList<Viewable> viewableParts = new ArrayList<>();
ArrayList<Part> attachments = new ArrayList<>();
MessageExtractor.findViewablesAndAttachments(part, viewableParts, attachments);
// 3. parse viewables into html string
ViewableExtractedText viewable = MessageViewInfoExtractor.extractTextFromViewables(context, viewableParts);
List<AttachmentViewInfo> attachmentInfos = AttachmentInfoExtractor.extractAttachmentInfos(context, attachments);
MessageViewContainer messageViewContainer =
new MessageViewContainer(viewable.html, part, attachmentInfos, pgpAnnotation);
containers.add(messageViewContainer);
}
return new MessageViewInfo(containers, message);
}
public static List<Part> getCryptPieces(Message message, MessageCryptoAnnotations annotations) throws MessagingException {
// TODO make sure this method does what it is supposed to
/* This method returns a list of mime parts which are to be parsed into
* individual MessageViewContainers for display, which each have their
* own crypto header. This means parts should be individual for each
* multipart/encrypted, multipart/signed, or a multipart/* which does
* not contain children of the former types.
*/
ArrayList<Part> parts = new ArrayList<>();
if (!getCryptSubPieces(message, parts, annotations)) {
parts.add(message);
}
return parts;
}
public static boolean getCryptSubPieces(Part part, ArrayList<Part> parts,
MessageCryptoAnnotations annotations) throws MessagingException {
Body body = part.getBody();
if (body instanceof Multipart) {
Multipart multi = (Multipart) body;
if (MimeUtility.isSameMimeType(part.getMimeType(), "multipart/mixed")) {
boolean foundSome = false;
for (BodyPart sub : multi.getBodyParts()) {
foundSome |= getCryptSubPieces(sub, parts, annotations);
}
if (!foundSome) {
parts.add(part);
return true;
}
} else if (annotations.has(part)) {
parts.add(part);
return true;
}
}
return false;
}
private LocalMessageExtractor() {}
/**
* Extract the viewable textual parts of a message and return the rest as attachments.
*
* @param context A {@link android.content.Context} instance that will be used to get localized strings.
* @return A {@link ViewableContainer} instance containing the textual parts of the message as
* @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.
*/
public static ViewableContainer extractTextAndAttachments(Context context, List<Viewable> viewables,
List<Part> attachments) throws MessagingException {
@VisibleForTesting
static ViewableExtractedText extractTextFromViewables(Context context, List<Viewable> viewables)
throws MessagingException {
try {
// Collect all viewable parts
/*
@ -120,7 +194,7 @@ public class LocalMessageExtractor {
}
}
return new ViewableContainer(text.toString(), html.toString(), attachments);
return new ViewableExtractedText(text.toString(), html.toString());
} catch (Exception e) {
throw new MessagingException("Couldn't extract viewable parts", e);
}
@ -142,8 +216,7 @@ public class LocalMessageExtractor {
*
* @return The contents of the supplied viewable instance as HTML.
*/
private static StringBuilder buildHtml(Viewable viewable, boolean prependDivider)
{
private static StringBuilder buildHtml(Viewable viewable, boolean prependDivider) {
StringBuilder html = new StringBuilder();
if (viewable instanceof Textual) {
Part part = ((Textual)viewable).getPart();
@ -174,8 +247,7 @@ public class LocalMessageExtractor {
return html;
}
private static StringBuilder buildText(Viewable viewable, boolean prependDivider)
{
private static StringBuilder buildText(Viewable viewable, boolean prependDivider) {
StringBuilder text = new StringBuilder();
if (viewable instanceof Textual) {
Part part = ((Textual)viewable).getPart();
@ -418,167 +490,14 @@ public class LocalMessageExtractor {
html.append("</td></tr>");
}
public static MessageViewInfo decodeMessageForView(Context context,
Message message, MessageCryptoAnnotations annotations) throws MessagingException {
@VisibleForTesting
static class ViewableExtractedText {
public final String text;
public final String html;
// 1. break mime structure on encryption/signature boundaries
List<Part> parts = getCryptPieces(message, annotations);
// 2. extract viewables/attachments of parts
ArrayList<MessageViewContainer> containers = new ArrayList<>();
for (Part part : parts) {
OpenPgpResultAnnotation pgpAnnotation = annotations.get(part);
// TODO properly handle decrypted data part - this just replaces the part
if (pgpAnnotation != NO_ANNOTATIONS && pgpAnnotation.hasOutputData()) {
part = pgpAnnotation.getOutputData();
}
ArrayList<Part> attachments = new ArrayList<>();
List<Viewable> viewables = MessageExtractor.getViewables(part, attachments);
// 3. parse viewables into html string
ViewableContainer viewable = LocalMessageExtractor.extractTextAndAttachments(context, viewables,
attachments);
List<AttachmentViewInfo> attachmentInfos = extractAttachmentInfos(context, attachments);
MessageViewContainer messageViewContainer =
new MessageViewContainer(viewable.html, part, attachmentInfos, pgpAnnotation);
containers.add(messageViewContainer);
public ViewableExtractedText(String text, String html) {
this.text = text;
this.html = html;
}
return new MessageViewInfo(containers, message);
}
public static List<Part> getCryptPieces(Message message, MessageCryptoAnnotations annotations) throws MessagingException {
// TODO make sure this method does what it is supposed to
/* This method returns a list of mime parts which are to be parsed into
* individual MessageViewContainers for display, which each have their
* own crypto header. This means parts should be individual for each
* multipart/encrypted, multipart/signed, or a multipart/* which does
* not contain children of the former types.
*/
ArrayList<Part> parts = new ArrayList<>();
if (!getCryptSubPieces(message, parts, annotations)) {
parts.add(message);
}
return parts;
}
public static boolean getCryptSubPieces(Part part, ArrayList<Part> parts,
MessageCryptoAnnotations annotations) throws MessagingException {
Body body = part.getBody();
if (body instanceof Multipart) {
Multipart multi = (Multipart) body;
if (MimeUtility.isSameMimeType(part.getMimeType(), "multipart/mixed")) {
boolean foundSome = false;
for (BodyPart sub : multi.getBodyParts()) {
foundSome |= getCryptSubPieces(sub, parts, annotations);
}
if (!foundSome) {
parts.add(part);
return true;
}
} else if (annotations.has(part)) {
parts.add(part);
return true;
}
}
return false;
}
private static List<AttachmentViewInfo> extractAttachmentInfos(Context context, List<Part> attachmentParts)
throws MessagingException {
List<AttachmentViewInfo> attachments = new ArrayList<>();
for (Part part : attachmentParts) {
attachments.add(extractAttachmentInfo(context, part));
}
return attachments;
}
public static AttachmentViewInfo extractAttachmentInfo(Context context, Part part) throws MessagingException {
if (part instanceof LocalPart) {
LocalPart localPart = (LocalPart) part;
String accountUuid = localPart.getAccountUuid();
long messagePartId = localPart.getId();
String mimeType = part.getMimeType();
String displayName = localPart.getDisplayName();
long size = localPart.getSize();
boolean firstClassAttachment = localPart.isFirstClassAttachment();
Uri uri = AttachmentProvider.getAttachmentUri(accountUuid, messagePartId);
return new AttachmentViewInfo(mimeType, displayName, size, uri, firstClassAttachment, part);
} else {
Body body = part.getBody();
if (body instanceof DecryptedTempFileBody) {
DecryptedTempFileBody decryptedTempFileBody = (DecryptedTempFileBody) body;
File file = decryptedTempFileBody.getFile();
Uri uri = K9FileProvider.getUriForFile(context, file, part.getMimeType());
long size = file.length();
return extractAttachmentInfo(part, uri, size);
} else {
throw new RuntimeException("Not supported");
}
}
}
public static AttachmentViewInfo extractAttachmentInfo(Part part) throws MessagingException {
return extractAttachmentInfo(part, Uri.EMPTY, AttachmentViewInfo.UNKNOWN_SIZE);
}
private static AttachmentViewInfo extractAttachmentInfo(Part part, Uri uri, long size) throws MessagingException {
boolean firstClassAttachment = true;
String mimeType = part.getMimeType();
String contentTypeHeader = MimeUtility.unfoldAndDecode(part.getContentType());
String contentDisposition = MimeUtility.unfoldAndDecode(part.getDisposition());
String name = MimeUtility.getHeaderParameter(contentDisposition, "filename");
if (name == null) {
name = MimeUtility.getHeaderParameter(contentTypeHeader, "name");
}
if (name == null) {
firstClassAttachment = false;
String extension = MimeUtility.getExtensionByMimeType(mimeType);
name = "noname" + ((extension != null) ? "." + extension : "");
}
// Inline parts with a content-id are almost certainly components of an HTML message
// not attachments. Only show them if the user pressed the button to show more
// attachments.
if (contentDisposition != null &&
MimeUtility.getHeaderParameter(contentDisposition, null).matches("^(?i:inline)") &&
part.getHeader(MimeHeader.HEADER_CONTENT_ID).length > 0) {
firstClassAttachment = false;
}
long attachmentSize = extractAttachmentSize(contentDisposition, size);
return new AttachmentViewInfo(mimeType, name, attachmentSize, uri, firstClassAttachment, part);
}
private static long extractAttachmentSize(String contentDisposition, long size) {
if (size != AttachmentViewInfo.UNKNOWN_SIZE) {
return size;
}
long result = AttachmentViewInfo.UNKNOWN_SIZE;
String sizeParam = MimeUtility.getHeaderParameter(contentDisposition, "size");
if (sizeParam != null) {
try {
result = Integer.parseInt(sizeParam);
} catch (NumberFormatException e) { /* ignore */ }
}
return result;
}
}

View file

@ -1,81 +0,0 @@
package com.fsck.k9.mailstore;
import android.app.PendingIntent;
import com.fsck.k9.mail.internet.MimeBodyPart;
import org.openintents.openpgp.OpenPgpDecryptionResult;
import org.openintents.openpgp.OpenPgpError;
import org.openintents.openpgp.OpenPgpSignatureResult;
public final class OpenPgpResultAnnotation {
private OpenPgpDecryptionResult decryptionResult;
private OpenPgpSignatureResult signatureResult;
private OpenPgpError error;
private CryptoError errorType = CryptoError.NONE;
private PendingIntent pendingIntent;
private MimeBodyPart outputData;
public OpenPgpDecryptionResult getDecryptionResult() {
return decryptionResult;
}
public void setDecryptionResult(OpenPgpDecryptionResult decryptionResult) {
this.decryptionResult = decryptionResult;
}
public OpenPgpSignatureResult getSignatureResult() {
return signatureResult;
}
public void setSignatureResult(OpenPgpSignatureResult signatureResult) {
this.signatureResult = signatureResult;
}
public PendingIntent getPendingIntent() {
return pendingIntent;
}
public void setPendingIntent(PendingIntent pendingIntent) {
this.pendingIntent = pendingIntent;
}
public OpenPgpError getError() {
return error;
}
public void setError(OpenPgpError error) {
this.error = error;
setErrorType(CryptoError.CRYPTO_API_RETURNED_ERROR);
}
public CryptoError getErrorType() {
return errorType;
}
public void setErrorType(CryptoError errorType) {
this.errorType = errorType;
}
public boolean hasOutputData() {
return outputData != null;
}
public void setOutputData(MimeBodyPart outputData) {
this.outputData = outputData;
}
public MimeBodyPart getOutputData() {
return outputData;
}
public enum CryptoError {
NONE,
CRYPTO_API_RETURNED_ERROR,
SIGNED_BUT_INCOMPLETE,
ENCRYPTED_BUT_INCOMPLETE
}
}

View file

@ -1,34 +0,0 @@
package com.fsck.k9.mailstore;
import com.fsck.k9.mail.Part;
import java.util.List;
/**
* Store viewable text of a message as plain text and HTML, and the parts considered
* attachments.
*
* @see LocalMessageExtractor#extractTextAndAttachments(android.content.Context, com.fsck.k9.mail.Message)
*/
public class ViewableContainer {
/**
* The viewable text of the message in plain text.
*/
public final String text;
/**
* The viewable text of the message in HTML.
*/
public final String html;
/**
* The parts of the message considered attachments (everything not viewable).
*/
public final List<Part> attachments;
public ViewableContainer(String text, String html, List<Part> attachments) {
this.text = text;
this.html = html;
this.attachments = attachments;
}
}

View file

@ -0,0 +1,112 @@
package com.fsck.k9.message.extractors;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.net.Uri;
import com.fsck.k9.mail.Body;
import com.fsck.k9.mail.MessagingException;
import com.fsck.k9.mail.Part;
import com.fsck.k9.mail.internet.MimeHeader;
import com.fsck.k9.mail.internet.MimeUtility;
import com.fsck.k9.mailstore.AttachmentViewInfo;
import com.fsck.k9.mailstore.DecryptedTempFileBody;
import com.fsck.k9.mailstore.LocalPart;
import com.fsck.k9.provider.AttachmentProvider;
import com.fsck.k9.provider.K9FileProvider;
public class AttachmentInfoExtractor {
public static List<AttachmentViewInfo> extractAttachmentInfos(Context context, List<Part> attachmentParts)
throws MessagingException {
List<AttachmentViewInfo> attachments = new ArrayList<>();
for (Part part : attachmentParts) {
attachments.add(extractAttachmentInfo(context, part));
}
return attachments;
}
public static AttachmentViewInfo extractAttachmentInfo(Context context, Part part) throws MessagingException {
if (part instanceof LocalPart) {
LocalPart localPart = (LocalPart) part;
String accountUuid = localPart.getAccountUuid();
long messagePartId = localPart.getId();
String mimeType = part.getMimeType();
String displayName = localPart.getDisplayName();
long size = localPart.getSize();
boolean firstClassAttachment = localPart.isFirstClassAttachment();
Uri uri = AttachmentProvider.getAttachmentUri(accountUuid, messagePartId);
return new AttachmentViewInfo(mimeType, displayName, size, uri, firstClassAttachment, part);
} else {
Body body = part.getBody();
if (body instanceof DecryptedTempFileBody) {
DecryptedTempFileBody decryptedTempFileBody = (DecryptedTempFileBody) body;
File file = decryptedTempFileBody.getFile();
Uri uri = K9FileProvider.getUriForFile(context, file, part.getMimeType());
long size = file.length();
return extractAttachmentInfo(part, uri, size);
} else {
throw new RuntimeException("Not supported");
}
}
}
public static AttachmentViewInfo extractAttachmentInfo(Part part) throws MessagingException {
return extractAttachmentInfo(part, Uri.EMPTY, AttachmentViewInfo.UNKNOWN_SIZE);
}
private static AttachmentViewInfo extractAttachmentInfo(Part part, Uri uri, long size) throws MessagingException {
boolean firstClassAttachment = true;
String mimeType = part.getMimeType();
String contentTypeHeader = MimeUtility.unfoldAndDecode(part.getContentType());
String contentDisposition = MimeUtility.unfoldAndDecode(part.getDisposition());
String name = MimeUtility.getHeaderParameter(contentDisposition, "filename");
if (name == null) {
name = MimeUtility.getHeaderParameter(contentTypeHeader, "name");
}
if (name == null) {
firstClassAttachment = false;
String extension = MimeUtility.getExtensionByMimeType(mimeType);
name = "noname" + ((extension != null) ? "." + extension : "");
}
// Inline parts with a content-id are almost certainly components of an HTML message
// not attachments. Only show them if the user pressed the button to show more
// attachments.
if (contentDisposition != null &&
MimeUtility.getHeaderParameter(contentDisposition, null).matches("^(?i:inline)") &&
part.getHeader(MimeHeader.HEADER_CONTENT_ID).length > 0) {
firstClassAttachment = false;
}
long attachmentSize = extractAttachmentSize(contentDisposition, size);
return new AttachmentViewInfo(mimeType, name, attachmentSize, uri, firstClassAttachment, part);
}
private static long extractAttachmentSize(String contentDisposition, long size) {
if (size != AttachmentViewInfo.UNKNOWN_SIZE) {
return size;
}
long result = AttachmentViewInfo.UNKNOWN_SIZE;
String sizeParam = MimeUtility.getHeaderParameter(contentDisposition, "size");
if (sizeParam != null) {
try {
result = Integer.parseInt(sizeParam);
} catch (NumberFormatException e) { /* ignore */ }
}
return result;
}
}

View file

@ -4,21 +4,21 @@ package com.fsck.k9.ui.crypto;
import java.util.HashMap;
import com.fsck.k9.mail.Part;
import com.fsck.k9.mailstore.OpenPgpResultAnnotation;
import com.fsck.k9.mailstore.CryptoResultAnnotation;
public class MessageCryptoAnnotations {
private HashMap<Part, OpenPgpResultAnnotation> annotations = new HashMap<Part, OpenPgpResultAnnotation>();
private HashMap<Part, CryptoResultAnnotation> annotations = new HashMap<Part, CryptoResultAnnotation>();
MessageCryptoAnnotations() {
// Package-private constructor
}
void put(Part part, OpenPgpResultAnnotation annotation) {
void put(Part part, CryptoResultAnnotation annotation) {
annotations.put(part, annotation);
}
public OpenPgpResultAnnotation get(Part part) {
public CryptoResultAnnotation get(Part part) {
return annotations.get(part);
}

View file

@ -33,9 +33,8 @@ import com.fsck.k9.mail.internet.TextBody;
import com.fsck.k9.mailstore.DecryptStreamParser;
import com.fsck.k9.mailstore.LocalMessage;
import com.fsck.k9.mailstore.MessageHelper;
import com.fsck.k9.mailstore.OpenPgpResultAnnotation;
import com.fsck.k9.mailstore.OpenPgpResultAnnotation.CryptoError;
import org.openintents.openpgp.IOpenPgpService;
import com.fsck.k9.mailstore.CryptoResultAnnotation;
import com.fsck.k9.mailstore.CryptoResultAnnotation.CryptoError;
import org.openintents.openpgp.IOpenPgpService2;
import org.openintents.openpgp.OpenPgpDecryptionResult;
import org.openintents.openpgp.OpenPgpError;
@ -58,7 +57,7 @@ public class MessageCryptoHelper {
private final Account account;
private LocalMessage message;
private Deque<CryptoPart> partsToDecryptOrVerify = new ArrayDeque<CryptoPart>();
private Deque<CryptoPart> partsToDecryptOrVerify = new ArrayDeque<>();
private OpenPgpApi openPgpApi;
private CryptoPart currentCryptoPart;
private Intent currentCryptoResult;
@ -109,10 +108,8 @@ public class MessageCryptoHelper {
}
}
private void addErrorAnnotation(Part part, CryptoError error, MimeBodyPart outputData) {
OpenPgpResultAnnotation annotation = new OpenPgpResultAnnotation();
annotation.setErrorType(error);
annotation.setOutputData(outputData);
private void addErrorAnnotation(Part part, CryptoError error, MimeBodyPart replacementPart) {
CryptoResultAnnotation annotation = CryptoResultAnnotation.createErrorAnnotation(error, replacementPart);
messageAnnotations.put(part, annotation);
}
@ -411,11 +408,8 @@ public class MessageCryptoHelper {
currentCryptoResult.getParcelableExtra(OpenPgpApi.RESULT_SIGNATURE);
PendingIntent pendingIntent = currentCryptoResult.getParcelableExtra(OpenPgpApi.RESULT_INTENT);
OpenPgpResultAnnotation resultAnnotation = new OpenPgpResultAnnotation();
resultAnnotation.setOutputData(outputPart);
resultAnnotation.setDecryptionResult(decryptionResult);
resultAnnotation.setSignatureResult(signatureResult);
resultAnnotation.setPendingIntent(pendingIntent);
CryptoResultAnnotation resultAnnotation = CryptoResultAnnotation.createOpenPgpResultAnnotation(
decryptionResult, signatureResult, pendingIntent, outputPart);
onCryptoSuccess(resultAnnotation);
}
@ -433,23 +427,22 @@ public class MessageCryptoHelper {
}
}
private void onCryptoSuccess(OpenPgpResultAnnotation resultAnnotation) {
addOpenPgpResultPartToMessage(resultAnnotation);
private void onCryptoSuccess(CryptoResultAnnotation resultAnnotation) {
addCryptoResultAnnotationToMessage(resultAnnotation);
onCryptoFinished();
}
private void addOpenPgpResultPartToMessage(OpenPgpResultAnnotation resultAnnotation) {
Part part = currentCryptoPart.part;
messageAnnotations.put(part, resultAnnotation);
}
private void onCryptoFailed(OpenPgpError error) {
OpenPgpResultAnnotation errorPart = new OpenPgpResultAnnotation();
errorPart.setError(error);
addOpenPgpResultPartToMessage(errorPart);
CryptoResultAnnotation errorPart = CryptoResultAnnotation.createOpenPgpErrorAnnotation(error);
addCryptoResultAnnotationToMessage(errorPart);
onCryptoFinished();
}
private void addCryptoResultAnnotationToMessage(CryptoResultAnnotation resultAnnotation) {
Part part = currentCryptoPart.part;
messageAnnotations.put(part, resultAnnotation);
}
private void onCryptoFinished() {
partsToDecryptOrVerify.removeFirst();
decryptOrVerifyNextPart();

View file

@ -9,19 +9,19 @@ import android.widget.Toast;
import com.fsck.k9.K9;
import com.fsck.k9.R;
import com.fsck.k9.mail.Message;
import com.fsck.k9.mailstore.LocalMessageExtractor;
import com.fsck.k9.mailstore.MessageViewInfoExtractor;
import com.fsck.k9.mailstore.MessageViewInfo;
import com.fsck.k9.ui.crypto.MessageCryptoAnnotations;
import java.util.Collections;
public class DecodeMessageLoader extends AsyncTaskLoader<MessageViewInfo> {
public class LocalMessageExtractorLoader extends AsyncTaskLoader<MessageViewInfo> {
private final Message message;
private MessageViewInfo messageViewInfo;
private MessageCryptoAnnotations annotations;
public DecodeMessageLoader(Context context, Message message, MessageCryptoAnnotations annotations) {
public LocalMessageExtractorLoader(Context context, Message message, MessageCryptoAnnotations annotations) {
super(context);
this.message = message;
this.annotations = annotations;
@ -47,7 +47,7 @@ public class DecodeMessageLoader extends AsyncTaskLoader<MessageViewInfo> {
@Override
public MessageViewInfo loadInBackground() {
try {
return LocalMessageExtractor.decodeMessageForView(getContext(), message, annotations);
return MessageViewInfoExtractor.extractMessageForView(getContext(), message, annotations);
} catch (Exception e) {
Log.e(K9.LOG_TAG, "Error while decoding message", e);
return null;

View file

@ -38,8 +38,8 @@ import com.fsck.k9.mail.MessagingException;
import com.fsck.k9.mailstore.AttachmentViewInfo;
import com.fsck.k9.mailstore.MessageViewInfo.MessageViewContainer;
import com.fsck.k9.mailstore.OpenPgpResultAnnotation;
import com.fsck.k9.mailstore.OpenPgpResultAnnotation.CryptoError;
import com.fsck.k9.mailstore.CryptoResultAnnotation;
import com.fsck.k9.mailstore.CryptoResultAnnotation.CryptoError;
import com.fsck.k9.view.K9WebViewClient;
import com.fsck.k9.view.MessageHeader.OnLayoutChangedListener;
import com.fsck.k9.view.MessageWebView;
@ -443,7 +443,7 @@ public class MessageContainerView extends LinearLayout implements OnClickListene
ViewStub openPgpHeaderStub = (ViewStub) findViewById(R.id.openpgp_header_stub);
OpenPgpHeaderView openPgpHeaderView = (OpenPgpHeaderView) openPgpHeaderStub.inflate();
OpenPgpResultAnnotation cryptoAnnotation = messageViewContainer.cryptoAnnotation;
CryptoResultAnnotation cryptoAnnotation = messageViewContainer.cryptoAnnotation;
openPgpHeaderView.setOpenPgpData(cryptoAnnotation);
openPgpHeaderView.setCallback(openPgpHeaderViewCallback);
mSidebar.setVisibility(View.VISIBLE);
@ -462,16 +462,16 @@ public class MessageContainerView extends LinearLayout implements OnClickListene
}
private String getTextToDisplay(MessageViewContainer messageViewContainer) {
OpenPgpResultAnnotation cryptoAnnotation = messageViewContainer.cryptoAnnotation;
CryptoResultAnnotation cryptoAnnotation = messageViewContainer.cryptoAnnotation;
if (cryptoAnnotation == null) {
return messageViewContainer.text;
}
CryptoError errorType = cryptoAnnotation.getErrorType();
switch (errorType) {
case CRYPTO_API_RETURNED_ERROR: {
case OPENPGP_API_RETURNED_ERROR: {
// TODO make a nice view for this
return wrapStatusMessage(cryptoAnnotation.getError().getMessage());
return wrapStatusMessage(cryptoAnnotation.getOpenPgpError().getMessage());
}
case ENCRYPTED_BUT_INCOMPLETE: {
return wrapStatusMessage(getContext().getString(R.string.crypto_download_complete_message_to_decrypt));

View file

@ -36,7 +36,6 @@ import com.fsck.k9.activity.ChooseFolder;
import com.fsck.k9.activity.MessageReference;
import com.fsck.k9.controller.MessagingController;
import com.fsck.k9.controller.MessagingListener;
import com.fsck.k9.crypto.PgpData;
import com.fsck.k9.fragment.ConfirmationDialogFragment;
import com.fsck.k9.fragment.ConfirmationDialogFragment.ConfirmationDialogFragmentListener;
import com.fsck.k9.fragment.ProgressDialogFragment;
@ -50,7 +49,7 @@ import com.fsck.k9.mailstore.MessageViewInfo;
import com.fsck.k9.mailstore.MessageViewInfo.MessageViewContainer;
import com.fsck.k9.ui.crypto.MessageCryptoCallback;
import com.fsck.k9.ui.crypto.MessageCryptoHelper;
import com.fsck.k9.ui.message.DecodeMessageLoader;
import com.fsck.k9.ui.message.LocalMessageExtractorLoader;
import com.fsck.k9.ui.message.LocalMessageLoader;
import com.fsck.k9.ui.crypto.MessageCryptoAnnotations;
import com.fsck.k9.view.MessageHeader;
@ -80,7 +79,6 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF
}
private MessageTopView mMessageView;
private PgpData mPgpData;
private Account mAccount;
private MessageReference mMessageReference;
private LocalMessage mMessage;
@ -175,28 +173,12 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
initializePgpData(savedInstanceState);
Bundle arguments = getArguments();
MessageReference messageReference = arguments.getParcelable(ARG_REFERENCE);
displayMessage(messageReference);
}
private void initializePgpData(Bundle savedInstanceState) {
if (savedInstanceState != null) {
mPgpData = (PgpData) savedInstanceState.get(STATE_PGP_DATA);
} else {
mPgpData = new PgpData();
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putSerializable(STATE_PGP_DATA, mPgpData);
}
private void displayMessage(MessageReference messageReference) {
mMessageReference = messageReference;
if (K9.DEBUG) {
@ -363,19 +345,19 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF
public void onReply() {
if (mMessage != null) {
mFragmentListener.onReply(mMessage, mPgpData);
mFragmentListener.onReply(mMessage);
}
}
public void onReplyAll() {
if (mMessage != null) {
mFragmentListener.onReplyAll(mMessage, mPgpData);
mFragmentListener.onReplyAll(mMessage);
}
}
public void onForward() {
if (mMessage != null) {
mFragmentListener.onForward(mMessage, mPgpData);
mFragmentListener.onForward(mMessage);
}
}
@ -714,10 +696,10 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF
}
public interface MessageViewFragmentListener {
public void onForward(LocalMessage mMessage, PgpData mPgpData);
public void onForward(LocalMessage mMessage);
public void disableDeleteAction();
public void onReplyAll(LocalMessage mMessage, PgpData mPgpData);
public void onReply(LocalMessage mMessage, PgpData mPgpData);
public void onReplyAll(LocalMessage mMessage);
public void onReply(LocalMessage mMessage);
public void displayMessageSubject(String title);
public void setProgress(boolean b);
public void showNextMessageOrReturn();
@ -757,18 +739,27 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF
class DecodeMessageLoaderCallback implements LoaderCallbacks<MessageViewInfo> {
@Override
public Loader<MessageViewInfo> onCreateLoader(int id, Bundle args) {
if (id != DECODE_MESSAGE_LOADER_ID) {
throw new IllegalStateException("loader id must be message decoder id");
}
setProgress(true);
return new DecodeMessageLoader(mContext, mMessage, messageAnnotations);
return new LocalMessageExtractorLoader(mContext, mMessage, messageAnnotations);
}
@Override
public void onLoadFinished(Loader<MessageViewInfo> loader, MessageViewInfo messageViewInfo) {
if (loader.getId() != DECODE_MESSAGE_LOADER_ID) {
throw new IllegalStateException("loader id must be message decoder id");
}
setProgress(false);
onDecodeMessageFinished(messageViewInfo);
}
@Override
public void onLoaderReset(Loader<MessageViewInfo> loader) {
if (loader.getId() != DECODE_MESSAGE_LOADER_ID) {
throw new IllegalStateException("loader id must be message decoder id");
}
// Do nothing
}
}

View file

@ -17,7 +17,7 @@ import android.widget.LinearLayout;
import android.widget.TextView;
import com.fsck.k9.R;
import com.fsck.k9.mailstore.OpenPgpResultAnnotation;
import com.fsck.k9.mailstore.CryptoResultAnnotation;
import org.openintents.openpgp.OpenPgpDecryptionResult;
import org.openintents.openpgp.OpenPgpError;
import org.openintents.openpgp.OpenPgpSignatureResult;
@ -28,7 +28,7 @@ public class OpenPgpHeaderView extends LinearLayout {
private Context context;
private OpenPgpHeaderViewCallback callback;
private OpenPgpResultAnnotation cryptoAnnotation;
private CryptoResultAnnotation cryptoAnnotation;
private ImageView resultEncryptionIcon;
private TextView resultEncryptionText;
@ -63,7 +63,7 @@ public class OpenPgpHeaderView extends LinearLayout {
this.callback = callback;
}
public void setOpenPgpData(OpenPgpResultAnnotation cryptoAnnotation) {
public void setOpenPgpData(CryptoResultAnnotation cryptoAnnotation) {
this.cryptoAnnotation = cryptoAnnotation;
initializeEncryptionHeader();
@ -78,7 +78,7 @@ public class OpenPgpHeaderView extends LinearLayout {
switch (cryptoAnnotation.getErrorType()) {
case NONE: {
OpenPgpDecryptionResult decryptionResult = cryptoAnnotation.getDecryptionResult();
OpenPgpDecryptionResult decryptionResult = cryptoAnnotation.getOpenPgpDecryptionResult();
switch (decryptionResult.getResult()) {
case OpenPgpDecryptionResult.RESULT_NOT_ENCRYPTED: {
displayNotEncrypted();
@ -97,7 +97,7 @@ public class OpenPgpHeaderView extends LinearLayout {
}
break;
}
case CRYPTO_API_RETURNED_ERROR: {
case OPENPGP_API_RETURNED_ERROR: {
displayEncryptionError();
break;
}
@ -134,7 +134,7 @@ public class OpenPgpHeaderView extends LinearLayout {
private void displayEncryptionError() {
setEncryptionImageAndTextColor(CryptoState.INVALID);
OpenPgpError error = cryptoAnnotation.getError();
OpenPgpError error = cryptoAnnotation.getOpenPgpError();
String text;
if (error == null) {
text = context.getString(R.string.openpgp_unknown_error);
@ -158,7 +158,7 @@ public class OpenPgpHeaderView extends LinearLayout {
}
switch (cryptoAnnotation.getErrorType()) {
case CRYPTO_API_RETURNED_ERROR:
case OPENPGP_API_RETURNED_ERROR:
displayEncryptionError();
hideVerificationState();
break;
@ -187,7 +187,7 @@ public class OpenPgpHeaderView extends LinearLayout {
}
private void displayVerificationResult() {
OpenPgpSignatureResult signatureResult = cryptoAnnotation.getSignatureResult();
OpenPgpSignatureResult signatureResult = cryptoAnnotation.getOpenPgpSignatureResult();
switch (signatureResult.getResult()) {
case OpenPgpSignatureResult.RESULT_NO_SIGNATURE: {
@ -239,11 +239,11 @@ public class OpenPgpHeaderView extends LinearLayout {
}
private boolean isSignatureButtonUsed() {
return cryptoAnnotation.getPendingIntent() != null;
return cryptoAnnotation.getOpenPgpPendingIntent() != null;
}
private void setSignatureButtonClickListener() {
final PendingIntent pendingIntent = cryptoAnnotation.getPendingIntent();
final PendingIntent pendingIntent = cryptoAnnotation.getOpenPgpPendingIntent();
resultSignatureButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
@ -287,7 +287,7 @@ public class OpenPgpHeaderView extends LinearLayout {
setSignatureImageAndTextColor(CryptoState.UNKNOWN_KEY);
resultSignatureText.setText(R.string.openpgp_result_signature_missing_key);
setUserId(cryptoAnnotation.getSignatureResult());
setUserId(cryptoAnnotation.getOpenPgpSignatureResult());
showSignatureButtonWithTextIfNecessary(R.string.openpgp_result_action_lookup);
showSignatureLayout();
}
@ -321,7 +321,7 @@ public class OpenPgpHeaderView extends LinearLayout {
}
private void displayUserIdAndSignatureButton() {
setUserId(cryptoAnnotation.getSignatureResult());
setUserId(cryptoAnnotation.getOpenPgpSignatureResult());
showSignatureButtonWithTextIfNecessary(R.string.openpgp_result_action_show);
showSignatureLayout();
}

View file

@ -25,7 +25,7 @@ import com.fsck.k9.mail.Body;
import com.fsck.k9.mail.Multipart;
import com.fsck.k9.mail.Part;
import com.fsck.k9.mailstore.AttachmentViewInfo;
import com.fsck.k9.mailstore.LocalMessageExtractor;
import com.fsck.k9.message.extractors.AttachmentInfoExtractor;
/**
@ -101,7 +101,7 @@ public abstract class K9WebViewClient extends WebViewClient {
Context context = webView.getContext();
ContentResolver contentResolver = context.getContentResolver();
try {
AttachmentViewInfo attachmentInfo = LocalMessageExtractor.extractAttachmentInfo(context, part);
AttachmentViewInfo attachmentInfo = AttachmentInfoExtractor.extractAttachmentInfo(context, part);
String mimeType = attachmentInfo.mimeType;
InputStream inputStream = contentResolver.openInputStream(attachmentInfo.uri);

View file

@ -42,6 +42,7 @@ import com.fsck.k9.mail.Message;
import com.fsck.k9.mail.MessagingException;
import com.fsck.k9.mail.internet.MimeUtility;
public class MessageHeader extends LinearLayout implements OnClickListener, OnLongClickListener {
private Context mContext;
private TextView mFromView;