mirror of
https://github.com/moparisthebest/k-9
synced 2024-11-27 11:42: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:
parent
c6abb50d10
commit
6f3f555986
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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,19 +103,22 @@ public class MessageCryptoHelper {
|
||||
}
|
||||
|
||||
Part part = partsToDecryptOrVerify.peekFirst();
|
||||
if ("text/plain".equalsIgnoreCase(part.getMimeType())) {
|
||||
if (!MessageHelper.isCompletePartAvailable(part)) {
|
||||
addErrorAnnotation(part);
|
||||
} else {
|
||||
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 {
|
||||
partsToDecryptOrVerify.removeFirst();
|
||||
decryptOrVerifyNextPart();
|
||||
annotation.setErrorType(CryptoError.ENCRYPTED_BUT_INCOMPLETE);
|
||||
}
|
||||
messageAnnotations.put(part, annotation);
|
||||
onCryptoFinished();
|
||||
}
|
||||
|
||||
private void startDecryptingOrVerifyingPart(Part part) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
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) {
|
||||
String text = "<div style=\"text-align:center; color: grey;\">" + status + "</div>";
|
||||
loadBodyFromText(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) {
|
||||
|
Loading…
Reference in New Issue
Block a user