diff --git a/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java b/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java index b3d0d3686..02c5312f5 100644 --- a/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java +++ b/app/core/src/main/java/com/fsck/k9/controller/MessagingController.java @@ -50,6 +50,7 @@ import com.fsck.k9.cache.EmailProviderCache; import com.fsck.k9.controller.ControllerExtension.ControllerInternals; import com.fsck.k9.controller.MessagingControllerCommands.PendingAppend; import com.fsck.k9.controller.MessagingControllerCommands.PendingCommand; +import com.fsck.k9.controller.MessagingControllerCommands.PendingDelete; import com.fsck.k9.controller.MessagingControllerCommands.PendingEmptyTrash; import com.fsck.k9.controller.MessagingControllerCommands.PendingExpunge; import com.fsck.k9.controller.MessagingControllerCommands.PendingMarkAllAsRead; @@ -1033,6 +1034,22 @@ public class MessagingController { backend.setFlag(command.folder, command.uids, command.flag, command.newState); } + private void queueDelete(final Account account, final String folderServerId, final List uids) { + putBackground("queueDelete " + account.getDescription() + ":" + folderServerId, null, new Runnable() { + @Override + public void run() { + PendingCommand command = PendingDelete.create(folderServerId, uids); + queuePendingCommand(account, command); + processPendingCommands(account); + } + }); + } + + void processPendingDelete(PendingDelete command, Account account) throws MessagingException { + Backend backend = getBackend(account); + backend.deleteMessages(command.folder, command.uids); + } + private void queueExpunge(final Account account, final String folderServerId) { putBackground("queueExpunge " + account.getDescription() + ":" + folderServerId, null, new Runnable() { @Override @@ -2221,7 +2238,7 @@ public class MessagingController { } else if (!syncedMessageUids.isEmpty()) { if (account.getDeletePolicy() == DeletePolicy.ON_DELETE) { if (folder.equals(account.getTrashFolder()) || !backend.isDeleteMoveToTrash()) { - queueSetFlag(account, folder, true, Flag.DELETED, syncedMessageUids); + queueDelete(account, folder, syncedMessageUids); } else { queueMoveOrCopy(account, folder, account.getTrashFolder(), false, syncedMessageUids, uidMap); diff --git a/app/core/src/main/java/com/fsck/k9/controller/MessagingControllerCommands.java b/app/core/src/main/java/com/fsck/k9/controller/MessagingControllerCommands.java index 9ac655054..e4475f111 100644 --- a/app/core/src/main/java/com/fsck/k9/controller/MessagingControllerCommands.java +++ b/app/core/src/main/java/com/fsck/k9/controller/MessagingControllerCommands.java @@ -13,6 +13,7 @@ public class MessagingControllerCommands { static final String COMMAND_APPEND = "append"; static final String COMMAND_MARK_ALL_AS_READ = "mark_all_as_read"; static final String COMMAND_SET_FLAG = "set_flag"; + static final String COMMAND_DELETE = "delete"; static final String COMMAND_EXPUNGE = "expunge"; static final String COMMAND_MOVE_OR_COPY = "move_or_copy"; static final String COMMAND_EMPTY_TRASH = "empty_trash"; @@ -158,6 +159,31 @@ public class MessagingControllerCommands { } } + public static class PendingDelete extends PendingCommand { + public final String folder; + public final List uids; + + + public static PendingDelete create(String folder, List uids) { + return new PendingDelete(folder, uids); + } + + private PendingDelete(String folder, List uids) { + this.folder = folder; + this.uids = uids; + } + + @Override + public String getCommandName() { + return COMMAND_DELETE; + } + + @Override + public void execute(MessagingController controller, Account account) throws MessagingException { + controller.processPendingDelete(this, account); + } + } + public static class PendingExpunge extends PendingCommand { public final String folder; diff --git a/app/core/src/main/java/com/fsck/k9/controller/PendingCommandSerializer.java b/app/core/src/main/java/com/fsck/k9/controller/PendingCommandSerializer.java index 27beff3d7..0427e7e9f 100644 --- a/app/core/src/main/java/com/fsck/k9/controller/PendingCommandSerializer.java +++ b/app/core/src/main/java/com/fsck/k9/controller/PendingCommandSerializer.java @@ -9,6 +9,7 @@ import java.util.Map; import com.fsck.k9.controller.MessagingControllerCommands.PendingAppend; import com.fsck.k9.controller.MessagingControllerCommands.PendingCommand; +import com.fsck.k9.controller.MessagingControllerCommands.PendingDelete; import com.fsck.k9.controller.MessagingControllerCommands.PendingEmptyTrash; import com.fsck.k9.controller.MessagingControllerCommands.PendingExpunge; import com.fsck.k9.controller.MessagingControllerCommands.PendingMarkAllAsRead; @@ -35,6 +36,7 @@ public class PendingCommandSerializer { adapters.put(MessagingControllerCommands.COMMAND_EXPUNGE, moshi.adapter(PendingExpunge.class)); adapters.put(MessagingControllerCommands.COMMAND_MARK_ALL_AS_READ, moshi.adapter(PendingMarkAllAsRead.class)); adapters.put(MessagingControllerCommands.COMMAND_SET_FLAG, moshi.adapter(PendingSetFlag.class)); + adapters.put(MessagingControllerCommands.COMMAND_DELETE, moshi.adapter(PendingDelete.class)); this.adapters = Collections.unmodifiableMap(adapters); } diff --git a/app/storage/src/main/java/com/fsck/k9/storage/StoreSchemaDefinition.java b/app/storage/src/main/java/com/fsck/k9/storage/StoreSchemaDefinition.java index 3753f4e9f..3dc815c22 100644 --- a/app/storage/src/main/java/com/fsck/k9/storage/StoreSchemaDefinition.java +++ b/app/storage/src/main/java/com/fsck/k9/storage/StoreSchemaDefinition.java @@ -12,7 +12,7 @@ import timber.log.Timber; class StoreSchemaDefinition implements SchemaDefinition { - static final int DB_VERSION = 68; + static final int DB_VERSION = 69; private final MigrationsHelper migrationsHelper; diff --git a/app/storage/src/main/java/com/fsck/k9/storage/migrations/MigrationTo69.kt b/app/storage/src/main/java/com/fsck/k9/storage/migrations/MigrationTo69.kt new file mode 100644 index 000000000..4ef11b9ab --- /dev/null +++ b/app/storage/src/main/java/com/fsck/k9/storage/migrations/MigrationTo69.kt @@ -0,0 +1,41 @@ +package com.fsck.k9.storage.migrations + +import android.content.ContentValues +import android.database.sqlite.SQLiteDatabase +import com.fsck.k9.controller.MessagingControllerCommands.PendingDelete +import com.fsck.k9.controller.MessagingControllerCommands.PendingSetFlag +import com.fsck.k9.controller.PendingCommandSerializer +import com.fsck.k9.mail.Flag + + +internal class MigrationTo69(private val db: SQLiteDatabase) { + private val serializer: PendingCommandSerializer = PendingCommandSerializer.getInstance() + + + fun createPendingDelete() { + val pendingSetFlagsToConvert = mutableListOf() + + db.rawQuery("SELECT id, command, data FROM pending_commands WHERE command = 'set_flag'", null).use { cursor -> + while (cursor.moveToNext()) { + val databaseId = cursor.getLong(0) + val commandName = cursor.getString(1) + val data = cursor.getString(2) + + val pendingSetFlag = serializer.unserialize(databaseId, commandName, data) as PendingSetFlag + if (pendingSetFlag.flag == Flag.DELETED && pendingSetFlag.newState) { + pendingSetFlagsToConvert.add(pendingSetFlag) + } + } + } + + for (pendingSetFlag in pendingSetFlagsToConvert) { + val pendingDelete = PendingDelete.create(pendingSetFlag.folder, pendingSetFlag.uids) + val contentValues = ContentValues().apply { + put("command", "delete") + put("data", serializer.serialize(pendingDelete)) + } + + db.update("pending_commands", contentValues, "id = ?", arrayOf(pendingSetFlag.databaseId.toString())) + } + } +} diff --git a/app/storage/src/main/java/com/fsck/k9/storage/migrations/Migrations.java b/app/storage/src/main/java/com/fsck/k9/storage/migrations/Migrations.java index cdf23ccf1..7b3bc52d1 100644 --- a/app/storage/src/main/java/com/fsck/k9/storage/migrations/Migrations.java +++ b/app/storage/src/main/java/com/fsck/k9/storage/migrations/Migrations.java @@ -94,6 +94,8 @@ public class Migrations { MigrationTo67.addTypeColumnToFoldersTable(db, migrationsHelper); case 67: MigrationTo68.addOutboxStateTable(db); + case 68: + new MigrationTo69(db).createPendingDelete(); } if (shouldBuildFtsTable) { diff --git a/backend/api/src/main/java/com/fsck/k9/backend/api/Backend.kt b/backend/api/src/main/java/com/fsck/k9/backend/api/Backend.kt index bdf68dd2d..2aa50955a 100644 --- a/backend/api/src/main/java/com/fsck/k9/backend/api/Backend.kt +++ b/backend/api/src/main/java/com/fsck/k9/backend/api/Backend.kt @@ -44,6 +44,9 @@ interface Backend { @Throws(MessagingException::class) fun expungeMessages(folderServerId: String, messageServerIds: List) + @Throws(MessagingException::class) + fun deleteMessages(folderServerId: String, messageServerIds: List) + @Throws(MessagingException::class) fun deleteAllMessages(folderServerId: String) diff --git a/backend/imap/src/main/java/com/fsck/k9/backend/imap/ImapBackend.java b/backend/imap/src/main/java/com/fsck/k9/backend/imap/ImapBackend.java index 01c7d1f89..856a32886 100644 --- a/backend/imap/src/main/java/com/fsck/k9/backend/imap/ImapBackend.java +++ b/backend/imap/src/main/java/com/fsck/k9/backend/imap/ImapBackend.java @@ -146,6 +146,12 @@ public class ImapBackend implements Backend { commandExpunge.expungeMessages(folderServerId, messageServerIds); } + @Override + public void deleteMessages(@NotNull String folderServerId, @NotNull List messageServerIds) + throws MessagingException { + commandSetFlag.setFlag(folderServerId, messageServerIds, Flag.DELETED, true); + } + @Override public void deleteAllMessages(@NotNull String folderServerId) throws MessagingException { commandDeleteAll.deleteAll(folderServerId); diff --git a/backend/pop3/src/main/java/com/fsck/k9/backend/pop3/Pop3Backend.kt b/backend/pop3/src/main/java/com/fsck/k9/backend/pop3/Pop3Backend.kt index 975225601..da9a61bd3 100644 --- a/backend/pop3/src/main/java/com/fsck/k9/backend/pop3/Pop3Backend.kt +++ b/backend/pop3/src/main/java/com/fsck/k9/backend/pop3/Pop3Backend.kt @@ -65,6 +65,10 @@ class Pop3Backend( throw UnsupportedOperationException("not supported") } + override fun deleteMessages(folderServerId: String, messageServerIds: List) { + commandSetFlag.setFlag(folderServerId, messageServerIds, Flag.DELETED, true) + } + override fun deleteAllMessages(folderServerId: String) { commandDeleteAll.deleteAll(folderServerId) } diff --git a/backend/webdav/src/main/java/com/fsck/k9/backend/webdav/WebDavBackend.kt b/backend/webdav/src/main/java/com/fsck/k9/backend/webdav/WebDavBackend.kt index 661860382..fc2dc8ad3 100644 --- a/backend/webdav/src/main/java/com/fsck/k9/backend/webdav/WebDavBackend.kt +++ b/backend/webdav/src/main/java/com/fsck/k9/backend/webdav/WebDavBackend.kt @@ -70,6 +70,10 @@ class WebDavBackend( throw UnsupportedOperationException("not supported") } + override fun deleteMessages(folderServerId: String, messageServerIds: List) { + commandSetFlag.setFlag(folderServerId, messageServerIds, Flag.DELETED, true) + } + override fun deleteAllMessages(folderServerId: String) { commandDeleteAll.deleteAll(folderServerId) }