mirror of
https://github.com/moparisthebest/k-9
synced 2024-11-27 11:42:16 -05:00
move crypto data into an annotation structure, and fix pgp/inline
note that we currently lack proper confirmation about whether data was actually decrypted or not, so for now we always assume it wasn't
This commit is contained in:
parent
4bec165fdc
commit
dc8fd39c7e
@ -83,7 +83,7 @@ public class MessageDecryptVerifier {
|
|||||||
String mimeType = part.getMimeType();
|
String mimeType = part.getMimeType();
|
||||||
Body body = part.getBody();
|
Body body = part.getBody();
|
||||||
|
|
||||||
if (TEXT_PLAIN.equals(mimeType)) {
|
if (TEXT_PLAIN.equalsIgnoreCase(mimeType)) {
|
||||||
String text = MessageExtractor.getTextFromPart(part);
|
String text = MessageExtractor.getTextFromPart(part);
|
||||||
switch (OpenPgpUtils.parseMessage(text)) {
|
switch (OpenPgpUtils.parseMessage(text)) {
|
||||||
case OpenPgpUtils.PARSE_RESULT_MESSAGE:
|
case OpenPgpUtils.PARSE_RESULT_MESSAGE:
|
||||||
@ -120,6 +120,12 @@ public class MessageDecryptVerifier {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Note: This method should ONLY be used to differentiate parts
|
||||||
|
// already filtered with the methods above!
|
||||||
|
public static boolean isPgpInlinePart(Part part) {
|
||||||
|
return TEXT_PLAIN.equals(part.getMimeType());
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean isPgpMimePart(Part part) {
|
public static boolean isPgpMimePart(Part part) {
|
||||||
return isPgpMimeSignedPart(part) || isPgpMimeEncryptedPart(part);
|
return isPgpMimeSignedPart(part) || isPgpMimeEncryptedPart(part);
|
||||||
}
|
}
|
||||||
|
@ -35,15 +35,15 @@ import org.apache.james.mime4j.stream.Field;
|
|||||||
import org.apache.james.mime4j.stream.MimeConfig;
|
import org.apache.james.mime4j.stream.MimeConfig;
|
||||||
import org.apache.james.mime4j.util.MimeUtil;
|
import org.apache.james.mime4j.util.MimeUtil;
|
||||||
|
|
||||||
|
// TODO rename this class? this class doesn't really bear any 'decrypted' semantics anymore...
|
||||||
public class DecryptStreamParser {
|
public class DecryptStreamParser {
|
||||||
|
|
||||||
private static final String DECRYPTED_CACHE_DIRECTORY = "decrypted";
|
private static final String DECRYPTED_CACHE_DIRECTORY = "decrypted";
|
||||||
|
|
||||||
public static OpenPgpResultBodyPart parse(Context context, InputStream inputStream) throws MessagingException, IOException {
|
public static MimeBodyPart parse(Context context, InputStream inputStream) throws MessagingException, IOException {
|
||||||
File decryptedTempDirectory = getDecryptedTempDirectory(context);
|
File decryptedTempDirectory = getDecryptedTempDirectory(context);
|
||||||
|
|
||||||
OpenPgpResultBodyPart decryptedRootPart = new OpenPgpResultBodyPart(true);
|
MimeBodyPart decryptedRootPart = new MimeBodyPart();
|
||||||
|
|
||||||
MimeConfig parserConfig = new MimeConfig();
|
MimeConfig parserConfig = new MimeConfig();
|
||||||
parserConfig.setMaxHeaderLen(-1);
|
parserConfig.setMaxHeaderLen(-1);
|
||||||
@ -111,10 +111,10 @@ public class DecryptStreamParser {
|
|||||||
|
|
||||||
private static class PartBuilder implements ContentHandler {
|
private static class PartBuilder implements ContentHandler {
|
||||||
private final File decryptedTempDirectory;
|
private final File decryptedTempDirectory;
|
||||||
private final OpenPgpResultBodyPart decryptedRootPart;
|
private final MimeBodyPart decryptedRootPart;
|
||||||
private final Stack<Object> stack = new Stack<Object>();
|
private final Stack<Object> stack = new Stack<Object>();
|
||||||
|
|
||||||
public PartBuilder(File decryptedTempDirectory, OpenPgpResultBodyPart decryptedRootPart)
|
public PartBuilder(File decryptedTempDirectory, MimeBodyPart decryptedRootPart)
|
||||||
throws MessagingException {
|
throws MessagingException {
|
||||||
this.decryptedTempDirectory = decryptedTempDirectory;
|
this.decryptedTempDirectory = decryptedTempDirectory;
|
||||||
this.decryptedRootPart = decryptedRootPart;
|
this.decryptedRootPart = decryptedRootPart;
|
||||||
|
@ -6,7 +6,6 @@ import android.net.Uri;
|
|||||||
|
|
||||||
import com.fsck.k9.R;
|
import com.fsck.k9.R;
|
||||||
import com.fsck.k9.crypto.DecryptedTempFileBody;
|
import com.fsck.k9.crypto.DecryptedTempFileBody;
|
||||||
import com.fsck.k9.crypto.MessageDecryptVerifier;
|
|
||||||
import com.fsck.k9.mail.Address;
|
import com.fsck.k9.mail.Address;
|
||||||
import com.fsck.k9.mail.Body;
|
import com.fsck.k9.mail.Body;
|
||||||
import com.fsck.k9.mail.BodyPart;
|
import com.fsck.k9.mail.BodyPart;
|
||||||
@ -22,6 +21,7 @@ import com.fsck.k9.mail.internet.Viewable;
|
|||||||
import com.fsck.k9.mailstore.MessageViewInfo.MessageViewContainer;
|
import com.fsck.k9.mailstore.MessageViewInfo.MessageViewContainer;
|
||||||
import com.fsck.k9.provider.AttachmentProvider;
|
import com.fsck.k9.provider.AttachmentProvider;
|
||||||
import com.fsck.k9.provider.K9FileProvider;
|
import com.fsck.k9.provider.K9FileProvider;
|
||||||
|
import com.fsck.k9.ui.messageview.MessageCryptoHelper.MessageCryptoAnnotations;
|
||||||
import org.openintents.openpgp.OpenPgpError;
|
import org.openintents.openpgp.OpenPgpError;
|
||||||
import org.openintents.openpgp.OpenPgpSignatureResult;
|
import org.openintents.openpgp.OpenPgpSignatureResult;
|
||||||
|
|
||||||
@ -45,7 +45,7 @@ public class LocalMessageExtractor {
|
|||||||
private static final int FILENAME_PREFIX_LENGTH = FILENAME_PREFIX.length();
|
private static final int FILENAME_PREFIX_LENGTH = FILENAME_PREFIX.length();
|
||||||
private static final String FILENAME_SUFFIX = " ";
|
private static final String FILENAME_SUFFIX = " ";
|
||||||
private static final int FILENAME_SUFFIX_LENGTH = FILENAME_SUFFIX.length();
|
private static final int FILENAME_SUFFIX_LENGTH = FILENAME_SUFFIX.length();
|
||||||
private static final OpenPgpResultBodyPart NO_SIGNATURE_RESULT = null;
|
private static final OpenPgpResultAnnotation NO_ANNOTATIONS = null;
|
||||||
|
|
||||||
private LocalMessageExtractor() {}
|
private LocalMessageExtractor() {}
|
||||||
/**
|
/**
|
||||||
@ -424,14 +424,22 @@ public class LocalMessageExtractor {
|
|||||||
html.append("</td></tr>");
|
html.append("</td></tr>");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MessageViewInfo decodeMessageForView(Context context, Message message) throws MessagingException {
|
public static MessageViewInfo decodeMessageForView(Context context,
|
||||||
|
Message message, MessageCryptoAnnotations annotations) throws MessagingException {
|
||||||
|
|
||||||
// 1. break mime structure on encryption/signature boundaries
|
// 1. break mime structure on encryption/signature boundaries
|
||||||
List<Part> parts = getCryptPieces(message);
|
List<Part> parts = getCryptPieces(message, annotations);
|
||||||
|
|
||||||
// 2. extract viewables/attachments of parts
|
// 2. extract viewables/attachments of parts
|
||||||
ArrayList<MessageViewContainer> containers = new ArrayList<MessageViewContainer>();
|
ArrayList<MessageViewContainer> containers = new ArrayList<MessageViewContainer>();
|
||||||
for (Part part : parts) {
|
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<Part>();
|
ArrayList<Part> attachments = new ArrayList<Part>();
|
||||||
List<Viewable> viewables = MessageExtractor.getViewables(part, attachments);
|
List<Viewable> viewables = MessageExtractor.getViewables(part, attachments);
|
||||||
|
|
||||||
@ -440,12 +448,11 @@ public class LocalMessageExtractor {
|
|||||||
attachments);
|
attachments);
|
||||||
List<AttachmentViewInfo> attachmentInfos = extractAttachmentInfos(context, attachments);
|
List<AttachmentViewInfo> attachmentInfos = extractAttachmentInfos(context, attachments);
|
||||||
|
|
||||||
OpenPgpResultBodyPart resultBodyPart = getSignatureResultForPart(part);
|
if (pgpAnnotation != NO_ANNOTATIONS) {
|
||||||
if (resultBodyPart != NO_SIGNATURE_RESULT) {
|
OpenPgpSignatureResult pgpResult = pgpAnnotation.getSignatureResult();
|
||||||
OpenPgpSignatureResult pgpResult = resultBodyPart.getSignatureResult();
|
OpenPgpError pgpError = pgpAnnotation.getError();
|
||||||
OpenPgpError pgpError = resultBodyPart.getError();
|
boolean wasEncrypted = pgpAnnotation.wasEncrypted();
|
||||||
boolean wasEncrypted = resultBodyPart.wasEncrypted();
|
PendingIntent pendingIntent = pgpAnnotation.getPendingIntent();
|
||||||
PendingIntent pendingIntent = resultBodyPart.getPendingIntent();
|
|
||||||
|
|
||||||
containers.add(new MessageViewContainer(
|
containers.add(new MessageViewContainer(
|
||||||
viewable.html, attachmentInfos, pgpResult, pgpError, wasEncrypted, pendingIntent));
|
viewable.html, attachmentInfos, pgpResult, pgpError, wasEncrypted, pendingIntent));
|
||||||
@ -458,7 +465,7 @@ public class LocalMessageExtractor {
|
|||||||
return new MessageViewInfo(containers, message);
|
return new MessageViewInfo(containers, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<Part> getCryptPieces(Part part) throws MessagingException {
|
public static List<Part> getCryptPieces(Message message, MessageCryptoAnnotations annotations) throws MessagingException {
|
||||||
|
|
||||||
// TODO make sure this method does what it is supposed to
|
// 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
|
/* This method returns a list of mime parts which are to be parsed into
|
||||||
@ -470,14 +477,15 @@ public class LocalMessageExtractor {
|
|||||||
|
|
||||||
|
|
||||||
ArrayList<Part> parts = new ArrayList<Part>();
|
ArrayList<Part> parts = new ArrayList<Part>();
|
||||||
if (!getCryptSubPieces(part, parts)) {
|
if (!getCryptSubPieces(message, parts, annotations)) {
|
||||||
parts.add(part);
|
parts.add(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
return parts;
|
return parts;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean getCryptSubPieces(Part part, ArrayList<Part> parts) throws MessagingException {
|
public static boolean getCryptSubPieces(Part part, ArrayList<Part> parts,
|
||||||
|
MessageCryptoAnnotations annotations) throws MessagingException {
|
||||||
|
|
||||||
Body body = part.getBody();
|
Body body = part.getBody();
|
||||||
if (body instanceof Multipart) {
|
if (body instanceof Multipart) {
|
||||||
@ -485,46 +493,20 @@ public class LocalMessageExtractor {
|
|||||||
if ("multipart/mixed".equals(part.getMimeType())) {
|
if ("multipart/mixed".equals(part.getMimeType())) {
|
||||||
boolean foundSome = false;
|
boolean foundSome = false;
|
||||||
for (BodyPart sub : multi.getBodyParts()) {
|
for (BodyPart sub : multi.getBodyParts()) {
|
||||||
foundSome |= getCryptSubPieces(sub, parts);
|
foundSome |= getCryptSubPieces(sub, parts, annotations);
|
||||||
}
|
}
|
||||||
if (!foundSome) {
|
if (!foundSome) {
|
||||||
parts.add(part);
|
parts.add(part);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else if (MessageDecryptVerifier.isPgpMimeSignedPart(part)) {
|
} else if (annotations.has(part)) {
|
||||||
parts.add(part);
|
parts.add(part);
|
||||||
return true;
|
return true;
|
||||||
} else if (isPgpMimeDecryptedPart(part)) {
|
|
||||||
parts.add(multi.getBodyPart(2));
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isPgpMimeDecryptedPart (Part part) {
|
|
||||||
Body body = part.getBody();
|
|
||||||
return (body instanceof Multipart)
|
|
||||||
&& MessageDecryptVerifier.isPgpMimeEncryptedPart(part)
|
|
||||||
&& ((Multipart) part.getBody()).getCount() == 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static OpenPgpResultBodyPart getSignatureResultForPart(Part part) {
|
|
||||||
if (part instanceof OpenPgpResultBodyPart) {
|
|
||||||
OpenPgpResultBodyPart openPgpResultBodyPart = (OpenPgpResultBodyPart) part;
|
|
||||||
return openPgpResultBodyPart;
|
|
||||||
}
|
|
||||||
if (MessageDecryptVerifier.isPgpMimeSignedPart(part)) {
|
|
||||||
Multipart multi = (Multipart) part.getBody();
|
|
||||||
if (multi.getCount() == 3 && multi.getBodyPart(2) instanceof OpenPgpResultBodyPart) {
|
|
||||||
OpenPgpResultBodyPart openPgpResultBodyPart = (OpenPgpResultBodyPart) multi.getBodyPart(2);
|
|
||||||
return openPgpResultBodyPart;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NO_SIGNATURE_RESULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static List<AttachmentViewInfo> extractAttachmentInfos(Context context, List<Part> attachmentParts)
|
private static List<AttachmentViewInfo> extractAttachmentInfos(Context context, List<Part> attachmentParts)
|
||||||
throws MessagingException {
|
throws MessagingException {
|
||||||
|
|
||||||
|
@ -3,21 +3,17 @@ package com.fsck.k9.mailstore;
|
|||||||
|
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
|
|
||||||
import com.fsck.k9.mail.MessagingException;
|
|
||||||
import com.fsck.k9.mail.internet.MimeBodyPart;
|
import com.fsck.k9.mail.internet.MimeBodyPart;
|
||||||
import org.openintents.openpgp.OpenPgpError;
|
import org.openintents.openpgp.OpenPgpError;
|
||||||
import org.openintents.openpgp.OpenPgpSignatureResult;
|
import org.openintents.openpgp.OpenPgpSignatureResult;
|
||||||
|
|
||||||
|
|
||||||
public class OpenPgpResultAnnotation extends MimeBodyPart {
|
public class OpenPgpResultAnnotation {
|
||||||
private boolean wasEncrypted;
|
private boolean wasEncrypted;
|
||||||
private OpenPgpSignatureResult signatureResult;
|
private OpenPgpSignatureResult signatureResult;
|
||||||
private OpenPgpError error;
|
private OpenPgpError error;
|
||||||
private PendingIntent pendingIntent;
|
private PendingIntent pendingIntent;
|
||||||
|
private MimeBodyPart outputData;
|
||||||
public OpenPgpResultAnnotation(boolean wasEncrypted) throws MessagingException {
|
|
||||||
this.wasEncrypted = wasEncrypted;
|
|
||||||
}
|
|
||||||
|
|
||||||
public OpenPgpSignatureResult getSignatureResult() {
|
public OpenPgpSignatureResult getSignatureResult() {
|
||||||
return signatureResult;
|
return signatureResult;
|
||||||
@ -43,7 +39,24 @@ public class OpenPgpResultAnnotation extends MimeBodyPart {
|
|||||||
this.error = error;
|
this.error = error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasOutputData() {
|
||||||
|
return outputData != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOutputData(MimeBodyPart outputData) {
|
||||||
|
this.outputData = outputData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MimeBodyPart getOutputData() {
|
||||||
|
return outputData;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean wasEncrypted() {
|
public boolean wasEncrypted() {
|
||||||
return wasEncrypted;
|
return wasEncrypted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setWasEncrypted(boolean wasEncrypted) {
|
||||||
|
this.wasEncrypted = wasEncrypted;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -9,15 +9,18 @@ import com.fsck.k9.K9;
|
|||||||
import com.fsck.k9.mail.Message;
|
import com.fsck.k9.mail.Message;
|
||||||
import com.fsck.k9.mailstore.LocalMessageExtractor;
|
import com.fsck.k9.mailstore.LocalMessageExtractor;
|
||||||
import com.fsck.k9.mailstore.MessageViewInfo;
|
import com.fsck.k9.mailstore.MessageViewInfo;
|
||||||
|
import com.fsck.k9.ui.messageview.MessageCryptoHelper.MessageCryptoAnnotations;
|
||||||
|
|
||||||
|
|
||||||
public class DecodeMessageLoader extends AsyncTaskLoader<MessageViewInfo> {
|
public class DecodeMessageLoader extends AsyncTaskLoader<MessageViewInfo> {
|
||||||
private final Message message;
|
private final Message message;
|
||||||
private MessageViewInfo messageViewInfo;
|
private MessageViewInfo messageViewInfo;
|
||||||
|
private MessageCryptoAnnotations annotations;
|
||||||
|
|
||||||
public DecodeMessageLoader(Context context, Message message) {
|
public DecodeMessageLoader(Context context, Message message, MessageCryptoAnnotations annotations) {
|
||||||
super(context);
|
super(context);
|
||||||
this.message = message;
|
this.message = message;
|
||||||
|
this.annotations = annotations;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -40,7 +43,7 @@ public class DecodeMessageLoader extends AsyncTaskLoader<MessageViewInfo> {
|
|||||||
@Override
|
@Override
|
||||||
public MessageViewInfo loadInBackground() {
|
public MessageViewInfo loadInBackground() {
|
||||||
try {
|
try {
|
||||||
return LocalMessageExtractor.decodeMessageForView(getContext(), message);
|
return LocalMessageExtractor.decodeMessageForView(getContext(), message, annotations);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.e(K9.LOG_TAG, "Error while decoding message", e);
|
Log.e(K9.LOG_TAG, "Error while decoding message", e);
|
||||||
return null;
|
return null;
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
package com.fsck.k9.ui.messageview;
|
package com.fsck.k9.ui.messageview;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.PipedInputStream;
|
import java.io.PipedInputStream;
|
||||||
import java.io.PipedOutputStream;
|
import java.io.PipedOutputStream;
|
||||||
import java.util.ArrayDeque;
|
import java.util.ArrayDeque;
|
||||||
import java.util.Deque;
|
import java.util.Deque;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
|
||||||
@ -30,9 +32,11 @@ import com.fsck.k9.mail.MessagingException;
|
|||||||
import com.fsck.k9.mail.Multipart;
|
import com.fsck.k9.mail.Multipart;
|
||||||
import com.fsck.k9.mail.Part;
|
import com.fsck.k9.mail.Part;
|
||||||
import com.fsck.k9.mail.internet.MessageExtractor;
|
import com.fsck.k9.mail.internet.MessageExtractor;
|
||||||
|
import com.fsck.k9.mail.internet.MimeBodyPart;
|
||||||
|
import com.fsck.k9.mail.internet.TextBody;
|
||||||
import com.fsck.k9.mailstore.DecryptStreamParser;
|
import com.fsck.k9.mailstore.DecryptStreamParser;
|
||||||
import com.fsck.k9.mailstore.LocalMessage;
|
import com.fsck.k9.mailstore.LocalMessage;
|
||||||
import com.fsck.k9.mailstore.OpenPgpResultBodyPart;
|
import com.fsck.k9.mailstore.OpenPgpResultAnnotation;
|
||||||
import org.openintents.openpgp.IOpenPgpService;
|
import org.openintents.openpgp.IOpenPgpService;
|
||||||
import org.openintents.openpgp.OpenPgpError;
|
import org.openintents.openpgp.OpenPgpError;
|
||||||
import org.openintents.openpgp.OpenPgpSignatureResult;
|
import org.openintents.openpgp.OpenPgpSignatureResult;
|
||||||
@ -42,7 +46,7 @@ import org.openintents.openpgp.util.OpenPgpServiceConnection;
|
|||||||
import org.openintents.openpgp.util.OpenPgpServiceConnection.OnBound;
|
import org.openintents.openpgp.util.OpenPgpServiceConnection.OnBound;
|
||||||
|
|
||||||
|
|
||||||
class MessageCryptoHelper {
|
public class MessageCryptoHelper {
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private final MessageViewFragment fragment;
|
private final MessageViewFragment fragment;
|
||||||
@ -54,12 +58,16 @@ class MessageCryptoHelper {
|
|||||||
private Part currentlyDecrypringOrVerifyingPart;
|
private Part currentlyDecrypringOrVerifyingPart;
|
||||||
private Intent currentCryptoResult;
|
private Intent currentCryptoResult;
|
||||||
|
|
||||||
|
private MessageCryptoAnnotations messageAnnotations;
|
||||||
|
|
||||||
private static final int INVALID_OPENPGP_RESULT_CODE = -1;
|
private static final int INVALID_OPENPGP_RESULT_CODE = -1;
|
||||||
|
|
||||||
public MessageCryptoHelper(Context context, MessageViewFragment fragment, Account account) {
|
public MessageCryptoHelper(Context context, MessageViewFragment fragment, Account account) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.fragment = fragment;
|
this.fragment = fragment;
|
||||||
this.account = account;
|
this.account = account;
|
||||||
|
|
||||||
|
this.messageAnnotations = new MessageCryptoAnnotations();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void decryptOrVerifyMessagePartsIfNecessary(LocalMessage message) {
|
public void decryptOrVerifyMessagePartsIfNecessary(LocalMessage message) {
|
||||||
@ -149,6 +157,8 @@ class MessageCryptoHelper {
|
|||||||
try {
|
try {
|
||||||
if (MessageDecryptVerifier.isPgpMimeSignedPart(currentlyDecrypringOrVerifyingPart)) {
|
if (MessageDecryptVerifier.isPgpMimeSignedPart(currentlyDecrypringOrVerifyingPart)) {
|
||||||
callAsyncDetachedVerify(intent);
|
callAsyncDetachedVerify(intent);
|
||||||
|
} else if (MessageDecryptVerifier.isPgpInlinePart(currentlyDecrypringOrVerifyingPart)) {
|
||||||
|
callAsyncInlineOperation(intent);
|
||||||
} else {
|
} else {
|
||||||
callAsyncDecrypt(intent);
|
callAsyncDecrypt(intent);
|
||||||
}
|
}
|
||||||
@ -159,6 +169,29 @@ class MessageCryptoHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void callAsyncInlineOperation(Intent intent) throws IOException {
|
||||||
|
final CountDownLatch latch = new CountDownLatch(1);
|
||||||
|
PipedInputStream pipedInputStream = getPipedInputStreamForEncryptedOrInlineData();
|
||||||
|
final ByteArrayOutputStream decryptedOutputStream = new ByteArrayOutputStream();
|
||||||
|
|
||||||
|
openPgpApi.executeApiAsync(intent, pipedInputStream, decryptedOutputStream, new IOpenPgpCallback() {
|
||||||
|
@Override
|
||||||
|
public void onReturn(Intent result) {
|
||||||
|
currentCryptoResult = result;
|
||||||
|
|
||||||
|
MimeBodyPart decryptedPart = null;
|
||||||
|
try {
|
||||||
|
TextBody body = new TextBody(new String(decryptedOutputStream.toByteArray()));
|
||||||
|
decryptedPart = new MimeBodyPart(body, "text/plain");
|
||||||
|
} catch (MessagingException e) {
|
||||||
|
Log.e(K9.LOG_TAG, "MessagingException", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
onCryptoConverge(decryptedPart);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private void callAsyncDecrypt(Intent intent) throws IOException {
|
private void callAsyncDecrypt(Intent intent) throws IOException {
|
||||||
final CountDownLatch latch = new CountDownLatch(1);
|
final CountDownLatch latch = new CountDownLatch(1);
|
||||||
PipedInputStream pipedInputStream = getPipedInputStreamForEncryptedOrInlineData();
|
PipedInputStream pipedInputStream = getPipedInputStreamForEncryptedOrInlineData();
|
||||||
@ -223,15 +256,17 @@ class MessageCryptoHelper {
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
if (currentlyDecrypringOrVerifyingPart instanceof Multipart) {
|
if (MessageDecryptVerifier.isPgpMimePart(currentlyDecrypringOrVerifyingPart)) {
|
||||||
Multipart multipartEncryptedMultipart =
|
Multipart multipartEncryptedMultipart =
|
||||||
(Multipart) currentlyDecrypringOrVerifyingPart.getBody();
|
(Multipart) currentlyDecrypringOrVerifyingPart.getBody();
|
||||||
BodyPart encryptionPayloadPart = multipartEncryptedMultipart.getBodyPart(1);
|
BodyPart encryptionPayloadPart = multipartEncryptedMultipart.getBodyPart(1);
|
||||||
Body encryptionPayloadBody = encryptionPayloadPart.getBody();
|
Body encryptionPayloadBody = encryptionPayloadPart.getBody();
|
||||||
encryptionPayloadBody.writeTo(out);
|
encryptionPayloadBody.writeTo(out);
|
||||||
} else {
|
} else if (MessageDecryptVerifier.isPgpInlinePart(currentlyDecrypringOrVerifyingPart)) {
|
||||||
String text = MessageExtractor.getTextFromPart(currentlyDecrypringOrVerifyingPart);
|
String text = MessageExtractor.getTextFromPart(currentlyDecrypringOrVerifyingPart);
|
||||||
out.write(text.getBytes());
|
out.write(text.getBytes());
|
||||||
|
} else {
|
||||||
|
Log.wtf(K9.LOG_TAG, "No suitable data to stream found!");
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.e(K9.LOG_TAG, "Exception while writing message to crypto provider", e);
|
Log.e(K9.LOG_TAG, "Exception while writing message to crypto provider", e);
|
||||||
@ -251,16 +286,16 @@ class MessageCryptoHelper {
|
|||||||
private PipedOutputStream getPipedOutputStreamForDecryptedData(final CountDownLatch latch) throws IOException {
|
private PipedOutputStream getPipedOutputStreamForDecryptedData(final CountDownLatch latch) throws IOException {
|
||||||
PipedOutputStream decryptedOutputStream = new PipedOutputStream();
|
PipedOutputStream decryptedOutputStream = new PipedOutputStream();
|
||||||
final PipedInputStream decryptedInputStream = new PipedInputStream(decryptedOutputStream);
|
final PipedInputStream decryptedInputStream = new PipedInputStream(decryptedOutputStream);
|
||||||
new AsyncTask<Void, Void, OpenPgpResultBodyPart>() {
|
new AsyncTask<Void, Void, MimeBodyPart>() {
|
||||||
@Override
|
@Override
|
||||||
protected OpenPgpResultBodyPart doInBackground(Void... params) {
|
protected MimeBodyPart doInBackground(Void... params) {
|
||||||
OpenPgpResultBodyPart decryptedPart = null;
|
MimeBodyPart decryptedPart = null;
|
||||||
try {
|
try {
|
||||||
decryptedPart = DecryptStreamParser.parse(context, decryptedInputStream);
|
decryptedPart = DecryptStreamParser.parse(context, decryptedInputStream);
|
||||||
|
|
||||||
latch.await();
|
latch.await();
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
Log.e(K9.LOG_TAG, "we were interrupted while waiting for onReturn!", e);
|
Log.w(K9.LOG_TAG, "we were interrupted while waiting for onReturn!", e);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.e(K9.LOG_TAG, "Something went wrong while parsing the decrypted MIME part", e);
|
Log.e(K9.LOG_TAG, "Something went wrong while parsing the decrypted MIME part", e);
|
||||||
//TODO: pass error to main thread and display error message to user
|
//TODO: pass error to main thread and display error message to user
|
||||||
@ -269,14 +304,14 @@ class MessageCryptoHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPostExecute(OpenPgpResultBodyPart decryptedPart) {
|
protected void onPostExecute(MimeBodyPart decryptedPart) {
|
||||||
onCryptoConverge(decryptedPart);
|
onCryptoConverge(decryptedPart);
|
||||||
}
|
}
|
||||||
}.execute();
|
}.execute();
|
||||||
return decryptedOutputStream;
|
return decryptedOutputStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onCryptoConverge(OpenPgpResultBodyPart openPgpResultBodyPart) {
|
private void onCryptoConverge(MimeBodyPart outputPart) {
|
||||||
try {
|
try {
|
||||||
if (currentCryptoResult == null) {
|
if (currentCryptoResult == null) {
|
||||||
Log.e(K9.LOG_TAG, "Internal error: we should have a result here!");
|
Log.e(K9.LOG_TAG, "Internal error: we should have a result here!");
|
||||||
@ -318,24 +353,26 @@ class MessageCryptoHelper {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OpenPgpApi.RESULT_CODE_SUCCESS: {
|
case OpenPgpApi.RESULT_CODE_SUCCESS: {
|
||||||
if (openPgpResultBodyPart == null) {
|
OpenPgpResultAnnotation resultAnnotation = new OpenPgpResultAnnotation();
|
||||||
openPgpResultBodyPart = new OpenPgpResultBodyPart(false);
|
|
||||||
}
|
resultAnnotation.setOutputData(outputPart);
|
||||||
|
|
||||||
|
// TODO if the data /was/ encrypted, we should set it here!
|
||||||
|
// this is not easy to determine for inline data though
|
||||||
|
resultAnnotation.setWasEncrypted(false);
|
||||||
|
|
||||||
OpenPgpSignatureResult signatureResult =
|
OpenPgpSignatureResult signatureResult =
|
||||||
currentCryptoResult.getParcelableExtra(OpenPgpApi.RESULT_SIGNATURE);
|
currentCryptoResult.getParcelableExtra(OpenPgpApi.RESULT_SIGNATURE);
|
||||||
openPgpResultBodyPart.setSignatureResult(signatureResult);
|
resultAnnotation.setSignatureResult(signatureResult);
|
||||||
|
|
||||||
PendingIntent pendingIntent =
|
PendingIntent pendingIntent =
|
||||||
currentCryptoResult.getParcelableExtra(OpenPgpApi.RESULT_INTENT);
|
currentCryptoResult.getParcelableExtra(OpenPgpApi.RESULT_INTENT);
|
||||||
openPgpResultBodyPart.setPendingIntent(pendingIntent);
|
resultAnnotation.setPendingIntent(pendingIntent);
|
||||||
|
|
||||||
onCryptoSuccess(openPgpResultBodyPart);
|
onCryptoSuccess(resultAnnotation);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (MessagingException e) {
|
|
||||||
// catching the empty OpenPgpResultBodyPart constructor above - this can't actually happen
|
|
||||||
Log.e(K9.LOG_TAG, "This shouldn't happen", e);
|
|
||||||
} finally {
|
} finally {
|
||||||
currentCryptoResult = null;
|
currentCryptoResult = null;
|
||||||
}
|
}
|
||||||
@ -350,28 +387,19 @@ class MessageCryptoHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onCryptoSuccess(OpenPgpResultBodyPart decryptedPart) {
|
private void onCryptoSuccess(OpenPgpResultAnnotation resultAnnotation) {
|
||||||
addOpenPgpResultPartToMessage(decryptedPart);
|
addOpenPgpResultPartToMessage(resultAnnotation);
|
||||||
onCryptoFinished();
|
onCryptoFinished();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addOpenPgpResultPartToMessage(OpenPgpResultBodyPart decryptedPart) {
|
private void addOpenPgpResultPartToMessage(OpenPgpResultAnnotation resultAnnotation) {
|
||||||
if ( ! (currentlyDecrypringOrVerifyingPart.getBody() instanceof Multipart)) {
|
messageAnnotations.put(currentlyDecrypringOrVerifyingPart, resultAnnotation);
|
||||||
// TODO this is a text/plain part - care about this later!
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Multipart multipart = (Multipart) currentlyDecrypringOrVerifyingPart.getBody();
|
|
||||||
multipart.addBodyPart(decryptedPart);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onCryptoFailed(OpenPgpError error) {
|
private void onCryptoFailed(OpenPgpError error) {
|
||||||
try {
|
OpenPgpResultAnnotation errorPart = new OpenPgpResultAnnotation();
|
||||||
OpenPgpResultBodyPart errorPart = new OpenPgpResultBodyPart(false);
|
errorPart.setError(error);
|
||||||
errorPart.setError(error);
|
addOpenPgpResultPartToMessage(errorPart);
|
||||||
addOpenPgpResultPartToMessage(errorPart);
|
|
||||||
} catch (MessagingException e) {
|
|
||||||
Log.e(K9.LOG_TAG, "This shouldn't happen", e);
|
|
||||||
}
|
|
||||||
onCryptoFinished();
|
onCryptoFinished();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -381,7 +409,25 @@ class MessageCryptoHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void returnResultToFragment() {
|
private void returnResultToFragment() {
|
||||||
fragment.startExtractingTextAndAttachments(message);
|
fragment.startExtractingTextAndAttachments(messageAnnotations);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class MessageCryptoAnnotations {
|
||||||
|
|
||||||
|
private HashMap<Part,OpenPgpResultAnnotation> annotations = new HashMap<Part,OpenPgpResultAnnotation>();
|
||||||
|
|
||||||
|
private void put(Part part, OpenPgpResultAnnotation annotation) {
|
||||||
|
annotations.put(part, annotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
public OpenPgpResultAnnotation get(Part part) {
|
||||||
|
return annotations.get(part);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean has(Part part) {
|
||||||
|
return annotations.containsKey(part);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -48,6 +48,7 @@ import com.fsck.k9.mailstore.LocalMessage;
|
|||||||
import com.fsck.k9.mailstore.MessageViewInfo;
|
import com.fsck.k9.mailstore.MessageViewInfo;
|
||||||
import com.fsck.k9.ui.message.DecodeMessageLoader;
|
import com.fsck.k9.ui.message.DecodeMessageLoader;
|
||||||
import com.fsck.k9.ui.message.LocalMessageLoader;
|
import com.fsck.k9.ui.message.LocalMessageLoader;
|
||||||
|
import com.fsck.k9.ui.messageview.MessageCryptoHelper.MessageCryptoAnnotations;
|
||||||
import com.fsck.k9.view.MessageHeader;
|
import com.fsck.k9.view.MessageHeader;
|
||||||
|
|
||||||
public class MessageViewFragment extends Fragment implements ConfirmationDialogFragmentListener,
|
public class MessageViewFragment extends Fragment implements ConfirmationDialogFragmentListener,
|
||||||
@ -80,6 +81,7 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF
|
|||||||
private Account mAccount;
|
private Account mAccount;
|
||||||
private MessageReference mMessageReference;
|
private MessageReference mMessageReference;
|
||||||
private LocalMessage mMessage;
|
private LocalMessage mMessage;
|
||||||
|
private MessageCryptoAnnotations messageAnnotations;
|
||||||
private MessagingController mController;
|
private MessagingController mController;
|
||||||
private LayoutInflater mLayoutInflater;
|
private LayoutInflater mLayoutInflater;
|
||||||
private Handler handler = new Handler();
|
private Handler handler = new Handler();
|
||||||
@ -258,7 +260,8 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF
|
|||||||
Toast.makeText(mContext, errorMessage, Toast.LENGTH_LONG).show();
|
Toast.makeText(mContext, errorMessage, Toast.LENGTH_LONG).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
void startExtractingTextAndAttachments(LocalMessage message) {
|
void startExtractingTextAndAttachments(MessageCryptoAnnotations annotations) {
|
||||||
|
this.messageAnnotations = annotations;
|
||||||
getLoaderManager().initLoader(DECODE_MESSAGE_LOADER_ID, null, decodeMessageLoaderCallback);
|
getLoaderManager().initLoader(DECODE_MESSAGE_LOADER_ID, null, decodeMessageLoaderCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -742,7 +745,7 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF
|
|||||||
@Override
|
@Override
|
||||||
public Loader<MessageViewInfo> onCreateLoader(int id, Bundle args) {
|
public Loader<MessageViewInfo> onCreateLoader(int id, Bundle args) {
|
||||||
setProgress(true);
|
setProgress(true);
|
||||||
return new DecodeMessageLoader(mContext, mMessage);
|
return new DecodeMessageLoader(mContext, mMessage, messageAnnotations);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
Loading…
Reference in New Issue
Block a user