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:
parent
c6abb50d10
commit
6f3f555986
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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 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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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) {
|
||||||
|
@ -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) {
|
||||||
|
Loading…
Reference in New Issue
Block a user