aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDominik Schürmann <dominik@dominikschuermann.de>2015-08-10 14:35:15 +0200
committerDominik Schürmann <dominik@dominikschuermann.de>2015-08-17 09:31:34 +0200
commitdbaf7070ead596f5c70ad48fc55aada2f77a856a (patch)
treec3c5c32478d1aaba490f4ff206d051fdb24f728a
parent7004d129a8546977c450bd40931b0b774cd2025e (diff)
downloadopen-keychain-dbaf7070ead596f5c70ad48fc55aada2f77a856a.tar.gz
open-keychain-dbaf7070ead596f5c70ad48fc55aada2f77a856a.tar.bz2
open-keychain-dbaf7070ead596f5c70ad48fc55aada2f77a856a.zip
WIP mime parsing
-rw-r--r--OpenKeychain/build.gradle10
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/MimeParsingOperation.java360
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/MimeParsingResult.java65
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java5
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainService.java4
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/MimeParsingParcel.java73
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptListFragment.java130
-rw-r--r--OpenKeychain/src/main/res/values/strings.xml5
8 files changed, 610 insertions, 42 deletions
diff --git a/OpenKeychain/build.gradle b/OpenKeychain/build.gradle
index 7d2f40128..5bf8f6d1b 100644
--- a/OpenKeychain/build.gradle
+++ b/OpenKeychain/build.gradle
@@ -56,6 +56,8 @@ dependencies {
compile 'com.mikepenz.iconics:community-material-typeface:1.0.0@aar'
compile 'com.nispok:snackbar:2.11.0'
compile 'com.squareup.okhttp:okhttp:2.4.0'
+ compile 'org.apache.james:apache-mime4j-core:0.7.2'
+ compile 'org.apache.james:apache-mime4j-dom:0.7.2'
// libs as submodules
compile project(':extern:openpgp-api-lib:openpgp-api')
@@ -199,15 +201,21 @@ android {
htmlOutput file('lint-report.html')
}
- // Disable preDexing, causes com.android.dx.cf.iface.ParseException: bad class file magic (cafebabe) or version (0034.0000) on some systems
dexOptions {
+ // Disable preDexing, causes com.android.dx.cf.iface.ParseException: bad class file magic (cafebabe) or version (0034.0000) on some systems
preDexLibraries = false
+ // faster with incremental?
+// incremental true
+ javaMaxHeapSize "4g"
}
packagingOptions {
exclude 'LICENSE.txt'
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/NOTICE.txt'
+ exclude 'META-INF/DEPENDENCIES'
+ exclude 'META-INF/LICENSE'
+ exclude 'META-INF/NOTICE'
exclude '.readme'
}
}
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 <dominik@dominikschuermann.de>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+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<MimeParsingParcel> {
+
+ public ArrayList<Uri> 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<String, String> 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<SimpleTreeNode> 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 <dominik@dominikschuermann.de>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+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<Uri> mTemporaryUris;
+
+ public ArrayList<Uri> getTemporaryUris() {
+ return mTemporaryUris;
+ }
+
+ public MimeParsingResult(int result, OperationLog log, ArrayList<Uri> 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<MimeParsingResult> CREATOR = new Creator<MimeParsingResult>() {
+ @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 <dominik@dominikschuermann.de>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+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<MimeParsingParcel> CREATOR = new Creator<MimeParsingParcel>() {
+ 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<Void,Void,Intent>() {
-
- @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<Void,Void,Intent>() {
+//
+// @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<MimeParsingParcel, MimeParsingResult> callback
+ = new CryptoOperationHelper.Callback<MimeParsingParcel, MimeParsingResult>() {
+
+ @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() {
diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml
index 72406aaab..6aa968756 100644
--- a/OpenKeychain/src/main/res/values/strings.xml
+++ b/OpenKeychain/src/main/res/values/strings.xml
@@ -1341,6 +1341,11 @@
<string name="msg_export_log_error_writing">"I/O error writing to file!"</string>
<string name="msg_export_log_success">"Log exported successfully!"</string>
+ <!-- Messages for Mime parsing operation -->
+ <string name="msg_mime_parsing_start">"Parsing the MIME structure"</string>
+ <string name="msg_mime_parsing_error">"MIME parsing failed"</string>
+ <string name="msg_mime_parsing_success">"MIME parsing successfully!"</string>
+
<!-- PassphraseCache -->
<string name="passp_cache_notif_click_to_clear">"Touch to clear passwords."</string>
<plurals name="passp_cache_notif_n_keys">