diff --git a/app/src/main/java/eu/faircode/email/EntityOperation.java b/app/src/main/java/eu/faircode/email/EntityOperation.java index 101f76b131..68d9d17f86 100644 --- a/app/src/main/java/eu/faircode/email/EntityOperation.java +++ b/app/src/main/java/eu/faircode/email/EntityOperation.java @@ -178,15 +178,23 @@ public class EntityOperation { db.message().countMessageByMsgId(target.id, message.msgid) == 0) { long id = message.id; long uid = message.uid; + boolean seen = message.seen; + boolean ui_seen = message.ui_seen; message.id = null; message.account = target.account; message.folder = target.id; message.uid = null; + if (autoread) { + message.seen = true; + message.ui_seen = true; + } newid = db.message().insertMessage(message); message.id = id; message.account = source.account; message.folder = source.id; message.uid = uid; + message.seen = seen; + message.ui_seen = ui_seen; if (message.content) try { @@ -205,13 +213,20 @@ public class EntityOperation { } // Cross account move - if (!source.account.equals(target.account)) { - name = ADD; - folder = target.id; - jargs = new JSONArray(); - jargs.put(0, newid); // Can be null - jargs.put(1, autoread); - } + if (!source.account.equals(target.account)) + if (message.raw != null && message.raw) { + name = ADD; + folder = target.id; + jargs = new JSONArray(); + jargs.put(0, newid); // Can be null + jargs.put(1, autoread); + } else { + name = RAW; + jargs = new JSONArray(); + jargs.put(0, newid); // Can be null + jargs.put(1, autoread); + jargs.put(2, target.id); + } } else if (DELETE.equals(name)) db.message().setMessageUiHide(message.id, true); diff --git a/app/src/main/java/eu/faircode/email/FragmentMessages.java b/app/src/main/java/eu/faircode/email/FragmentMessages.java index 26b1cf5f81..d0c71da8f3 100644 --- a/app/src/main/java/eu/faircode/email/FragmentMessages.java +++ b/app/src/main/java/eu/faircode/email/FragmentMessages.java @@ -2107,18 +2107,6 @@ public class FragmentMessages extends FragmentBase { EntityMessage message = db.message().getMessage(target.id); if (message != null) { Log.i("Move id=" + target.id + " target=" + target.folder.name); - - // Cross account move: check if message downloaded - if (!target.folder.account.equals(message.account)) { - if (!message.content) - throw new IllegalArgumentException(getString(R.string.title_no_accross)); - - List attachments = db.attachment().getAttachments(message.id); - for (EntityAttachment attachment : attachments) - if (!attachment.available) - throw new IllegalArgumentException(getString(R.string.title_no_accross)); - } - EntityOperation.queue(context, db, message, EntityOperation.MOVE, target.folder.id); } } diff --git a/app/src/main/java/eu/faircode/email/ServiceSynchronize.java b/app/src/main/java/eu/faircode/email/ServiceSynchronize.java index 7400d843e5..1b205d595d 100644 --- a/app/src/main/java/eu/faircode/email/ServiceSynchronize.java +++ b/app/src/main/java/eu/faircode/email/ServiceSynchronize.java @@ -61,10 +61,13 @@ import com.sun.mail.util.MailConnectException; import org.json.JSONArray; import org.json.JSONException; +import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; +import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; import java.net.SocketException; import java.net.SocketTimeoutException; @@ -1496,7 +1499,7 @@ public class ServiceSynchronize extends LifecycleService { doHeaders(folder, ifolder, message, db); else if (EntityOperation.RAW.equals(op.name)) - doRaw(folder, ifolder, message, db); + doRaw(folder, ifolder, message, jargs, db); else if (EntityOperation.BODY.equals(op.name)) doBody(folder, ifolder, message, db); @@ -1537,19 +1540,27 @@ public class ServiceSynchronize extends LifecycleService { db.operation().deleteOperation(op.id); // Cleanup - if (message != null) - if (ex instanceof MessageRemovedException) { + if (message != null) { + if (ex instanceof MessageRemovedException) db.message().deleteMessage(message.id); - // Delete temporary copy in target folder - if (EntityOperation.MOVE.equals(op.name) && - jargs.length() > 2) - db.message().deleteMessage(jargs.getInt(2)); - if (EntityOperation.ADD.equals(op.name) && - jargs.length() > 0 && !jargs.isNull(0)) - db.message().deleteMessage(jargs.getInt(0)); - } else + Long newid = null; + + if (EntityOperation.MOVE.equals(op.name) && + jargs.length() > 2) + newid = jargs.getLong(2); + + if ((EntityOperation.ADD.equals(op.name) || + EntityOperation.RAW.equals(op.name)) && + jargs.length() > 0 && !jargs.isNull(0)) + newid = jargs.getLong(0); + + // Delete temporary copy in target folder + if (newid != null) { + db.message().deleteMessage(newid); db.message().setMessageUiHide(message.id, false); + } + } continue; } else if (ex instanceof MessagingException) { @@ -1673,21 +1684,41 @@ public class ServiceSynchronize extends LifecycleService { } private void doAdd(EntityFolder folder, Session isession, IMAPFolder ifolder, EntityMessage message, JSONArray jargs, DB db) throws MessagingException, JSONException, IOException { - if (!message.content) - throw new IllegalArgumentException("Message body missing"); + MimeMessage imessage; + if (folder.id.equals(message.folder)) { + if (!message.content) + throw new IllegalArgumentException("Message body missing"); - List attachments = db.attachment().getAttachments(message.id); - for (EntityAttachment attachment : attachments) - if (!attachment.available) - throw new IllegalArgumentException("Attachment missing"); + List attachments = db.attachment().getAttachments(message.id); + for (EntityAttachment attachment : attachments) + if (!attachment.available) + throw new IllegalArgumentException("Attachment missing"); - // Append message - MimeMessage imessage = MessageHelper.from(this, message, isession); + imessage = MessageHelper.from(this, message, isession); + } else { + // Cross account move + File file = EntityMessage.getRawFile(this, message.id); + if (!file.exists()) + throw new IllegalArgumentException("raw message file not found"); + + InputStream is = null; + try { + Log.i(folder.name + " reading " + file); + is = new BufferedInputStream(new FileInputStream(file)); + imessage = new MimeMessage(isession, is); + } finally { + if (is != null) + is.close(); + } + } + boolean autoread = false; if (jargs.length() > 1) { - boolean autoread = jargs.getBoolean(1); - if (autoread && !imessage.isSet(Flags.Flag.SEEN)) + autoread = jargs.getBoolean(1); + if (autoread && !imessage.isSet(Flags.Flag.SEEN)) { + Log.i(folder.name + " autoread"); imessage.setFlag(Flags.Flag.SEEN, true); + } } if (EntityFolder.DRAFTS.equals(folder.type)) { @@ -1698,8 +1729,15 @@ public class ServiceSynchronize extends LifecycleService { ifolder.appendMessages(new Message[]{imessage}); // Cross account move - if (!folder.id.equals(message.folder)) + if (!folder.id.equals(message.folder)) { + if (autoread) { + Log.i(folder.name + " queuing SEEN id=" + message.id); + EntityOperation.queue(this, db, message, EntityOperation.SEEN, true); + } + + Log.i(folder.name + " queuing DELETE id=" + message.id); EntityOperation.queue(this, db, message, EntityOperation.DELETE); + } } private void doMove(EntityFolder folder, Session isession, IMAPStore istore, IMAPFolder ifolder, EntityMessage message, JSONArray jargs, DB db) throws JSONException, MessagingException, IOException { @@ -1740,7 +1778,7 @@ public class ServiceSynchronize extends LifecycleService { } } - private void doDelete(EntityFolder folder, IMAPFolder ifolder, EntityMessage message, JSONArray jargs, DB db) throws MessagingException, JSONException { + private void doDelete(EntityFolder folder, IMAPFolder ifolder, EntityMessage message, JSONArray jargs, DB db) throws MessagingException { // Delete message if (message.msgid != null) { Message[] imessages = ifolder.search(new MessageIDTerm(message.msgid)); @@ -1953,7 +1991,7 @@ public class ServiceSynchronize extends LifecycleService { } } - private void doHeaders(EntityFolder folder, IMAPFolder ifolder, EntityMessage message, DB db) throws MessagingException, IOException { + private void doHeaders(EntityFolder folder, IMAPFolder ifolder, EntityMessage message, DB db) throws MessagingException { if (message.headers != null) return; @@ -1965,29 +2003,37 @@ public class ServiceSynchronize extends LifecycleService { db.message().setMessageHeaders(message.id, helper.getHeaders()); } - private void doRaw(EntityFolder folder, IMAPFolder ifolder, EntityMessage message, DB db) throws MessagingException, IOException { - if (message.raw) - return; - - Message imessage = ifolder.getMessageByUID(message.uid); - if (imessage == null) - throw new MessageRemovedException(); - - if (imessage instanceof MimeMessage) { - MimeMessage mmessage = (MimeMessage) imessage; + private void doRaw(EntityFolder folder, IMAPFolder ifolder, EntityMessage message, JSONArray jargs, DB db) throws MessagingException, IOException, JSONException { + if (message.raw == null || !message.raw) { + IMAPMessage imessage = (IMAPMessage) ifolder.getMessageByUID(message.uid); + if (imessage == null) + throw new MessageRemovedException(); File file = EntityMessage.getRawFile(this, message.id); OutputStream os = null; try { os = new BufferedOutputStream(new FileOutputStream(file)); - mmessage.writeTo(os); + imessage.writeTo(os); + db.message().setMessageRaw(message.id, true); } finally { if (os != null) os.close(); } + } - db.message().setMessageRaw(message.id, true); + if (jargs.length() > 0) { + long target = jargs.getLong(2); + jargs.remove(2); + Log.i(folder.name + " queuing ADD id=" + message.id + ":" + target); + + EntityOperation operation = new EntityOperation(); + operation.folder = target; + operation.message = message.id; + operation.name = EntityOperation.ADD; + operation.args = jargs.toString(); + operation.created = new Date().getTime(); + operation.id = db.operation().insertOperation(operation); } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 0a9a6d67a2..f9b91fbaaa 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -306,8 +306,7 @@ An outdated app sent a file path instead of a file stream Contact picker not available No internet connection - Moving across accounts requires all message content to be downloaded - Messages moved across accounts will not be identical after moving + Messages moved across accounts will be downloaded again causing and extra data usage Raw message saved Attachment saved Attachments saved