mirror of
https://github.com/moparisthebest/k-9
synced 2024-11-30 05:02:26 -05:00
First attempt at decrypting PGP/MIME messages
This commit is contained in:
parent
bb83fdc0e8
commit
7f811fce2c
@ -2,6 +2,7 @@
|
|||||||
package com.fsck.k9.mail;
|
package com.fsck.k9.mail;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
|
||||||
public interface Part {
|
public interface Part {
|
||||||
|
@ -7,13 +7,15 @@ import java.util.Stack;
|
|||||||
|
|
||||||
import com.fsck.k9.mail.Body;
|
import com.fsck.k9.mail.Body;
|
||||||
import com.fsck.k9.mail.BodyPart;
|
import com.fsck.k9.mail.BodyPart;
|
||||||
import com.fsck.k9.mail.MessagingException;
|
|
||||||
import com.fsck.k9.mail.Multipart;
|
import com.fsck.k9.mail.Multipart;
|
||||||
import com.fsck.k9.mail.Part;
|
import com.fsck.k9.mail.Part;
|
||||||
|
import com.fsck.k9.mail.internet.MimeUtility;
|
||||||
|
|
||||||
|
|
||||||
public class MessageDecryptor {
|
public class MessageDecryptor {
|
||||||
private static final String MULTIPART_ENCRYPTED = "multipart/encrypted";
|
private static final String MULTIPART_ENCRYPTED = "multipart/encrypted";
|
||||||
|
private static final String PROTOCOL_PARAMETER = "protocol";
|
||||||
|
private static final String APPLICATION_PGP_ENCRYPTED = "application/pgp-encrypted";
|
||||||
|
|
||||||
public static List<Part> findEncryptedParts(Part startPart) {
|
public static List<Part> findEncryptedParts(Part startPart) {
|
||||||
List<Part> encryptedParts = new ArrayList<Part>();
|
List<Part> encryptedParts = new ArrayList<Part>();
|
||||||
@ -38,4 +40,12 @@ public class MessageDecryptor {
|
|||||||
|
|
||||||
return encryptedParts;
|
return encryptedParts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isPgpMimeEncryptedPart(Part part) {
|
||||||
|
//FIXME: Doesn't work right now because LocalMessage.getContentType() doesn't load headers from database
|
||||||
|
// String contentType = part.getContentType();
|
||||||
|
// String protocol = MimeUtility.getHeaderParameter(contentType, PROTOCOL_PARAMETER);
|
||||||
|
// return APPLICATION_PGP_ENCRYPTED.equals(protocol);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,200 @@
|
|||||||
|
package com.fsck.k9.mailstore;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.Stack;
|
||||||
|
|
||||||
|
import com.fsck.k9.mail.Body;
|
||||||
|
import com.fsck.k9.mail.BodyPart;
|
||||||
|
import com.fsck.k9.mail.Message;
|
||||||
|
import com.fsck.k9.mail.MessagingException;
|
||||||
|
import com.fsck.k9.mail.Multipart;
|
||||||
|
import com.fsck.k9.mail.Part;
|
||||||
|
import com.fsck.k9.mail.internet.MimeBodyPart;
|
||||||
|
import com.fsck.k9.mail.internet.MimeMessage;
|
||||||
|
import com.fsck.k9.mail.internet.MimeMultipart;
|
||||||
|
import com.fsck.k9.mail.internet.MimeUtility;
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.apache.james.mime4j.MimeException;
|
||||||
|
import org.apache.james.mime4j.io.EOLConvertingInputStream;
|
||||||
|
import org.apache.james.mime4j.parser.ContentHandler;
|
||||||
|
import org.apache.james.mime4j.parser.MimeStreamParser;
|
||||||
|
import org.apache.james.mime4j.stream.BodyDescriptor;
|
||||||
|
import org.apache.james.mime4j.stream.Field;
|
||||||
|
import org.apache.james.mime4j.stream.MimeConfig;
|
||||||
|
|
||||||
|
|
||||||
|
public class DecryptStreamParser {
|
||||||
|
public static DecryptedBodyPart parse(Part multipartEncrypted, InputStream inputStream) throws MessagingException, IOException {
|
||||||
|
DecryptedBodyPart decryptedRootPart = new DecryptedBodyPart(multipartEncrypted);
|
||||||
|
|
||||||
|
MimeConfig parserConfig = new MimeConfig();
|
||||||
|
parserConfig.setMaxHeaderLen(-1);
|
||||||
|
parserConfig.setMaxLineLen(-1);
|
||||||
|
parserConfig.setMaxHeaderCount(-1);
|
||||||
|
|
||||||
|
MimeStreamParser parser = new MimeStreamParser(parserConfig);
|
||||||
|
parser.setContentHandler(new PartBuilder(multipartEncrypted, decryptedRootPart));
|
||||||
|
parser.setRecurse();
|
||||||
|
|
||||||
|
try {
|
||||||
|
parser.parse(new EOLConvertingInputStream(inputStream));
|
||||||
|
} catch (MimeException e) {
|
||||||
|
throw new MessagingException("Failed to parse decrypted content", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return decryptedRootPart;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Body createBody(InputStream inputStream, String transferEncoding) throws IOException {
|
||||||
|
//TODO: only read parts we're going to display into memory
|
||||||
|
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||||
|
try {
|
||||||
|
IOUtils.copy(inputStream, byteArrayOutputStream);
|
||||||
|
} finally {
|
||||||
|
byteArrayOutputStream.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] data = byteArrayOutputStream.toByteArray();
|
||||||
|
|
||||||
|
return new BinaryMemoryBody(data, transferEncoding);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static class PartBuilder implements ContentHandler {
|
||||||
|
private final Part multipartEncrypted;
|
||||||
|
private final DecryptedBodyPart decryptedRootPart;
|
||||||
|
private final Stack<Object> stack = new Stack<Object>();
|
||||||
|
|
||||||
|
public PartBuilder(Part multipartEncrypted, DecryptedBodyPart decryptedRootPart) throws MessagingException {
|
||||||
|
this.multipartEncrypted = multipartEncrypted;
|
||||||
|
this.decryptedRootPart = decryptedRootPart;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startMessage() throws MimeException {
|
||||||
|
if (stack.isEmpty()) {
|
||||||
|
stack.push(decryptedRootPart);
|
||||||
|
} else {
|
||||||
|
Part part = (Part) stack.peek();
|
||||||
|
|
||||||
|
Message innerMessage = new DecryptedMimeMessage(multipartEncrypted);
|
||||||
|
part.setBody(innerMessage);
|
||||||
|
|
||||||
|
stack.push(innerMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void endMessage() throws MimeException {
|
||||||
|
stack.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startBodyPart() throws MimeException {
|
||||||
|
try {
|
||||||
|
Multipart multipart = (Multipart) stack.peek();
|
||||||
|
|
||||||
|
BodyPart bodyPart = new DecryptedBodyPart(multipartEncrypted);
|
||||||
|
multipart.addBodyPart(bodyPart);
|
||||||
|
|
||||||
|
stack.push(bodyPart);
|
||||||
|
} catch (MessagingException e) {
|
||||||
|
throw new MimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void endBodyPart() throws MimeException {
|
||||||
|
stack.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startHeader() throws MimeException {
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void field(Field parsedField) throws MimeException {
|
||||||
|
try {
|
||||||
|
String name = parsedField.getName();
|
||||||
|
String raw = parsedField.getRaw().toString();
|
||||||
|
|
||||||
|
Part part = (Part) stack.peek();
|
||||||
|
part.addRawHeader(name, raw);
|
||||||
|
} catch (MessagingException e) {
|
||||||
|
throw new MimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void endHeader() throws MimeException {
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void preamble(InputStream is) throws MimeException, IOException {
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void epilogue(InputStream is) throws MimeException, IOException {
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startMultipart(BodyDescriptor bd) throws MimeException {
|
||||||
|
Part part = (Part) stack.peek();
|
||||||
|
try {
|
||||||
|
String contentType = part.getContentType();
|
||||||
|
String mimeType = MimeUtility.getHeaderParameter(contentType, null);
|
||||||
|
String boundary = MimeUtility.getHeaderParameter(contentType, "boundary");
|
||||||
|
|
||||||
|
MimeMultipart multipart = new MimeMultipart(mimeType, boundary);
|
||||||
|
part.setBody(multipart);
|
||||||
|
|
||||||
|
stack.push(multipart);
|
||||||
|
} catch (MessagingException e) {
|
||||||
|
throw new MimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void endMultipart() throws MimeException {
|
||||||
|
stack.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void body(BodyDescriptor bd, InputStream inputStream) throws MimeException, IOException {
|
||||||
|
Part part = (Part) stack.peek();
|
||||||
|
|
||||||
|
String transferEncoding = bd.getTransferEncoding();
|
||||||
|
Body body = createBody(inputStream, transferEncoding);
|
||||||
|
|
||||||
|
part.setBody(body);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void raw(InputStream is) throws MimeException, IOException {
|
||||||
|
throw new IllegalStateException("Not implemented");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class DecryptedBodyPart extends MimeBodyPart {
|
||||||
|
private final Part multipartEncrypted;
|
||||||
|
|
||||||
|
public DecryptedBodyPart(Part multipartEncrypted) throws MessagingException {
|
||||||
|
this.multipartEncrypted = multipartEncrypted;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class DecryptedMimeMessage extends MimeMessage {
|
||||||
|
private final Part multipartEncrypted;
|
||||||
|
|
||||||
|
public DecryptedMimeMessage(Part multipartEncrypted) {
|
||||||
|
this.multipartEncrypted = multipartEncrypted;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -442,7 +442,8 @@ public class LocalMessageExtractor {
|
|||||||
|
|
||||||
return new AttachmentViewInfo(mimeType, displayName, size, uri, firstClassAttachment, part);
|
return new AttachmentViewInfo(mimeType, displayName, size, uri, firstClassAttachment, part);
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalStateException("Not supported yet");
|
//FIXME: The content provider URI thing needs to be reworked
|
||||||
|
return extractAttachmentInfo(part, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,13 @@
|
|||||||
package com.fsck.k9.ui.messageview;
|
package com.fsck.k9.ui.messageview;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.PipedInputStream;
|
||||||
|
import java.io.PipedOutputStream;
|
||||||
|
import java.util.ArrayDeque;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.Deque;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
@ -14,6 +20,7 @@ import android.content.Context;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.Loader;
|
import android.content.Loader;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.os.AsyncTask;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
@ -27,6 +34,7 @@ import android.view.ViewGroup;
|
|||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.fsck.k9.Account;
|
import com.fsck.k9.Account;
|
||||||
|
import com.fsck.k9.Identity;
|
||||||
import com.fsck.k9.K9;
|
import com.fsck.k9.K9;
|
||||||
import com.fsck.k9.Preferences;
|
import com.fsck.k9.Preferences;
|
||||||
import com.fsck.k9.R;
|
import com.fsck.k9.R;
|
||||||
@ -34,21 +42,35 @@ import com.fsck.k9.activity.ChooseFolder;
|
|||||||
import com.fsck.k9.activity.MessageReference;
|
import com.fsck.k9.activity.MessageReference;
|
||||||
import com.fsck.k9.controller.MessagingController;
|
import com.fsck.k9.controller.MessagingController;
|
||||||
import com.fsck.k9.controller.MessagingListener;
|
import com.fsck.k9.controller.MessagingListener;
|
||||||
|
import com.fsck.k9.crypto.MessageDecryptor;
|
||||||
|
import com.fsck.k9.crypto.OpenPgpApiHelper;
|
||||||
import com.fsck.k9.crypto.PgpData;
|
import com.fsck.k9.crypto.PgpData;
|
||||||
import com.fsck.k9.fragment.ConfirmationDialogFragment;
|
import com.fsck.k9.fragment.ConfirmationDialogFragment;
|
||||||
import com.fsck.k9.fragment.ConfirmationDialogFragment.ConfirmationDialogFragmentListener;
|
import com.fsck.k9.fragment.ConfirmationDialogFragment.ConfirmationDialogFragmentListener;
|
||||||
import com.fsck.k9.fragment.ProgressDialogFragment;
|
import com.fsck.k9.fragment.ProgressDialogFragment;
|
||||||
import com.fsck.k9.helper.FileBrowserHelper;
|
import com.fsck.k9.helper.FileBrowserHelper;
|
||||||
import com.fsck.k9.helper.FileBrowserHelper.FileBrowserFailOverCallback;
|
import com.fsck.k9.helper.FileBrowserHelper.FileBrowserFailOverCallback;
|
||||||
|
import com.fsck.k9.helper.IdentityHelper;
|
||||||
|
import com.fsck.k9.mail.Body;
|
||||||
|
import com.fsck.k9.mail.BodyPart;
|
||||||
import com.fsck.k9.mail.Flag;
|
import com.fsck.k9.mail.Flag;
|
||||||
import com.fsck.k9.mail.MessagingException;
|
import com.fsck.k9.mail.MessagingException;
|
||||||
|
import com.fsck.k9.mail.Multipart;
|
||||||
|
import com.fsck.k9.mail.Part;
|
||||||
import com.fsck.k9.mailstore.AttachmentViewInfo;
|
import com.fsck.k9.mailstore.AttachmentViewInfo;
|
||||||
|
import com.fsck.k9.mailstore.DecryptStreamParser;
|
||||||
|
import com.fsck.k9.mailstore.DecryptStreamParser.DecryptedBodyPart;
|
||||||
import com.fsck.k9.mailstore.LocalMessage;
|
import com.fsck.k9.mailstore.LocalMessage;
|
||||||
import com.fsck.k9.mailstore.MessageViewInfo;
|
import com.fsck.k9.mailstore.MessageViewInfo;
|
||||||
import com.fsck.k9.ui.message.DecodeMessageLoader;
|
import com.fsck.k9.ui.message.DecodeMessageLoader;
|
||||||
import com.fsck.k9.ui.message.LocalMessageLoader;
|
import com.fsck.k9.ui.message.LocalMessageLoader;
|
||||||
import com.fsck.k9.view.MessageHeader;
|
import com.fsck.k9.view.MessageHeader;
|
||||||
|
import org.openintents.openpgp.IOpenPgpService;
|
||||||
import org.openintents.openpgp.OpenPgpSignatureResult;
|
import org.openintents.openpgp.OpenPgpSignatureResult;
|
||||||
|
import org.openintents.openpgp.util.OpenPgpApi;
|
||||||
|
import org.openintents.openpgp.util.OpenPgpApi.IOpenPgpCallback;
|
||||||
|
import org.openintents.openpgp.util.OpenPgpServiceConnection;
|
||||||
|
import org.openintents.openpgp.util.OpenPgpServiceConnection.OnBound;
|
||||||
|
|
||||||
|
|
||||||
public class MessageViewFragment extends Fragment implements ConfirmationDialogFragmentListener,
|
public class MessageViewFragment extends Fragment implements ConfirmationDialogFragmentListener,
|
||||||
@ -109,6 +131,9 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF
|
|||||||
private LoaderCallbacks<MessageViewInfo> decodeMessageLoaderCallback = new DecodeMessageLoaderCallback();
|
private LoaderCallbacks<MessageViewInfo> decodeMessageLoaderCallback = new DecodeMessageLoaderCallback();
|
||||||
private MessageViewInfo messageViewInfo;
|
private MessageViewInfo messageViewInfo;
|
||||||
private AttachmentViewInfo currentAttachmentViewInfo;
|
private AttachmentViewInfo currentAttachmentViewInfo;
|
||||||
|
private Deque<Part> partsToDecrypt;
|
||||||
|
private OpenPgpApi openPgpApi;
|
||||||
|
private Part currentlyDecryptingPart;
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -223,11 +248,177 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF
|
|||||||
|
|
||||||
if (message.isBodyMissing()) {
|
if (message.isBodyMissing()) {
|
||||||
startDownloadingMessageBody(message);
|
startDownloadingMessageBody(message);
|
||||||
|
} else {
|
||||||
|
decryptMessagePartsIfNecessary(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void decryptMessagePartsIfNecessary(LocalMessage message) {
|
||||||
|
List<Part> encryptedParts = MessageDecryptor.findEncryptedParts(message);
|
||||||
|
if (!encryptedParts.isEmpty()) {
|
||||||
|
partsToDecrypt = new ArrayDeque<Part>(encryptedParts);
|
||||||
|
decryptNextPartOrStartExtractingTextAndAttachments();
|
||||||
} else {
|
} else {
|
||||||
startExtractingTextAndAttachments(message);
|
startExtractingTextAndAttachments(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void decryptNextPartOrStartExtractingTextAndAttachments() {
|
||||||
|
if (partsToDecrypt.isEmpty()) {
|
||||||
|
startExtractingTextAndAttachments(mMessage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Part part = partsToDecrypt.peekFirst();
|
||||||
|
if (MessageDecryptor.isPgpMimeEncryptedPart(part)) {
|
||||||
|
startDecryptingPart(part);
|
||||||
|
} else {
|
||||||
|
// Note: We currently only support PGP/MIME multipart/encrypted parts
|
||||||
|
|
||||||
|
partsToDecrypt.removeFirst();
|
||||||
|
decryptNextPartOrStartExtractingTextAndAttachments();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startDecryptingPart(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 {
|
||||||
|
decryptPart(part);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isBoundToCryptoProviderService() {
|
||||||
|
return openPgpApi != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void connectToCryptoProviderService() {
|
||||||
|
String openPgpProvider = mAccount.getOpenPgpProvider();
|
||||||
|
new OpenPgpServiceConnection(getContext(), openPgpProvider,
|
||||||
|
new OnBound() {
|
||||||
|
@Override
|
||||||
|
public void onBound(IOpenPgpService service) {
|
||||||
|
openPgpApi = new OpenPgpApi(getContext(), service);
|
||||||
|
|
||||||
|
decryptNextPartOrStartExtractingTextAndAttachments();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(Exception e) {
|
||||||
|
Log.e(K9.LOG_TAG, "Couldn't connect to OpenPgpService", e);
|
||||||
|
}
|
||||||
|
}).bindToService();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void decryptPart(Part part) {
|
||||||
|
currentlyDecryptingPart = part;
|
||||||
|
decryptVerify(new Intent());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void decryptVerify(Intent intent) {
|
||||||
|
intent.setAction(OpenPgpApi.ACTION_DECRYPT_VERIFY);
|
||||||
|
|
||||||
|
Identity identity = IdentityHelper.getRecipientIdentityFromMessage(mAccount, mMessage);
|
||||||
|
String accountName = OpenPgpApiHelper.buildAccountName(identity);
|
||||||
|
intent.putExtra(OpenPgpApi.EXTRA_ACCOUNT_NAME, accountName);
|
||||||
|
|
||||||
|
try {
|
||||||
|
PipedInputStream pipedInputStream = getPipedInputStreamForEncryptedData();
|
||||||
|
PipedOutputStream decryptedOutputStream = getPipedOutputStreamForDecryptedData();
|
||||||
|
|
||||||
|
openPgpApi.executeApiAsync(intent, pipedInputStream, decryptedOutputStream, new IOpenPgpCallback() {
|
||||||
|
@Override
|
||||||
|
public void onReturn(Intent result) {
|
||||||
|
//TODO: check result code
|
||||||
|
//TODO: signal to AsyncTask in getPipedOutputStreamForDecryptedData() that we have a result code
|
||||||
|
//TODO: handle RESULT_INTENT
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(K9.LOG_TAG, "IOException", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private PipedInputStream getPipedInputStreamForEncryptedData() throws IOException {
|
||||||
|
PipedInputStream pipedInputStream = new PipedInputStream();
|
||||||
|
|
||||||
|
final PipedOutputStream out = new PipedOutputStream(pipedInputStream);
|
||||||
|
new Thread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
Multipart multipartEncryptedMultipart = (Multipart) currentlyDecryptingPart.getBody();
|
||||||
|
BodyPart encryptionPayloadPart = multipartEncryptedMultipart.getBodyPart(1);
|
||||||
|
Body encryptionPayloadBody = encryptionPayloadPart.getBody();
|
||||||
|
encryptionPayloadBody.writeTo(out);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(K9.LOG_TAG, "Exception while writing message to crypto provider", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
|
||||||
|
return pipedInputStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
private PipedOutputStream getPipedOutputStreamForDecryptedData() throws IOException {
|
||||||
|
PipedOutputStream decryptedOutputStream = new PipedOutputStream();
|
||||||
|
final PipedInputStream decryptedInputStream = new PipedInputStream(decryptedOutputStream);
|
||||||
|
new AsyncTask<Void, Void, DecryptedBodyPart>() {
|
||||||
|
@Override
|
||||||
|
protected DecryptedBodyPart doInBackground(Void... params) {
|
||||||
|
try {
|
||||||
|
DecryptedBodyPart decryptedPart =
|
||||||
|
DecryptStreamParser.parse(currentlyDecryptingPart, decryptedInputStream);
|
||||||
|
|
||||||
|
//TODO: wait for IOpenPgpCallback.onReturn() to get the result code and only use
|
||||||
|
// decryptedPart when the decryption was successful
|
||||||
|
|
||||||
|
return decryptedPart;
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(K9.LOG_TAG, "Something went wrong while parsing the decrypted MIME part", e);
|
||||||
|
//TODO: pass error to main thread and display error message to user
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(DecryptedBodyPart decryptedPart) {
|
||||||
|
if (decryptedPart == null) {
|
||||||
|
onDecryptionFailed();
|
||||||
|
} else {
|
||||||
|
onDecryptionSuccess(decryptedPart);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.execute();
|
||||||
|
return decryptedOutputStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onDecryptionSuccess(DecryptedBodyPart decryptedPart) {
|
||||||
|
addDecryptedPartToMessage(decryptedPart);
|
||||||
|
onDecryptionFinished();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addDecryptedPartToMessage(DecryptedBodyPart decryptedPart) {
|
||||||
|
Multipart multipart = (Multipart) currentlyDecryptingPart.getBody();
|
||||||
|
multipart.addBodyPart(decryptedPart);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onDecryptionFailed() {
|
||||||
|
//TODO: display error to user?
|
||||||
|
onDecryptionFinished();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onDecryptionFinished() {
|
||||||
|
partsToDecrypt.removeFirst();
|
||||||
|
decryptNextPartOrStartExtractingTextAndAttachments();
|
||||||
|
}
|
||||||
|
|
||||||
private void onLoadMessageFromDatabaseFailed() {
|
private void onLoadMessageFromDatabaseFailed() {
|
||||||
mMessageView.showStatusMessage(mContext.getString(R.string.status_invalid_id_error));
|
mMessageView.showStatusMessage(mContext.getString(R.string.status_invalid_id_error));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user