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:
Vincent Breitmoser 2015-01-30 16:10:47 +01:00
parent 4bec165fdc
commit dc8fd39c7e
7 changed files with 147 additions and 94 deletions

View File

@ -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);
} }

View File

@ -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;

View File

@ -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 {

View File

@ -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;
}
} }

View File

@ -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;

View File

@ -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);
}
} }
} }

View File

@ -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