1
0
mirror of https://github.com/moparisthebest/k-9 synced 2024-11-27 03:32:16 -05:00

Add support for new decrypt/verify error conditions

We can decrypt or verify a message if it was only partly downloaded.
This commit is contained in:
cketti 2015-02-21 00:29:27 +01:00
parent c6abb50d10
commit 6f3f555986
6 changed files with 118 additions and 61 deletions

View File

@ -1,6 +1,5 @@
package com.fsck.k9.mailstore;
import android.app.PendingIntent;
import android.content.Context;
import android.net.Uri;
@ -22,8 +21,6 @@ import com.fsck.k9.mailstore.MessageViewInfo.MessageViewContainer;
import com.fsck.k9.provider.AttachmentProvider;
import com.fsck.k9.provider.K9FileProvider;
import com.fsck.k9.ui.crypto.MessageCryptoAnnotations;
import org.openintents.openpgp.OpenPgpError;
import org.openintents.openpgp.OpenPgpSignatureResult;
import java.io.File;
import java.util.ArrayList;
@ -448,18 +445,8 @@ public class LocalMessageExtractor {
attachments);
List<AttachmentViewInfo> attachmentInfos = extractAttachmentInfos(context, attachments);
MessageViewContainer messageViewContainer;
if (pgpAnnotation == NO_ANNOTATIONS) {
messageViewContainer = new MessageViewContainer(viewable.html, part, attachmentInfos);
} else {
OpenPgpSignatureResult pgpResult = pgpAnnotation.getSignatureResult();
OpenPgpError pgpError = pgpAnnotation.getError();
boolean wasEncrypted = pgpAnnotation.wasEncrypted();
PendingIntent pendingIntent = pgpAnnotation.getPendingIntent();
messageViewContainer = new MessageViewContainer(viewable.html, part, attachmentInfos, pgpResult,
pgpError, wasEncrypted, pendingIntent);
}
MessageViewContainer messageViewContainer =
new MessageViewContainer(viewable.html, part, attachmentInfos, pgpAnnotation);
containers.add(messageViewContainer);
}

View File

@ -0,0 +1,37 @@
package com.fsck.k9.mailstore;
import java.util.Stack;
import com.fsck.k9.mail.Body;
import com.fsck.k9.mail.BodyPart;
import com.fsck.k9.mail.Multipart;
import com.fsck.k9.mail.Part;
public class MessageHelper {
public static boolean isCompletePartAvailable(Part part) {
Stack<Part> partsToCheck = new Stack<Part>();
partsToCheck.push(part);
while (!partsToCheck.isEmpty()) {
Part currentPart = partsToCheck.pop();
Body body = currentPart.getBody();
boolean isBodyMissing = body == null;
if (isBodyMissing) {
return false;
}
if (body instanceof Multipart) {
Multipart multipart = (Multipart) body;
for (BodyPart bodyPart : multipart.getBodyParts()) {
partsToCheck.push(bodyPart);
}
}
}
return true;
}
}

View File

@ -3,12 +3,8 @@ package com.fsck.k9.mailstore;
import java.util.List;
import android.app.PendingIntent;
import com.fsck.k9.mail.Message;
import com.fsck.k9.mail.Part;
import org.openintents.openpgp.OpenPgpError;
import org.openintents.openpgp.OpenPgpSignatureResult;
public class MessageViewInfo {
@ -26,25 +22,15 @@ public class MessageViewInfo {
public final String text;
public final Part rootPart;
public final List<AttachmentViewInfo> attachments;
public final boolean encrypted;
public final OpenPgpSignatureResult signatureResult;
public final OpenPgpError pgpError;
public final PendingIntent pgpPendingIntent;
public final OpenPgpResultAnnotation cryptoAnnotation;
MessageViewContainer(String text, Part rootPart, List<AttachmentViewInfo> attachments) {
this(text, rootPart, attachments, null, null, false, null);
}
MessageViewContainer(String text, Part rootPart, List<AttachmentViewInfo> attachments,
OpenPgpSignatureResult signatureResult, OpenPgpError pgpError, boolean encrypted,
PendingIntent pgpPendingIntent) {
OpenPgpResultAnnotation cryptoAnnotation) {
this.text = text;
this.rootPart = rootPart;
this.attachments = attachments;
this.signatureResult = signatureResult;
this.pgpError = pgpError;
this.encrypted = encrypted;
this.pgpPendingIntent = pgpPendingIntent;
this.cryptoAnnotation = cryptoAnnotation;
}
}
}

View File

@ -8,10 +8,11 @@ import org.openintents.openpgp.OpenPgpError;
import org.openintents.openpgp.OpenPgpSignatureResult;
public class OpenPgpResultAnnotation {
public final class OpenPgpResultAnnotation {
private boolean wasEncrypted;
private OpenPgpSignatureResult signatureResult;
private OpenPgpError error;
private CryptoError errorType = CryptoError.NONE;
private PendingIntent pendingIntent;
private MimeBodyPart outputData;
@ -37,6 +38,15 @@ public class OpenPgpResultAnnotation {
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() {
@ -59,4 +69,11 @@ public class OpenPgpResultAnnotation {
this.wasEncrypted = wasEncrypted;
}
public static enum CryptoError {
NONE,
CRYPTO_API_RETURNED_ERROR,
SIGNED_BUT_INCOMPLETE,
ENCRYPTED_BUT_INCOMPLETE
}
}

View File

@ -34,7 +34,9 @@ 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.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 org.openintents.openpgp.OpenPgpError;
import org.openintents.openpgp.OpenPgpSignatureResult;
@ -101,21 +103,24 @@ public class MessageCryptoHelper {
}
Part part = partsToDecryptOrVerify.peekFirst();
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);
if (!MessageHelper.isCompletePartAvailable(part)) {
addErrorAnnotation(part);
} else {
partsToDecryptOrVerify.removeFirst();
decryptOrVerifyNextPart();
startDecryptingOrVerifyingPart(part);
}
}
private void addErrorAnnotation(Part part) {
OpenPgpResultAnnotation annotation = new OpenPgpResultAnnotation();
if (MessageDecryptVerifier.isPgpMimeSignedPart(part)) {
annotation.setErrorType(CryptoError.SIGNED_BUT_INCOMPLETE);
} else {
annotation.setErrorType(CryptoError.ENCRYPTED_BUT_INCOMPLETE);
}
messageAnnotations.put(part, annotation);
onCryptoFinished();
}
private void startDecryptingOrVerifyingPart(Part part) {
if (!isBoundToCryptoProviderService()) {
connectToCryptoProviderService();

View File

@ -37,10 +37,11 @@ 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.view.K9WebViewClient;
import com.fsck.k9.view.MessageHeader.OnLayoutChangedListener;
import com.fsck.k9.view.MessageWebView;
import org.openintents.openpgp.OpenPgpError;
public class MessageContainerView extends LinearLayout implements OnClickListener,
@ -374,15 +375,6 @@ public class MessageContainerView extends LinearLayout implements OnClickListene
WebViewClient webViewClient = K9WebViewClient.newInstance(messageViewContainer.rootPart);
mMessageContentView.setWebViewClient(webViewClient);
// Save the text so we can reset the WebView when the user clicks the "Show pictures" button
OpenPgpError error = messageViewContainer.pgpError;
if (error != null) {
// TODO make a nice view for this
mText = error.getMessage();
} else {
mText = messageViewContainer.text;
}
boolean hasAttachments = !messageViewContainer.attachments.isEmpty();
if (hasAttachments) {
renderAttachments(messageViewContainer);
@ -404,6 +396,7 @@ public class MessageContainerView extends LinearLayout implements OnClickListene
mSavedState = null;
}
mText = getTextToDisplay(messageViewContainer);
if (mText != null && lookForImages) {
if (Utility.hasExternalImages(mText) && !isShowingPictures()) {
if (automaticallyLoadPictures) {
@ -418,24 +411,56 @@ public class MessageContainerView extends LinearLayout implements OnClickListene
ViewStub openPgpHeaderStub = (ViewStub) findViewById(R.id.openpgp_header_stub);
OpenPgpHeaderView openPgpHeaderView = (OpenPgpHeaderView) openPgpHeaderStub.inflate();
openPgpHeaderView.setOpenPgpData(messageViewContainer.signatureResult, messageViewContainer.encrypted,
messageViewContainer.pgpPendingIntent);
OpenPgpResultAnnotation cryptoAnnotation = messageViewContainer.cryptoAnnotation;
if (cryptoAnnotation == null) {
openPgpHeaderView.setOpenPgpData(null, false, null);
} else {
openPgpHeaderView.setOpenPgpData(cryptoAnnotation.getSignatureResult(), cryptoAnnotation.wasEncrypted(),
cryptoAnnotation.getPendingIntent());
}
openPgpHeaderView.setCallback(openPgpHeaderViewCallback);
mSidebar.setVisibility(View.VISIBLE);
} else {
mSidebar.setVisibility(View.GONE);
}
String text;
if (mText != null) {
loadBodyFromText(mText);
text = mText;
} else {
showStatusMessage(getContext().getString(R.string.webview_empty_message));
text = wrapStatusMessage(getContext().getString(R.string.webview_empty_message));
}
loadBodyFromText(text);
}
public void showStatusMessage(String status) {
String text = "<div style=\"text-align:center; color: grey;\">" + status + "</div>";
loadBodyFromText(text);
private String getTextToDisplay(MessageViewContainer messageViewContainer) {
OpenPgpResultAnnotation cryptoAnnotation = messageViewContainer.cryptoAnnotation;
if (cryptoAnnotation == null) {
return messageViewContainer.text;
}
CryptoError errorType = cryptoAnnotation.getErrorType();
switch (errorType) {
case CRYPTO_API_RETURNED_ERROR: {
// TODO make a nice view for this
return wrapStatusMessage(cryptoAnnotation.getError().getMessage());
}
case ENCRYPTED_BUT_INCOMPLETE: {
//FIXME
return wrapStatusMessage("You need to download the complete message to be able to decrypt it.");
}
case NONE:
case SIGNED_BUT_INCOMPLETE: {
return messageViewContainer.text;
}
}
throw new IllegalStateException("Unknown error type: " + errorType);
}
public String wrapStatusMessage(String status) {
return "<div style=\"text-align:center; color: grey;\">" + status + "</div>";
}
private void loadBodyFromText(String emailText) {