From 4bec165fdcdbc42f58a88cc4dfaa60303b8253f8 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Fri, 30 Jan 2015 14:51:44 +0100 Subject: [PATCH] preliminary support for pgp/inline --- .../k9/crypto/MessageDecryptVerifier.java | 33 +++++++++++++++ ...Part.java => OpenPgpResultAnnotation.java} | 4 +- .../ui/messageview/MessageCryptoHelper.java | 41 +++++++++++++------ 3 files changed, 63 insertions(+), 15 deletions(-) rename k9mail/src/main/java/com/fsck/k9/mailstore/{OpenPgpResultBodyPart.java => OpenPgpResultAnnotation.java} (88%) diff --git a/k9mail/src/main/java/com/fsck/k9/crypto/MessageDecryptVerifier.java b/k9mail/src/main/java/com/fsck/k9/crypto/MessageDecryptVerifier.java index 8dfb86966..1a331c539 100644 --- a/k9mail/src/main/java/com/fsck/k9/crypto/MessageDecryptVerifier.java +++ b/k9mail/src/main/java/com/fsck/k9/crypto/MessageDecryptVerifier.java @@ -12,6 +12,8 @@ import com.fsck.k9.mail.BodyPart; import com.fsck.k9.mail.MessagingException; import com.fsck.k9.mail.Multipart; import com.fsck.k9.mail.Part; +import com.fsck.k9.mail.internet.MessageExtractor; +import org.openintents.openpgp.util.OpenPgpUtils; public class MessageDecryptVerifier { @@ -20,6 +22,8 @@ public class MessageDecryptVerifier { private static final String PROTOCOL_PARAMETER = "protocol"; private static final String APPLICATION_PGP_ENCRYPTED = "application/pgp-encrypted"; private static final String APPLICATION_PGP_SIGNATURE = "application/pgp-signature"; + private static final String TEXT_PLAIN = "text/plain"; + public static List findEncryptedParts(Part startPart) { List encryptedParts = new ArrayList(); @@ -69,6 +73,35 @@ public class MessageDecryptVerifier { return signedParts; } + public static List findPgpInlineParts(Part startPart) { + List inlineParts = new ArrayList(); + Stack partsToCheck = new Stack(); + partsToCheck.push(startPart); + + while (!partsToCheck.isEmpty()) { + Part part = partsToCheck.pop(); + String mimeType = part.getMimeType(); + Body body = part.getBody(); + + if (TEXT_PLAIN.equals(mimeType)) { + String text = MessageExtractor.getTextFromPart(part); + switch (OpenPgpUtils.parseMessage(text)) { + case OpenPgpUtils.PARSE_RESULT_MESSAGE: + case OpenPgpUtils.PARSE_RESULT_SIGNED_MESSAGE: + inlineParts.add(part); + } + } else if (body instanceof Multipart) { + Multipart multipart = (Multipart) body; + for (int i = multipart.getCount() - 1; i >= 0; i--) { + BodyPart bodyPart = multipart.getBodyPart(i); + partsToCheck.push(bodyPart); + } + } + } + + return inlineParts; + } + public static byte[] getSignatureData(Part part) throws IOException, MessagingException { if (MULTIPART_SIGNED.equals(part.getMimeType())) { diff --git a/k9mail/src/main/java/com/fsck/k9/mailstore/OpenPgpResultBodyPart.java b/k9mail/src/main/java/com/fsck/k9/mailstore/OpenPgpResultAnnotation.java similarity index 88% rename from k9mail/src/main/java/com/fsck/k9/mailstore/OpenPgpResultBodyPart.java rename to k9mail/src/main/java/com/fsck/k9/mailstore/OpenPgpResultAnnotation.java index 47e2f10fe..bcd60b711 100644 --- a/k9mail/src/main/java/com/fsck/k9/mailstore/OpenPgpResultBodyPart.java +++ b/k9mail/src/main/java/com/fsck/k9/mailstore/OpenPgpResultAnnotation.java @@ -9,13 +9,13 @@ import org.openintents.openpgp.OpenPgpError; import org.openintents.openpgp.OpenPgpSignatureResult; -public class OpenPgpResultBodyPart extends MimeBodyPart { +public class OpenPgpResultAnnotation extends MimeBodyPart { private boolean wasEncrypted; private OpenPgpSignatureResult signatureResult; private OpenPgpError error; private PendingIntent pendingIntent; - public OpenPgpResultBodyPart(boolean wasEncrypted) throws MessagingException { + public OpenPgpResultAnnotation(boolean wasEncrypted) throws MessagingException { this.wasEncrypted = wasEncrypted; } diff --git a/k9mail/src/main/java/com/fsck/k9/ui/messageview/MessageCryptoHelper.java b/k9mail/src/main/java/com/fsck/k9/ui/messageview/MessageCryptoHelper.java index 9e5837a57..e1865fbc7 100644 --- a/k9mail/src/main/java/com/fsck/k9/ui/messageview/MessageCryptoHelper.java +++ b/k9mail/src/main/java/com/fsck/k9/ui/messageview/MessageCryptoHelper.java @@ -29,6 +29,7 @@ import com.fsck.k9.mail.BodyPart; import com.fsck.k9.mail.MessagingException; import com.fsck.k9.mail.Multipart; import com.fsck.k9.mail.Part; +import com.fsck.k9.mail.internet.MessageExtractor; import com.fsck.k9.mailstore.DecryptStreamParser; import com.fsck.k9.mailstore.LocalMessage; import com.fsck.k9.mailstore.OpenPgpResultBodyPart; @@ -66,10 +67,12 @@ class MessageCryptoHelper { List encryptedParts = MessageDecryptVerifier.findEncryptedParts(message); List signedParts = MessageDecryptVerifier.findSignedParts(message); - if (!encryptedParts.isEmpty() || !signedParts.isEmpty()) { + List inlineParts = MessageDecryptVerifier.findPgpInlineParts(message); + if (!encryptedParts.isEmpty() || !signedParts.isEmpty() || !inlineParts.isEmpty()) { partsToDecryptOrVerify = new ArrayDeque(); partsToDecryptOrVerify.addAll(encryptedParts); partsToDecryptOrVerify.addAll(signedParts); + partsToDecryptOrVerify.addAll(inlineParts); decryptOrVerifyNextPartOrStartExtractingTextAndAttachments(); } else { returnResultToFragment(); @@ -80,7 +83,14 @@ class MessageCryptoHelper { if (!partsToDecryptOrVerify.isEmpty()) { Part part = partsToDecryptOrVerify.peekFirst(); - if (MessageDecryptVerifier.isPgpMimePart(part)) { + if ("text/plain".equalsIgnoreCase(part.getMimeType())) { + startDecryptingOrVerifyingPart(part); + } else if (MessageDecryptVerifier.isPgpMimePart(part)) { + Multipart multipart = (Multipart) part.getBody(); + if (multipart == null) { + throw new RuntimeException("Downloading missing parts before decryption isn't supported yet"); + } + startDecryptingOrVerifyingPart(part); } else { partsToDecryptOrVerify.removeFirst(); @@ -95,11 +105,6 @@ class MessageCryptoHelper { } private void startDecryptingOrVerifyingPart(Part part) { - Multipart multipart = (Multipart) part.getBody(); - if (multipart == null) { - throw new RuntimeException("Downloading missing parts before decryption isn't supported yet"); - } - if (!isBoundToCryptoProviderService()) { connectToCryptoProviderService(); } else { @@ -156,7 +161,7 @@ class MessageCryptoHelper { private void callAsyncDecrypt(Intent intent) throws IOException { final CountDownLatch latch = new CountDownLatch(1); - PipedInputStream pipedInputStream = getPipedInputStreamForEncryptedData(); + PipedInputStream pipedInputStream = getPipedInputStreamForEncryptedOrInlineData(); PipedOutputStream decryptedOutputStream = getPipedOutputStreamForDecryptedData(latch); openPgpApi.executeApiAsync(intent, pipedInputStream, decryptedOutputStream, new IOpenPgpCallback() { @@ -210,7 +215,7 @@ class MessageCryptoHelper { return pipedInputStream; } - private PipedInputStream getPipedInputStreamForEncryptedData() throws IOException { + private PipedInputStream getPipedInputStreamForEncryptedOrInlineData() throws IOException { PipedInputStream pipedInputStream = new PipedInputStream(); final PipedOutputStream out = new PipedOutputStream(pipedInputStream); @@ -218,10 +223,16 @@ class MessageCryptoHelper { @Override public void run() { try { - Multipart multipartEncryptedMultipart = (Multipart) currentlyDecrypringOrVerifyingPart.getBody(); - BodyPart encryptionPayloadPart = multipartEncryptedMultipart.getBodyPart(1); - Body encryptionPayloadBody = encryptionPayloadPart.getBody(); - encryptionPayloadBody.writeTo(out); + if (currentlyDecrypringOrVerifyingPart instanceof Multipart) { + Multipart multipartEncryptedMultipart = + (Multipart) currentlyDecrypringOrVerifyingPart.getBody(); + BodyPart encryptionPayloadPart = multipartEncryptedMultipart.getBodyPart(1); + Body encryptionPayloadBody = encryptionPayloadPart.getBody(); + encryptionPayloadBody.writeTo(out); + } else { + String text = MessageExtractor.getTextFromPart(currentlyDecrypringOrVerifyingPart); + out.write(text.getBytes()); + } } catch (Exception e) { Log.e(K9.LOG_TAG, "Exception while writing message to crypto provider", e); } finally { @@ -345,6 +356,10 @@ class MessageCryptoHelper { } private void addOpenPgpResultPartToMessage(OpenPgpResultBodyPart decryptedPart) { + if ( ! (currentlyDecrypringOrVerifyingPart.getBody() instanceof Multipart)) { + // TODO this is a text/plain part - care about this later! + return; + } Multipart multipart = (Multipart) currentlyDecrypringOrVerifyingPart.getBody(); multipart.addBodyPart(decryptedPart); }