Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow messages to be moved/copied across accounts #2697

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1834,13 +1834,27 @@ private void queueMoveOrCopy(Account account, String srcFolder, String destFolde
queuePendingCommand(account, command);
}

private void queueMoveOrCopy(Account account, String srcFolder, String destFolder,
private void queueMoveOrCopy(Account srcAccount, String srcFolder, Account destAccount, String destFolder,
boolean isCopy, List<String> uids, Map<String, String> uidMap) {
if (uidMap == null || uidMap.isEmpty()) {
queueMoveOrCopy(account, srcFolder, destFolder, isCopy, uids);
if (srcAccount.equals(destAccount)) {
if (uidMap == null || uidMap.isEmpty()) {
queueMoveOrCopy(srcAccount, srcFolder, destFolder, isCopy, uids);
} else {
PendingCommand command = PendingMoveOrCopy.create(srcFolder, destFolder, isCopy, uidMap);
queuePendingCommand(srcAccount, command);
}
} else {
PendingCommand command = PendingMoveOrCopy.create(srcFolder, destFolder, isCopy, uidMap);
queuePendingCommand(account, command);
if (uidMap == null) {
return;
}

for (String uid : uidMap.values()) {
PendingCommand command = PendingAppend.create(destFolder, uid);
queuePendingCommand(destAccount, command);
}
if (!isCopy) {
queueSetFlag(srcAccount, srcFolder, true, Flag.DELETED, uids);
}
}
}

Expand Down Expand Up @@ -2876,7 +2890,7 @@ public boolean isCopyCapable(final Account account) {
}

public void moveMessages(final Account srcAccount, final String srcFolder,
List<MessageReference> messageReferences, final String destFolder) {
List<MessageReference> messageReferences, final Account destAccount, final String destFolder) {
actOnMessageGroup(srcAccount, srcFolder, messageReferences, new MessageActor() {
@Override
public void act(final Account account, LocalFolder messageFolder, final List<LocalMessage> messages) {
Expand All @@ -2885,15 +2899,15 @@ public void act(final Account account, LocalFolder messageFolder, final List<Loc
putBackground("moveMessages", null, new Runnable() {
@Override
public void run() {
moveOrCopyMessageSynchronous(account, srcFolder, messages, destFolder, false);
moveOrCopyMessageSynchronous(account, srcFolder, messages, destAccount, destFolder, false);
}
});
}
});
}

public void moveMessagesInThread(Account srcAccount, final String srcFolder,
final List<MessageReference> messageReferences, final String destFolder) {
final List<MessageReference> messageReferences, final Account destAccount, final String destFolder) {
actOnMessageGroup(srcAccount, srcFolder, messageReferences, new MessageActor() {
@Override
public void act(final Account account, LocalFolder messageFolder, final List<LocalMessage> messages) {
Expand All @@ -2904,7 +2918,8 @@ public void act(final Account account, LocalFolder messageFolder, final List<Loc
public void run() {
try {
List<Message> messagesInThreads = collectMessagesInThreads(account, messages);
moveOrCopyMessageSynchronous(account, srcFolder, messagesInThreads, destFolder, false);
moveOrCopyMessageSynchronous(account, srcFolder, messagesInThreads, destAccount, destFolder,
false);
} catch (MessagingException e) {
Timber.e(e, "Exception while moving messages");
}
Expand All @@ -2916,26 +2931,26 @@ public void run() {

public void moveMessage(final Account account, final String srcFolder, final MessageReference message,
final String destFolder) {
moveMessages(account, srcFolder, Collections.singletonList(message), destFolder);
moveMessages(account, srcFolder, Collections.singletonList(message), account, destFolder);
}

public void copyMessages(final Account srcAccount, final String srcFolder,
final List<MessageReference> messageReferences, final String destFolder) {
final List<MessageReference> messageReferences, final Account destAccount, final String destFolder) {
actOnMessageGroup(srcAccount, srcFolder, messageReferences, new MessageActor() {
@Override
public void act(final Account account, LocalFolder messageFolder, final List<LocalMessage> messages) {
putBackground("copyMessages", null, new Runnable() {
@Override
public void run() {
moveOrCopyMessageSynchronous(srcAccount, srcFolder, messages, destFolder, true);
moveOrCopyMessageSynchronous(srcAccount, srcFolder, messages, destAccount, destFolder, true);
}
});
}
});
}

public void copyMessagesInThread(Account srcAccount, final String srcFolder,
final List<MessageReference> messageReferences, final String destFolder) {
final List<MessageReference> messageReferences, final Account destAccount, final String destFolder) {
actOnMessageGroup(srcAccount, srcFolder, messageReferences, new MessageActor() {
@Override
public void act(final Account account, LocalFolder messageFolder, final List<LocalMessage> messages) {
Expand All @@ -2944,7 +2959,7 @@ public void act(final Account account, LocalFolder messageFolder, final List<Loc
public void run() {
try {
List<Message> messagesInThreads = collectMessagesInThreads(account, messages);
moveOrCopyMessageSynchronous(account, srcFolder, messagesInThreads, destFolder,
moveOrCopyMessageSynchronous(account, srcFolder, messagesInThreads, destAccount, destFolder,
true);
} catch (MessagingException e) {
Timber.e(e, "Exception while copying messages");
Expand All @@ -2958,24 +2973,33 @@ public void run() {
public void copyMessage(final Account account, final String srcFolder, final MessageReference message,
final String destFolder) {

copyMessages(account, srcFolder, Collections.singletonList(message), destFolder);
copyMessages(account, srcFolder, Collections.singletonList(message), account, destFolder);
}

private void moveOrCopyMessageSynchronous(final Account account, final String srcFolder,
final List<? extends Message> inMessages, final String destFolder, final boolean isCopy) {
private void moveOrCopyMessageSynchronous(final Account srcAccount, final String srcFolder,
final List<? extends Message> inMessages, final Account destAccount, final String destFolder,
final boolean isCopy) {
Timber.i("moveOrCopyMessageSynchronous: source account = %s, source folder = %s, %d messages, " +
"destination account = %s, destination folder = %s, isCopy = %s", srcAccount.getName(),
srcFolder, inMessages.size(), destAccount.getName(), destFolder, isCopy);

try {
LocalStore localStore = account.getLocalStore();
RemoteStore remoteStore = account.getRemoteStore();
if (!isCopy && !remoteStore.isMoveCapable()) {
LocalStore srcLocalStore = srcAccount.getLocalStore();
RemoteStore srcRemoteStore = srcAccount.getRemoteStore();
LocalStore destLocalStore = destAccount.getLocalStore();
RemoteStore destRemoteStore = destAccount.getRemoteStore();

if (!isCopy && (!srcRemoteStore.isMoveCapable() || !destRemoteStore.isMoveCapable())) {
Timber.e("Cannot move: incompatible source or destination store!");
return;
}
if (isCopy && !remoteStore.isCopyCapable()) {
if (isCopy && (!srcRemoteStore.isCopyCapable() || !destRemoteStore.isCopyCapable())) {
Timber.e("Cannot copy: incompatible source or destination store!");
return;
}

LocalFolder localSrcFolder = localStore.getFolder(srcFolder);
Folder localDestFolder = localStore.getFolder(destFolder);
LocalFolder localSrcFolder = srcLocalStore.getFolder(srcFolder);
LocalFolder localDestFolder = destLocalStore.getFolder(destFolder);

boolean unreadCountAffected = false;
List<String> uids = new LinkedList<>();
Expand All @@ -2998,9 +3022,6 @@ private void moveOrCopyMessageSynchronous(final Account account, final String sr
origUidMap.put(message.getUid(), message);
}

Timber.i("moveOrCopyMessageSynchronous: source folder = %s, %d messages, destination folder = %s, " +
"isCopy = %s", srcFolder, messages.size(), destFolder, isCopy);

Map<String, String> uidMap;

if (isCopy) {
Expand All @@ -3015,7 +3036,7 @@ private void moveOrCopyMessageSynchronous(final Account account, final String sr
// folder, notify the listeners.
int unreadMessageCount = localDestFolder.getUnreadMessageCount();
for (MessagingListener l : getListeners()) {
l.folderStatusChanged(account, destFolder, unreadMessageCount);
l.folderStatusChanged(srcAccount, destFolder, unreadMessageCount);
}
}
} else {
Expand All @@ -3024,28 +3045,29 @@ private void moveOrCopyMessageSynchronous(final Account account, final String sr
String origUid = entry.getKey();
Message message = entry.getValue();
for (MessagingListener l : getListeners()) {
l.messageUidChanged(account, srcFolder, origUid, message.getUid());
l.messageUidChanged(srcAccount, srcFolder, origUid, message.getUid());
}
}
unsuppressMessages(account, messages);
unsuppressMessages(srcAccount, messages);

if (unreadCountAffected) {
// If this move operation changes the unread count, notify the listeners
// that the unread count changed in both the source and destination folder.
int unreadMessageCountSrc = localSrcFolder.getUnreadMessageCount();
int unreadMessageCountDest = localDestFolder.getUnreadMessageCount();
for (MessagingListener l : getListeners()) {
l.folderStatusChanged(account, srcFolder, unreadMessageCountSrc);
l.folderStatusChanged(account, destFolder, unreadMessageCountDest);
l.folderStatusChanged(srcAccount, srcFolder, unreadMessageCountSrc);
l.folderStatusChanged(srcAccount, destFolder, unreadMessageCountDest);
}
}
}

List<String> origUidKeys = new ArrayList<>(origUidMap.keySet());
queueMoveOrCopy(account, srcFolder, destFolder, isCopy, origUidKeys, uidMap);
queueMoveOrCopy(srcAccount, srcFolder, destAccount, destFolder, isCopy, origUidKeys, uidMap);
}

processPendingCommands(account);
processPendingCommands(srcAccount);
processPendingCommandsSynchronous(destAccount);
} catch (UnavailableStorageException e) {
Timber.i("Failed to move/copy message because storage is not available - trying again later.");
throw new UnavailableAccountException(e);
Expand Down Expand Up @@ -3256,15 +3278,16 @@ private void deleteMessagesSynchronous(final Account account, final String folde
if (folder.equals(account.getTrashFolder())) {
queueSetFlag(account, folder, true, Flag.DELETED, syncedMessageUids);
} else {
queueMoveOrCopy(account, folder, account.getTrashFolder(), false,
syncedMessageUids, uidMap);
queueMoveOrCopy(account, folder, account.getTrashFolder(), false, syncedMessageUids);
}
processPendingCommands(account);
} else if (account.getDeletePolicy() == DeletePolicy.MARK_AS_READ) {
queueSetFlag(account, folder, true, Flag.SEEN, syncedMessageUids);
processPendingCommands(account);
} else {
Timber.d("Delete policy %s prevents delete from server", account.getDeletePolicy());
// TODO
// queueMoveOrCopy(account, folder, account, account.getTrashFolderName(), false, uids, uidMap);
}
}

Expand Down
Loading