1
0
mirror of https://github.com/moparisthebest/k-9 synced 2024-11-30 13:12:25 -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; package com.fsck.k9.mailstore;
import android.app.PendingIntent;
import android.content.Context; import android.content.Context;
import android.net.Uri; 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.AttachmentProvider;
import com.fsck.k9.provider.K9FileProvider; import com.fsck.k9.provider.K9FileProvider;
import com.fsck.k9.ui.crypto.MessageCryptoAnnotations; import com.fsck.k9.ui.crypto.MessageCryptoAnnotations;
import org.openintents.openpgp.OpenPgpError;
import org.openintents.openpgp.OpenPgpSignatureResult;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
@ -448,18 +445,8 @@ public class LocalMessageExtractor {
attachments); attachments);
List<AttachmentViewInfo> attachmentInfos = extractAttachmentInfos(context, attachments); List<AttachmentViewInfo> attachmentInfos = extractAttachmentInfos(context, attachments);
MessageViewContainer messageViewContainer; MessageViewContainer messageViewContainer =
if (pgpAnnotation == NO_ANNOTATIONS) { new MessageViewContainer(viewable.html, part, attachmentInfos, pgpAnnotation);
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);
}
containers.add(messageViewContainer); 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 java.util.List;
import android.app.PendingIntent;
import com.fsck.k9.mail.Message; import com.fsck.k9.mail.Message;
import com.fsck.k9.mail.Part; import com.fsck.k9.mail.Part;
import org.openintents.openpgp.OpenPgpError;
import org.openintents.openpgp.OpenPgpSignatureResult;
public class MessageViewInfo { public class MessageViewInfo {
@ -26,25 +22,15 @@ public class MessageViewInfo {
public final String text; public final String text;
public final Part rootPart; public final Part rootPart;
public final List<AttachmentViewInfo> attachments; public final List<AttachmentViewInfo> attachments;
public final boolean encrypted; public final OpenPgpResultAnnotation cryptoAnnotation;
public final OpenPgpSignatureResult signatureResult;
public final OpenPgpError pgpError;
public final PendingIntent pgpPendingIntent;
MessageViewContainer(String text, Part rootPart, List<AttachmentViewInfo> attachments) {
this(text, rootPart, attachments, null, null, false, null);
}
MessageViewContainer(String text, Part rootPart, List<AttachmentViewInfo> attachments, MessageViewContainer(String text, Part rootPart, List<AttachmentViewInfo> attachments,
OpenPgpSignatureResult signatureResult, OpenPgpError pgpError, boolean encrypted, OpenPgpResultAnnotation cryptoAnnotation) {
PendingIntent pgpPendingIntent) {
this.text = text; this.text = text;
this.rootPart = rootPart; this.rootPart = rootPart;
this.attachments = attachments; this.attachments = attachments;
this.signatureResult = signatureResult; this.cryptoAnnotation = cryptoAnnotation;
this.pgpError = pgpError;
this.encrypted = encrypted;
this.pgpPendingIntent = pgpPendingIntent;
} }
} }
} }

View File

@ -8,10 +8,11 @@ import org.openintents.openpgp.OpenPgpError;
import org.openintents.openpgp.OpenPgpSignatureResult; import org.openintents.openpgp.OpenPgpSignatureResult;
public class OpenPgpResultAnnotation { public final class OpenPgpResultAnnotation {
private boolean wasEncrypted; private boolean wasEncrypted;
private OpenPgpSignatureResult signatureResult; private OpenPgpSignatureResult signatureResult;
private OpenPgpError error; private OpenPgpError error;
private CryptoError errorType = CryptoError.NONE;
private PendingIntent pendingIntent; private PendingIntent pendingIntent;
private MimeBodyPart outputData; private MimeBodyPart outputData;
@ -37,6 +38,15 @@ public class OpenPgpResultAnnotation {
public void setError(OpenPgpError error) { public void setError(OpenPgpError error) {
this.error = 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() { public boolean hasOutputData() {
@ -59,4 +69,11 @@ public class OpenPgpResultAnnotation {
this.wasEncrypted = wasEncrypted; 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.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.MessageHelper;
import com.fsck.k9.mailstore.OpenPgpResultAnnotation; import com.fsck.k9.mailstore.OpenPgpResultAnnotation;
import com.fsck.k9.mailstore.OpenPgpResultAnnotation.CryptoError;
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;
@ -101,19 +103,22 @@ public class MessageCryptoHelper {
} }
Part part = partsToDecryptOrVerify.peekFirst(); Part part = partsToDecryptOrVerify.peekFirst();
if ("text/plain".equalsIgnoreCase(part.getMimeType())) { if (!MessageHelper.isCompletePartAvailable(part)) {
addErrorAnnotation(part);
} else {
startDecryptingOrVerifyingPart(part); 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); private void addErrorAnnotation(Part part) {
OpenPgpResultAnnotation annotation = new OpenPgpResultAnnotation();
if (MessageDecryptVerifier.isPgpMimeSignedPart(part)) {
annotation.setErrorType(CryptoError.SIGNED_BUT_INCOMPLETE);
} else { } else {
partsToDecryptOrVerify.removeFirst(); annotation.setErrorType(CryptoError.ENCRYPTED_BUT_INCOMPLETE);
decryptOrVerifyNextPart();
} }
messageAnnotations.put(part, annotation);
onCryptoFinished();
} }
private void startDecryptingOrVerifyingPart(Part part) { private void startDecryptingOrVerifyingPart(Part part) {

View File

@ -37,10 +37,11 @@ import com.fsck.k9.mail.MessagingException;
import com.fsck.k9.mailstore.AttachmentViewInfo; import com.fsck.k9.mailstore.AttachmentViewInfo;
import com.fsck.k9.mailstore.MessageViewInfo.MessageViewContainer; 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.K9WebViewClient;
import com.fsck.k9.view.MessageHeader.OnLayoutChangedListener; import com.fsck.k9.view.MessageHeader.OnLayoutChangedListener;
import com.fsck.k9.view.MessageWebView; import com.fsck.k9.view.MessageWebView;
import org.openintents.openpgp.OpenPgpError;
public class MessageContainerView extends LinearLayout implements OnClickListener, public class MessageContainerView extends LinearLayout implements OnClickListener,
@ -374,15 +375,6 @@ public class MessageContainerView extends LinearLayout implements OnClickListene
WebViewClient webViewClient = K9WebViewClient.newInstance(messageViewContainer.rootPart); WebViewClient webViewClient = K9WebViewClient.newInstance(messageViewContainer.rootPart);
mMessageContentView.setWebViewClient(webViewClient); 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(); boolean hasAttachments = !messageViewContainer.attachments.isEmpty();
if (hasAttachments) { if (hasAttachments) {
renderAttachments(messageViewContainer); renderAttachments(messageViewContainer);
@ -404,6 +396,7 @@ public class MessageContainerView extends LinearLayout implements OnClickListene
mSavedState = null; mSavedState = null;
} }
mText = getTextToDisplay(messageViewContainer);
if (mText != null && lookForImages) { if (mText != null && lookForImages) {
if (Utility.hasExternalImages(mText) && !isShowingPictures()) { if (Utility.hasExternalImages(mText) && !isShowingPictures()) {
if (automaticallyLoadPictures) { if (automaticallyLoadPictures) {
@ -418,24 +411,56 @@ public class MessageContainerView extends LinearLayout implements OnClickListene
ViewStub openPgpHeaderStub = (ViewStub) findViewById(R.id.openpgp_header_stub); ViewStub openPgpHeaderStub = (ViewStub) findViewById(R.id.openpgp_header_stub);
OpenPgpHeaderView openPgpHeaderView = (OpenPgpHeaderView) openPgpHeaderStub.inflate(); OpenPgpHeaderView openPgpHeaderView = (OpenPgpHeaderView) openPgpHeaderStub.inflate();
openPgpHeaderView.setOpenPgpData(messageViewContainer.signatureResult, messageViewContainer.encrypted, OpenPgpResultAnnotation cryptoAnnotation = messageViewContainer.cryptoAnnotation;
messageViewContainer.pgpPendingIntent); if (cryptoAnnotation == null) {
openPgpHeaderView.setOpenPgpData(null, false, null);
} else {
openPgpHeaderView.setOpenPgpData(cryptoAnnotation.getSignatureResult(), cryptoAnnotation.wasEncrypted(),
cryptoAnnotation.getPendingIntent());
}
openPgpHeaderView.setCallback(openPgpHeaderViewCallback); openPgpHeaderView.setCallback(openPgpHeaderViewCallback);
mSidebar.setVisibility(View.VISIBLE); mSidebar.setVisibility(View.VISIBLE);
} else { } else {
mSidebar.setVisibility(View.GONE); mSidebar.setVisibility(View.GONE);
} }
String text;
if (mText != null) { if (mText != null) {
loadBodyFromText(mText); text = mText;
} else { } else {
showStatusMessage(getContext().getString(R.string.webview_empty_message)); text = wrapStatusMessage(getContext().getString(R.string.webview_empty_message));
}
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;
} }
} }
public void showStatusMessage(String status) { throw new IllegalStateException("Unknown error type: " + errorType);
String text = "<div style=\"text-align:center; color: grey;\">" + status + "</div>"; }
loadBodyFromText(text);
public String wrapStatusMessage(String status) {
return "<div style=\"text-align:center; color: grey;\">" + status + "</div>";
} }
private void loadBodyFromText(String emailText) { private void loadBodyFromText(String emailText) {