Repository: thundernest/k-9
Issue: Deleted mail from inbox is doubled in trash directory

Please search to check for an existing issue (including closed issues, for which the fix may not have yet been released) before opening a new issue: https://github.com/k9mail/k-9/issues?q=is%3Aissue

### Expected behavior
When deleting one or more mails from inbox, I expect every deleted mail one time in trash directory.

### Actual behavior
When deleting one or more mails from inbox, every deleted mail exist in trash two times.

### Steps to reproduce
1. Wait for incomaing mail  (or send a test mail)
2. Delete a mail from inbox using symbol 'trash can' on left bottom.
3. Change to 'trash' directory. 
    In first moment the deleted mail appears only one time. After short time the deleted mail appears a
    second time in trash directory.
    After manually syncing the doubled mail disappears - the mail is only shown one time.

### Environment
K-9 Mail version: 5.207
I use the same email account with thunderbird on my desktop pc. These problems do not occur
using thunderbird on pc.

Android version: 7.0.0

Account type (IMAP, POP3, WebDAV/Exchange):
It is an IMAP Account.



Changed files:
app/core/src/main/java/com/fsck/k9/controller/MessagingController.java

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 337b8c54a..1e49338d9 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
@@ -89,6 +89,7 @@ import timber.log.Timber;
 
 import static com.fsck.k9.K9.MAX_SEND_ATTEMPTS;
 import static com.fsck.k9.helper.ExceptionHelper.getRootCauseMessage;
+import static com.fsck.k9.helper.Preconditions.checkNotNull;
 import static com.fsck.k9.mail.Flag.X_REMOTE_COPY_STARTED;
 import static com.fsck.k9.search.LocalSearchExtensions.getAccountsFromLocalSearch;
 
@@ -843,10 +844,10 @@ public class MessagingController {
     @VisibleForTesting
     void processPendingMoveOrCopy(Account account, String srcFolder, String destFolder, List<String> uids,
                                   MoveOrCopyFlavor operation, Map<String, String> newUidMap) throws MessagingException {
-        LocalFolder localDestFolder;
+        checkNotNull(newUidMap);
 
         LocalStore localStore = localStoreProvider.getInstance(account);
-        localDestFolder = localStore.getFolder(destFolder);
+        LocalFolder localDestFolder = localStore.getFolder(destFolder);
 
         Backend backend = getBackend(account);
 
@@ -871,28 +872,32 @@ public class MessagingController {
             backend.expungeMessages(srcFolder, uids);
         }
 
-        /*
-         * This next part is used to bring the local UIDs of the local destination folder
-         * upto speed with the remote UIDs of remote destination folder.
-         */
-        if (newUidMap != null && remoteUidMap != null && !remoteUidMap.isEmpty()) {
-            Timber.i("processingPendingMoveOrCopy: changing local uids of %d messages", remoteUidMap.size());
-            for (Entry<String, String> entry : remoteUidMap.entrySet()) {
-                String remoteSrcUid = entry.getKey();
-                String newUid = entry.getValue();
-                String localDestUid = newUidMap.get(remoteSrcUid);
-                if (localDestUid == null) {
-                    continue;
-                }
+        // TODO: Change Backend interface to ensure we never receive null for remoteUidMap
+        if (remoteUidMap == null) {
+            remoteUidMap = Collections.emptyMap();
+        }
 
-                Message localDestMessage = localDestFolder.getMessage(localDestUid);
-                if (localDestMessage != null) {
-                    localDestMessage.setUid(newUid);
-                    localDestFolder.changeUid((LocalMessage) localDestMessage);
-                    for (MessagingListener l : getListeners()) {
-                        l.messageUidChanged(account, destFolder, localDestUid, newUid);
-                    }
+        // Update local messages (that currently have local UIDs) with new server IDs
+        for (String uid : uids) {
+            String localUid = newUidMap.get(uid);
+            String newUid = remoteUidMap.get(uid);
+
+            LocalMessage localMessage = localDestFolder.getMessage(localUid);
+            if (localMessage == null) {
+                // Local message no longer exists
+                continue;
+            }
+
+            if (newUid != null) {
+                // Update local message with new server ID
+                localMessage.setUid(newUid);
+                localDestFolder.changeUid(localMessage);
+                for (MessagingListener l : getListeners()) {
+                    l.messageUidChanged(account, destFolder, localUid, newUid);
                 }
+            } else {
+                // New server ID wasn't provided. Remove local message.
+                localMessage.destroy();
             }
         }
     }