diff --git a/app/build.gradle b/app/build.gradle
index 560e7212b1..73bfe4b4d3 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -161,6 +161,7 @@ dependencies {
// https://javaee.github.io/javamail/
// https://projects.eclipse.org/projects/ee4j.javamail
+ // https://mvnrepository.com/artifact/com.sun.mail
implementation "com.sun.mail:android-mail:$javamail_version"
implementation "com.sun.mail:android-activation:$javamail_version"
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index de04f36db4..a23f1423f7 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -160,6 +160,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/java/eu/faircode/email/ActivityDSN.java b/app/src/main/java/eu/faircode/email/ActivityDSN.java
new file mode 100644
index 0000000000..ff26d470d8
--- /dev/null
+++ b/app/src/main/java/eu/faircode/email/ActivityDSN.java
@@ -0,0 +1,93 @@
+package eu.faircode.email;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.res.AssetFileDescriptor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.TextView;
+
+import com.google.android.material.snackbar.Snackbar;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+
+import androidx.constraintlayout.widget.Group;
+
+public class ActivityDSN extends ActivityBase {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ getSupportActionBar().setSubtitle("DSN");
+ setContentView(R.layout.activity_dsn);
+
+ final TextView tvHeaders = findViewById(R.id.tvHeaders);
+ final ContentLoadingProgressBar pbWait = findViewById(R.id.pbWait);
+ final Group grpReady = findViewById(R.id.grpReady);
+
+ grpReady.setVisibility(View.GONE);
+
+ Uri uri = getIntent().getData();
+ if (uri == null) {
+ pbWait.setVisibility(View.GONE);
+ return;
+ } else
+ pbWait.setVisibility(View.VISIBLE);
+
+ Log.i("Disposition uri=" + uri);
+
+ Bundle args = new Bundle();
+ args.putParcelable("uri", uri);
+
+ new SimpleTask() {
+ @Override
+ protected void onPostExecute(Bundle args) {
+ pbWait.setVisibility(View.GONE);
+ }
+
+ @Override
+ protected Result onExecute(Context context, Bundle args) throws Throwable {
+ Uri uri = args.getParcelable("uri");
+
+ if ("file".equals(uri.getScheme()))
+ throw new IllegalArgumentException(context.getString(R.string.title_no_stream));
+
+ Result result = new Result();
+
+ ContentResolver resolver = context.getContentResolver();
+ AssetFileDescriptor descriptor = resolver.openTypedAssetFileDescriptor(uri, "*/*", null);
+ try (InputStream is = new BufferedInputStream(descriptor.createInputStream())) {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ byte[] buffer = new byte[1024];
+ int length;
+ while ((length = is.read(buffer)) != -1)
+ bos.write(buffer, 0, length);
+ result.headers = bos.toString("UTF-8");
+ }
+
+ return result;
+ }
+
+ @Override
+ protected void onExecuted(Bundle args, Result result) {
+ tvHeaders.setText(result.headers);
+ grpReady.setVisibility(View.VISIBLE);
+ }
+
+ @Override
+ protected void onException(Bundle args, Throwable ex) {
+ if (ex instanceof IllegalArgumentException)
+ Snackbar.make(findViewById(android.R.id.content), ex.getMessage(), Snackbar.LENGTH_LONG).show();
+ else
+ Helper.unexpectedError(ActivityDSN.this, ActivityDSN.this, ex);
+ }
+ }.execute(this, args, "disposition:decode");
+ }
+
+ private class Result {
+ String headers;
+ }
+}
diff --git a/app/src/main/res/layout/activity_dsn.xml b/app/src/main/res/layout/activity_dsn.xml
new file mode 100644
index 0000000000..724779e4e3
--- /dev/null
+++ b/app/src/main/res/layout/activity_dsn.xml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file