From dbaf7070ead596f5c70ad48fc55aada2f77a856a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Mon, 10 Aug 2015 14:35:15 +0200 Subject: WIP mime parsing --- .../keychain/operations/MimeParsingOperation.java | 360 +++++++++++++++++++++ .../operations/results/MimeParsingResult.java | 65 ++++ .../operations/results/OperationResult.java | 5 + .../keychain/service/KeychainService.java | 4 + .../keychain/service/MimeParsingParcel.java | 73 +++++ .../keychain/ui/DecryptListFragment.java | 130 +++++--- 6 files changed, 596 insertions(+), 41 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/MimeParsingOperation.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/MimeParsingResult.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/MimeParsingParcel.java (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/MimeParsingOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/MimeParsingOperation.java new file mode 100644 index 000000000..c7ebbf5fd --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/MimeParsingOperation.java @@ -0,0 +1,360 @@ +/* + * Copyright (C) 2015 Dominik Schürmann + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.sufficientlysecure.keychain.operations; + +import android.content.Context; +import android.net.Uri; +import android.support.annotation.NonNull; + +import org.apache.james.mime4j.dom.BinaryBody; +import org.apache.james.mime4j.dom.Body; +import org.apache.james.mime4j.dom.Entity; +import org.apache.james.mime4j.dom.Message; +import org.apache.james.mime4j.dom.MessageBuilder; +import org.apache.james.mime4j.dom.Multipart; +import org.apache.james.mime4j.dom.TextBody; +import org.apache.james.mime4j.dom.address.Mailbox; +import org.apache.james.mime4j.dom.address.MailboxList; +import org.apache.james.mime4j.dom.field.AddressListField; +import org.apache.james.mime4j.dom.field.ContentTypeField; +import org.apache.james.mime4j.dom.field.DateTimeField; +import org.apache.james.mime4j.dom.field.UnstructuredField; +import org.apache.james.mime4j.field.address.AddressFormatter; +import org.apache.james.mime4j.message.BodyPart; +import org.apache.james.mime4j.message.DefaultMessageBuilder; +import org.apache.james.mime4j.message.MessageImpl; +import org.apache.james.mime4j.stream.Field; +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.operations.results.MimeParsingResult; +import org.sufficientlysecure.keychain.operations.results.OperationResult; +import org.sufficientlysecure.keychain.pgp.Progressable; +import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.provider.TemporaryStorageProvider; +import org.sufficientlysecure.keychain.service.MimeParsingParcel; +import org.sufficientlysecure.keychain.service.input.CryptoInputParcel; +import org.sufficientlysecure.keychain.util.Log; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Reader; +import java.util.ArrayList; +import java.util.Date; +import java.util.Map; + +public class MimeParsingOperation extends BaseOperation { + + public ArrayList mTempUris; + + public MimeParsingOperation(Context context, ProviderHelper providerHelper, Progressable progressable) { + super(context, providerHelper, progressable); + } + + @NonNull + @Override + public MimeParsingResult execute(MimeParsingParcel parcel, + CryptoInputParcel cryptoInputParcel) { + OperationResult.OperationLog log = new OperationResult.OperationLog(); + + log.add(OperationResult.LogType.MSG_MIME_PARSING, 0); + + mTempUris = new ArrayList<>(); + + try { + InputStream in = mContext.getContentResolver().openInputStream(parcel.getInputUri()); + + final MessageBuilder builder = new DefaultMessageBuilder(); + final Message message = builder.parseMessage(in); + + SimpleTreeNode root = createNode(message); + + traverseTree(root); + + log.add(OperationResult.LogType.MSG_MIME_PARSING_SUCCESS, 1); + + } catch (Exception e) { + Log.e(Constants.TAG, "Mime parsing error", e); + log.add(OperationResult.LogType.MSG_MIME_PARSING_ERROR, 1); + } + + return new MimeParsingResult(MimeParsingResult.RESULT_OK, log, + mTempUris); + } + + private void traverseTree(SimpleTreeNode node) { + if (node.isLeaf()) { + parseAndSaveAsUris(node); + return; + } + + for (SimpleTreeNode child : node.children) { + traverseTree(child); + } + } + + + /** + * Wraps an Object and associates it with a text. All message parts + * (headers, bodies, multiparts, body parts) will be wrapped in + * ObjectWrapper instances before they are added to the JTree instance. + */ + public static class ObjectWrapper { + private String text = ""; + private Object object = null; + + public ObjectWrapper(String text, Object object) { + this.text = text; + this.object = object; + } + + @Override + public String toString() { + return text; + } + + public Object getObject() { + return object; + } + } + +// /** +// * Create a node given a Multipart body. +// * Add the Preamble, all Body parts and the Epilogue to the node. +// * +// * @return the root node of the tree. +// */ +// private DefaultMutableTreeNode createNode(Header header) { +// DefaultMutableTreeNode node = new DefaultMutableTreeNode( +// new ObjectWrapper("Header", header)); +// +// for (Field field : header.getFields()) { +// String name = field.getName(); +// +// node.add(new DefaultMutableTreeNode(new ObjectWrapper(name, field))); +// } +// +// return node; +// } + + /** + * Create a node given a Multipart body. + * Add the Preamble, all Body parts and the Epilogue to the node. + * + * @param multipart the Multipart. + * @return the root node of the tree. + */ + private SimpleTreeNode createNode(Multipart multipart) { + SimpleTreeNode node = new SimpleTreeNode( + new ObjectWrapper("Multipart", multipart)); + +// node.add(new DefaultMutableTreeNode( +// new ObjectWrapper("Preamble", multipart.getPreamble()))); + for (Entity part : multipart.getBodyParts()) { + node.add(createNode(part)); + } +// node.add(new DefaultMutableTreeNode( +// new ObjectWrapper("Epilogue", multipart.getEpilogue()))); + + return node; + } + + /** + * Creates the tree nodes given a MIME entity (either a Message or + * a BodyPart). + * + * @param entity the entity. + * @return the root node of the tree displaying the specified entity and + * its children. + */ + private SimpleTreeNode createNode(Entity entity) { + + /* + * Create the root node for the entity. It's either a + * Message or a Body part. + */ + String type = "Message"; + if (entity instanceof BodyPart) { + type = "Body part"; + } + SimpleTreeNode node = new SimpleTreeNode( + new ObjectWrapper(type, entity)); + + /* + * Add the node encapsulating the entity Header. + */ +// node.add(createNode(entity.getHeader())); + + Body body = entity.getBody(); + + if (body instanceof Multipart) { + /* + * The body of the entity is a Multipart. + */ + + node.add(createNode((Multipart) body)); + } else if (body instanceof MessageImpl) { + /* + * The body is another Message. + */ + + node.add(createNode((MessageImpl) body)); + + } else { + /* + * Discrete Body (either of type TextBody or BinaryBody). + */ + type = "Text body"; + if (body instanceof BinaryBody) { + type = "Binary body"; + } + + type += " (" + entity.getMimeType() + ")"; + node.add(new SimpleTreeNode(new ObjectWrapper(type, body))); + + } + + return node; + } + + public void parseAndSaveAsUris(SimpleTreeNode node) { + Object o = ((ObjectWrapper) node.getUserObject()).getObject(); + + if (o instanceof TextBody) { + /* + * A text body. Display its contents. + */ + TextBody body = (TextBody) o; + StringBuilder sb = new StringBuilder(); + try { + Reader r = body.getReader(); + int c; + while ((c = r.read()) != -1) { + sb.append((char) c); + } + } catch (IOException ex) { + ex.printStackTrace(); + } + Log.d(Constants.TAG, "text: " + sb.toString()); +// textView.setText(sb.toString()); + + Uri tempUri = null; + try { + tempUri = TemporaryStorageProvider.createFile(mContext, "text", "text/plain"); + OutputStream outStream = mContext.getContentResolver().openOutputStream(tempUri); + body.writeTo(outStream); + outStream.close(); + } catch (IOException e) { + Log.e(Constants.TAG, "error mime parsing", e); + } + + mTempUris.add(tempUri); + + } else if (o instanceof BinaryBody) { + /* + * A binary body. Display its MIME type and length in bytes. + */ + BinaryBody body = (BinaryBody) o; + int size = 0; + try { + InputStream is = body.getInputStream(); + while ((is.read()) != -1) { + size++; + } + } catch (IOException ex) { + ex.printStackTrace(); + } + Log.d(Constants.TAG, "Binary body\n" + + "MIME type: " + + body.getParent().getMimeType() + "\n" + + "Size of decoded data: " + size + " bytes"); + + } else if (o instanceof ContentTypeField) { + /* + * Content-Type field. + */ + ContentTypeField field = (ContentTypeField) o; + StringBuilder sb = new StringBuilder(); + sb.append("MIME type: ").append(field.getMimeType()).append("\n"); + for (Map.Entry entry : field.getParameters().entrySet()) { + sb.append(entry.getKey()).append(" = ").append(entry.getValue()).append("\n"); + } + Log.d(Constants.TAG, sb.toString()); + + } else if (o instanceof AddressListField) { + /* + * An address field (From, To, Cc, etc) + */ + AddressListField field = (AddressListField) o; + MailboxList list = field.getAddressList().flatten(); + StringBuilder sb = new StringBuilder(); + for (Mailbox mailbox : list) { + sb.append(AddressFormatter.DEFAULT.format(mailbox, false)).append("\n"); + } + Log.d(Constants.TAG, sb.toString()); + + } else if (o instanceof DateTimeField) { + Date date = ((DateTimeField) o).getDate(); + Log.d(Constants.TAG, date.toString()); + } else if (o instanceof UnstructuredField) { + Log.d(Constants.TAG, ((UnstructuredField) o).getValue()); + } else if (o instanceof Field) { + Log.d(Constants.TAG, ((Field) o).getBody()); + } else { + /* + * The Object should be a Header or a String containing a + * Preamble or Epilogue. + */ + Log.d(Constants.TAG, o.toString()); + } + } + + public class SimpleTreeNode { + private SimpleTreeNode parent; + private Object userObject; + private ArrayList children; + + protected SimpleTreeNode(Object userObject) { + this.parent = null; + this.userObject = userObject; + this.children = new ArrayList<>(); + } + + protected Object getUserObject() { + return userObject; + } + + protected void setUserObject(Object userObject) { + this.userObject = userObject; + } + + public void add(SimpleTreeNode newChild) { + newChild.parent = this; + children.add(newChild); + } + + public SimpleTreeNode getParent() { + return parent; + } + + public boolean isLeaf() { + return children.isEmpty(); + } + + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/MimeParsingResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/MimeParsingResult.java new file mode 100644 index 000000000..05f5125cb --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/MimeParsingResult.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2015 Dominik Schürmann + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.sufficientlysecure.keychain.operations.results; + +import android.net.Uri; +import android.os.Parcel; + +import java.util.ArrayList; + +public class MimeParsingResult extends OperationResult { + + public final ArrayList mTemporaryUris; + + public ArrayList getTemporaryUris() { + return mTemporaryUris; + } + + public MimeParsingResult(int result, OperationLog log, ArrayList temporaryUris) { + super(result, log); + mTemporaryUris = temporaryUris; + } + + protected MimeParsingResult(Parcel in) { + super(in); + mTemporaryUris = in.createTypedArrayList(Uri.CREATOR); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeTypedList(mTemporaryUris); + } + + public static final Creator CREATOR = new Creator() { + @Override + public MimeParsingResult createFromParcel(Parcel in) { + return new MimeParsingResult(in); + } + + @Override + public MimeParsingResult[] newArray(int size) { + return new MimeParsingResult[size]; + } + }; +} \ No newline at end of file diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java index d498bd9a1..3c15a2e7b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java @@ -787,6 +787,11 @@ public abstract class OperationResult implements Parcelable { MSG_EXPORT_LOG_EXPORT_ERROR_FOPEN(LogLevel.ERROR,R.string.msg_export_log_error_fopen), MSG_EXPORT_LOG_EXPORT_ERROR_WRITING(LogLevel.ERROR,R.string.msg_export_log_error_writing), MSG_EXPORT_LOG_EXPORT_SUCCESS (LogLevel.OK, R.string.msg_export_log_success), + + // mim parsing + MSG_MIME_PARSING(LogLevel.START,R.string.msg_mime_parsing_start), + MSG_MIME_PARSING_ERROR(LogLevel.ERROR,R.string.msg_mime_parsing_error), + MSG_MIME_PARSING_SUCCESS(LogLevel.OK,R.string.msg_mime_parsing_success), ; public final int mMsgId; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainService.java index dca2a08c2..ce4381140 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainService.java @@ -36,6 +36,7 @@ import org.sufficientlysecure.keychain.operations.EditKeyOperation; import org.sufficientlysecure.keychain.operations.ExportOperation; import org.sufficientlysecure.keychain.operations.ImportOperation; import org.sufficientlysecure.keychain.operations.KeybaseVerificationOperation; +import org.sufficientlysecure.keychain.operations.MimeParsingOperation; import org.sufficientlysecure.keychain.operations.PromoteKeyOperation; import org.sufficientlysecure.keychain.operations.RevokeOperation; import org.sufficientlysecure.keychain.operations.SignEncryptOperation; @@ -137,6 +138,9 @@ public class KeychainService extends Service implements Progressable { } else if (inputParcel instanceof KeybaseVerificationParcel) { op = new KeybaseVerificationOperation(outerThis, new ProviderHelper(outerThis), outerThis); + } else if (inputParcel instanceof MimeParsingParcel) { + op = new MimeParsingOperation(outerThis, new ProviderHelper(outerThis), + outerThis); } else { throw new AssertionError("Unrecognized input parcel in KeychainService!"); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/MimeParsingParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/MimeParsingParcel.java new file mode 100644 index 000000000..ccc817c21 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/MimeParsingParcel.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2015 Dominik Schürmann + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.sufficientlysecure.keychain.service; + +import android.net.Uri; +import android.os.Parcel; +import android.os.Parcelable; + +public class MimeParsingParcel implements Parcelable { + + private Uri mInputUri; + private Uri mOutputUri; + + public MimeParsingParcel() { + } + + public MimeParsingParcel(Uri inputUri, Uri outputUri) { + mInputUri = inputUri; + mOutputUri = outputUri; + } + + MimeParsingParcel(Parcel source) { + // we do all of those here, so the PgpSignEncryptInput class doesn't have to be parcelable + mInputUri = source.readParcelable(getClass().getClassLoader()); + mOutputUri = source.readParcelable(getClass().getClassLoader()); + } + + public Uri getInputUri() { + return mInputUri; + } + + public Uri getOutputUri() { + return mOutputUri; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeParcelable(mInputUri, 0); + dest.writeParcelable(mOutputUri, 0); + } + + public static final Creator CREATOR = new Creator() { + public MimeParsingParcel createFromParcel(final Parcel source) { + return new MimeParsingParcel(source); + } + + public MimeParsingParcel[] newArray(final int size) { + return new MimeParsingParcel[size]; + } + }; + +} + diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptListFragment.java index f57d2d056..640755ef3 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptListFragment.java @@ -28,7 +28,6 @@ import android.app.Activity; import android.content.ClipDescription; import android.content.Context; import android.content.Intent; -import android.content.pm.LabeledIntent; import android.content.pm.ResolveInfo; import android.graphics.Bitmap; import android.graphics.Point; @@ -38,7 +37,6 @@ import android.net.Uri; import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; -import android.os.Parcelable; import android.support.v7.widget.DefaultItemAnimator; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; @@ -58,14 +56,16 @@ import android.widget.ViewAnimator; import org.openintents.openpgp.OpenPgpMetadata; import org.openintents.openpgp.OpenPgpSignatureResult; -import org.sufficientlysecure.keychain.BuildConfig; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult; +import org.sufficientlysecure.keychain.operations.results.MimeParsingResult; import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyInputParcel; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.TemporaryStorageProvider; // this import NEEDS to be above the ViewModel one, or it won't compile! (as of 06/06/15) +import org.sufficientlysecure.keychain.service.MimeParsingParcel; +import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper; import org.sufficientlysecure.keychain.ui.base.QueueingCryptoOperationFragment; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.StatusHolder; import org.sufficientlysecure.keychain.ui.DecryptListFragment.DecryptFilesAdapter.ViewModel; @@ -432,45 +432,47 @@ public class DecryptListFragment // OpenKeychain's internal viewer if ("text/plain".equals(metadata.getMimeType())) { - // this is a significant i/o operation, use an asynctask - new AsyncTask() { - - @Override - protected Intent doInBackground(Void... params) { - - Activity activity = getActivity(); - if (activity == null) { - return null; - } - - Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setDataAndType(outputUri, "text/plain"); - intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - return intent; - } - - @Override - protected void onPostExecute(Intent intent) { - // for result so we can possibly get a snackbar error from internal viewer - Activity activity = getActivity(); - if (intent == null || activity == null) { - return; - } + parseMime(outputUri); - LabeledIntent internalIntent = new LabeledIntent( - new Intent(intent) - .setClass(activity, DisplayTextActivity.class) - .putExtra(DisplayTextActivity.EXTRA_METADATA, result), - BuildConfig.APPLICATION_ID, R.string.view_internal, R.drawable.ic_launcher); - - Intent chooserIntent = Intent.createChooser(intent, getString(R.string.intent_show)); - chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, - new Parcelable[] { internalIntent }); - - activity.startActivity(chooserIntent); - } - - }.execute(); + // this is a significant i/o operation, use an asynctask +// new AsyncTask() { +// +// @Override +// protected Intent doInBackground(Void... params) { +// +// Activity activity = getActivity(); +// if (activity == null) { +// return null; +// } +// +// Intent intent = new Intent(Intent.ACTION_VIEW); +// intent.setDataAndType(outputUri, "text/plain"); +// intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); +// return intent; +// } +// +// @Override +// protected void onPostExecute(Intent intent) { +// // for result so we can possibly get a snackbar error from internal viewer +// Activity activity = getActivity(); +// if (intent == null || activity == null) { +// return; +// } +// +// LabeledIntent internalIntent = new LabeledIntent( +// new Intent(intent) +// .setClass(activity, DisplayTextActivity.class) +// .putExtra(DisplayTextActivity.EXTRA_METADATA, result), +// BuildConfig.APPLICATION_ID, R.string.view_internal, R.drawable.ic_launcher); +// +// Intent chooserIntent = Intent.createChooser(intent, getString(R.string.intent_show)); +// chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, +// new Parcelable[] { internalIntent }); +// +// activity.startActivity(chooserIntent); +// } +// +// }.execute(); } else { Intent intent = new Intent(Intent.ACTION_VIEW); @@ -484,6 +486,52 @@ public class DecryptListFragment } + private void parseMime(final Uri inputUri) { + + CryptoOperationHelper.Callback callback + = new CryptoOperationHelper.Callback() { + + @Override + public MimeParsingParcel createOperationInput() { + return new MimeParsingParcel(inputUri, null); + } + + @Override + public void onCryptoOperationSuccess(MimeParsingResult result) { + handleResult(result); + } + + @Override + public void onCryptoOperationCancelled() { + + } + + @Override + public void onCryptoOperationError(MimeParsingResult result) { + handleResult(result); + } + + public void handleResult(MimeParsingResult result) { + // TODO: merge with other log +// saveKeyResult.getLog().add(result, 0); + + mOutputUris = new HashMap<>(result.getTemporaryUris().size()); + for (Uri tempUri : result.getTemporaryUris()) { + // TODO: use same inputUri for all? + mOutputUris.put(inputUri, tempUri); + } + } + + @Override + public boolean onCryptoSetProgress(String msg, int progress, int max) { + return false; + } + }; + + CryptoOperationHelper mimeParsingHelper = new CryptoOperationHelper<>(3, this, callback, R.string.progress_uploading); + mimeParsingHelper.cryptoOperation(); + } + @Override public PgpDecryptVerifyInputParcel createOperationInput() { -- cgit v1.2.3