diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 161ec4780f..b97187c875 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -52,9 +52,19 @@ + android:parentActivityName=".ActivityView"> + + + + + + + + + + diff --git a/app/src/main/java/eu/faircode/email/ActivityCompose.java b/app/src/main/java/eu/faircode/email/ActivityCompose.java index cfde557409..e2d38e80dc 100644 --- a/app/src/main/java/eu/faircode/email/ActivityCompose.java +++ b/app/src/main/java/eu/faircode/email/ActivityCompose.java @@ -19,9 +19,14 @@ package eu.faircode.email; Copyright 2018 by Marcel Bokhorst (M66B) */ +import android.content.Intent; +import android.net.Uri; import android.os.Bundle; +import android.text.TextUtils; import android.view.MenuItem; +import java.util.ArrayList; + import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentTransaction; import androidx.lifecycle.Lifecycle; @@ -42,8 +47,44 @@ public class ActivityCompose extends ActivityBase implements FragmentManager.OnB getSupportFragmentManager().addOnBackStackChangedListener(this); if (getSupportFragmentManager().getFragments().size() == 0) { + Bundle args; + if (Intent.ACTION_SEND.equals(getIntent().getAction()) || + Intent.ACTION_SENDTO.equals(getIntent().getAction()) || + Intent.ACTION_SEND_MULTIPLE.equals(getIntent().getAction())) { + args = new Bundle(); + + args.putString("action", "new"); + args.putLong("account", -1); + + if (getIntent().hasExtra(Intent.EXTRA_EMAIL)) + args.putString("to", TextUtils.join(", ", getIntent().getStringArrayExtra(Intent.EXTRA_EMAIL))); + + if (getIntent().hasExtra(Intent.EXTRA_CC)) + args.putString("cc", TextUtils.join(", ", getIntent().getStringArrayExtra(Intent.EXTRA_CC))); + + if (getIntent().hasExtra(Intent.EXTRA_BCC)) + args.putString("bcc", TextUtils.join(", ", getIntent().getStringArrayExtra(Intent.EXTRA_BCC))); + + if (getIntent().hasExtra(Intent.EXTRA_SUBJECT)) + args.putString("subject", getIntent().getStringExtra(Intent.EXTRA_SUBJECT)); + + if (getIntent().hasExtra(Intent.EXTRA_TEXT)) + args.putString("body", getIntent().getStringExtra(Intent.EXTRA_TEXT)); // Intent.EXTRA_HTML_TEXT + + if (getIntent().hasExtra(Intent.EXTRA_STREAM)) + if (Intent.ACTION_SEND_MULTIPLE.equals(getIntent().getAction())) + args.putParcelableArrayList("attachments", getIntent().getParcelableArrayListExtra(Intent.EXTRA_STREAM)); + else { + ArrayList uris = new ArrayList<>(); + uris.add((Uri) getIntent().getParcelableExtra(Intent.EXTRA_STREAM)); + args.putParcelableArrayList("attachments", uris); + } + + } else + args = getIntent().getExtras(); + FragmentCompose fragment = new FragmentCompose(); - fragment.setArguments(getIntent().getExtras()); + fragment.setArguments(args); FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction(); fragmentTransaction.replace(R.id.content_frame, fragment).addToBackStack("compose"); diff --git a/app/src/main/java/eu/faircode/email/DaoAccount.java b/app/src/main/java/eu/faircode/email/DaoAccount.java index 4a56a23741..71001c25a3 100644 --- a/app/src/main/java/eu/faircode/email/DaoAccount.java +++ b/app/src/main/java/eu/faircode/email/DaoAccount.java @@ -41,6 +41,9 @@ public interface DaoAccount { @Query("SELECT * FROM account WHERE id = :id") EntityAccount getAccount(long id); + @Query("SELECT * FROM account WHERE `primary`") + EntityAccount getPrimaryAccount(); + @Query("SELECT * FROM account WHERE `primary`") LiveData livePrimaryAccount(); diff --git a/app/src/main/java/eu/faircode/email/FragmentCompose.java b/app/src/main/java/eu/faircode/email/FragmentCompose.java index 627c92d04c..8c8036dd52 100644 --- a/app/src/main/java/eu/faircode/email/FragmentCompose.java +++ b/app/src/main/java/eu/faircode/email/FragmentCompose.java @@ -68,6 +68,7 @@ import java.util.List; import javax.mail.Address; import javax.mail.MessageRemovedException; +import javax.mail.internet.AddressException; import javax.mail.internet.InternetAddress; import androidx.annotation.NonNull; @@ -328,6 +329,12 @@ public class FragmentCompose extends FragmentEx { args.putLong("id", getArguments().getLong("id", -1)); args.putLong("account", getArguments().getLong("account", -1)); args.putLong("reference", getArguments().getLong("reference", -1)); + args.putString("to", getArguments().getString("to")); + args.putString("cc", getArguments().getString("cc")); + args.putString("bcc", getArguments().getString("bcc")); + args.putString("subject", getArguments().getString("subject")); + args.putString("body", getArguments().getString("body")); + args.putParcelableArrayList("attachments", getArguments().getParcelableArrayList("attachments")); draftLoader.load(this, args); } else { Bundle args = new Bundle(); @@ -455,92 +462,10 @@ public class FragmentCompose extends FragmentEx { new SimpleTask() { @Override protected Void onLoad(Context context, Bundle args) throws IOException { - Cursor cursor = null; - try { - Uri uri = args.getParcelable("uri"); - cursor = context.getContentResolver().query(uri, null, null, null, null, null); - if (cursor == null || !cursor.moveToFirst()) - return null; - - Long id = args.getLong("id"); - EntityAttachment attachment = new EntityAttachment(); - - DB db = DB.getInstance(context); - try { - db.beginTransaction(); - - EntityMessage draft = db.message().getMessage(id); - Log.i(Helper.TAG, "Attaching to id=" + draft.id); - - attachment.message = draft.id; - attachment.sequence = db.attachment().getAttachmentCount(draft.id) + 1; - attachment.name = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)); - - String extension = MimeTypeMap.getFileExtensionFromUrl(attachment.name.toLowerCase()); - if (extension != null) - attachment.type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension); - if (attachment.type == null) - attachment.type = "application/octet-stream"; - - String size = cursor.getString(cursor.getColumnIndex(OpenableColumns.SIZE)); - - attachment.size = (size == null ? null : Integer.parseInt(size)); - attachment.progress = 0; - - attachment.id = db.attachment().insertAttachment(attachment); - Log.i(Helper.TAG, "Created attachment seq=" + attachment.sequence + - " name=" + attachment.name + " type=" + attachment.type); - - db.setTransactionSuccessful(); - } finally { - db.endTransaction(); - } - - try { - File file = EntityAttachment.getFile(context, attachment.id); - - InputStream is = null; - OutputStream os = null; - try { - is = context.getContentResolver().openInputStream(uri); - os = new BufferedOutputStream(new FileOutputStream(file)); - - int size = 0; - byte[] buffer = new byte[ATTACHMENT_BUFFER_SIZE]; - for (int len = is.read(buffer); len != -1; len = is.read(buffer)) { - size += len; - os.write(buffer, 0, len); - - // Update progress - if (attachment.size != null) - db.attachment().setProgress(attachment.id, size * 100 / attachment.size); - } - - attachment.size = size; - attachment.progress = null; - attachment.available = true; - db.attachment().updateAttachment(attachment); - } finally { - try { - if (is != null) - is.close(); - } finally { - if (os != null) - os.close(); - } - } - } catch (Throwable ex) { - // Reset progress on failure - attachment.progress = null; - db.attachment().updateAttachment(attachment); - throw ex; - } - - return null; - } finally { - if (cursor != null) - cursor.close(); - } + Long id = args.getLong("id"); + Uri uri = args.getParcelable("uri"); + addAttachment(context, id, uri); + return null; } @Override @@ -570,6 +495,95 @@ public class FragmentCompose extends FragmentEx { actionLoader.load(this, args); } + private void addAttachment(Context context, long id, Uri uri) throws IOException { + EntityAttachment attachment = new EntityAttachment(); + + String name = null; + String s = null; + + Cursor cursor = null; + try { + cursor = context.getContentResolver().query(uri, null, null, null, null, null); + if (cursor != null && cursor.moveToFirst()) { + name = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)); + s = cursor.getString(cursor.getColumnIndex(OpenableColumns.SIZE)); + } + + } finally { + if (cursor != null) + cursor.close(); + } + + DB db = DB.getInstance(context); + try { + db.beginTransaction(); + + EntityMessage draft = db.message().getMessage(id); + Log.i(Helper.TAG, "Attaching to id=" + draft.id); + + attachment.message = draft.id; + attachment.sequence = db.attachment().getAttachmentCount(draft.id) + 1; + attachment.name = name; + + String extension = MimeTypeMap.getFileExtensionFromUrl(attachment.name.toLowerCase()); + if (extension != null) + attachment.type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension); + if (attachment.type == null) + attachment.type = "application/octet-stream"; + + + attachment.size = (s == null ? null : Integer.parseInt(s)); + attachment.progress = 0; + + attachment.id = db.attachment().insertAttachment(attachment); + Log.i(Helper.TAG, "Created attachment=" + attachment.name + ":" + attachment.sequence + " type=" + attachment.type); + + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + } + + try { + File file = EntityAttachment.getFile(context, attachment.id); + + InputStream is = null; + OutputStream os = null; + try { + is = context.getContentResolver().openInputStream(uri); + os = new BufferedOutputStream(new FileOutputStream(file)); + + int size = 0; + byte[] buffer = new byte[ATTACHMENT_BUFFER_SIZE]; + for (int len = is.read(buffer); len != -1; len = is.read(buffer)) { + size += len; + os.write(buffer, 0, len); + + // Update progress + if (attachment.size != null) + db.attachment().setProgress(attachment.id, size * 100 / attachment.size); + } + + attachment.size = size; + attachment.progress = null; + attachment.available = true; + db.attachment().updateAttachment(attachment); + } finally { + try { + if (is != null) + is.close(); + } finally { + if (os != null) + os.close(); + } + } + } catch (IOException ex) { + // Reset progress on failure + attachment.progress = null; + db.attachment().updateAttachment(attachment); + throw ex; + } + } + private SimpleTask draftLoader = new SimpleTask() { @Override protected EntityMessage onLoad(Context context, Bundle args) throws IOException { @@ -594,7 +608,14 @@ public class FragmentCompose extends FragmentEx { return draft; EntityMessage ref = db.message().getMessage(reference); - if (ref != null) { + if (ref == null) { + if (account < 0) { + EntityAccount a = db.account().getPrimaryAccount(); + if (a == null) + throw new IllegalArgumentException(context.getString(R.string.title_no_account)); + account = a.id; + } + } else { account = ref.account; // Reply to sender, not to known self @@ -626,7 +647,34 @@ public class FragmentCompose extends FragmentEx { draft.folder = drafts.id; draft.msgid = EntityMessage.generateMessageId(); // for multiple appends - if (ref != null) { + if (ref == null) { + try { + String to = args.getString("to"); + draft.to = (TextUtils.isEmpty(to) ? null : InternetAddress.parse(to)); + } catch (AddressException ex) { + Log.w(Helper.TAG, ex + "\n" + Log.getStackTraceString(ex)); + } + + try { + String cc = args.getString("cc"); + draft.cc = (TextUtils.isEmpty(cc) ? null : InternetAddress.parse(cc)); + } catch (AddressException ex) { + Log.w(Helper.TAG, ex + "\n" + Log.getStackTraceString(ex)); + } + + try { + String bcc = args.getString("bcc"); + draft.bcc = (TextUtils.isEmpty(bcc) ? null : InternetAddress.parse(bcc)); + } catch (AddressException ex) { + Log.w(Helper.TAG, ex + "\n" + Log.getStackTraceString(ex)); + } + + draft.subject = args.getString("subject"); + body = args.getString("body"); + if (!TextUtils.isEmpty(body)) + body = "
" + body.replaceAll("\\r?\\n", "
") + "
"; + + } else { draft.thread = ref.thread; if ("reply".equals(action) || "reply_all".equals(action)) { @@ -656,16 +704,19 @@ public class FragmentCompose extends FragmentEx { } } - if ("new".equals(action)) - body = ""; - draft.received = new Date().getTime(); draft.seen = false; draft.ui_seen = false; draft.ui_hide = false; draft.id = db.message().insertMessage(draft); - draft.write(context, body); + draft.write(context, body == null ? "" : body); + + if (args.containsKey("attachments")) { + ArrayList uris = args.getParcelableArrayList("attachments"); + for (Uri uri : uris) + addAttachment(context, draft.id, uri); + } EntityOperation.queue(db, draft, EntityOperation.ADD);