serialize PendingCommands as JSON
This commit is contained in:
parent
fd8e0b4123
commit
15f3ba6219
8 changed files with 305 additions and 327 deletions
|
@ -31,6 +31,7 @@ dependencies {
|
|||
compile 'com.splitwise:tokenautocomplete:2.0.7'
|
||||
compile 'de.cketti.safecontentresolver:safe-content-resolver-v14:0.9.0'
|
||||
compile 'com.github.amlcurran.showcaseview:library:5.4.1'
|
||||
compile 'com.squareup.moshi:moshi:1.2.0'
|
||||
|
||||
androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.1'
|
||||
|
||||
|
|
|
@ -56,6 +56,13 @@ import com.fsck.k9.R;
|
|||
import com.fsck.k9.activity.MessageReference;
|
||||
import com.fsck.k9.activity.setup.AccountSetupCheckSettings.CheckDirection;
|
||||
import com.fsck.k9.cache.EmailProviderCache;
|
||||
import com.fsck.k9.controller.MessagingControllerCommands.PendingAppend;
|
||||
import com.fsck.k9.controller.MessagingControllerCommands.PendingCommand;
|
||||
import com.fsck.k9.controller.MessagingControllerCommands.PendingEmptyTrash;
|
||||
import com.fsck.k9.controller.MessagingControllerCommands.PendingExpunge;
|
||||
import com.fsck.k9.controller.MessagingControllerCommands.PendingMarkAllAsRead;
|
||||
import com.fsck.k9.controller.MessagingControllerCommands.PendingMoveOrCopy;
|
||||
import com.fsck.k9.controller.MessagingControllerCommands.PendingSetFlag;
|
||||
import com.fsck.k9.helper.Contacts;
|
||||
import com.fsck.k9.mail.Address;
|
||||
import com.fsck.k9.mail.AuthenticationFailedException;
|
||||
|
@ -86,7 +93,6 @@ import com.fsck.k9.mailstore.LocalFolder;
|
|||
import com.fsck.k9.mailstore.LocalFolder.MoreMessages;
|
||||
import com.fsck.k9.mailstore.LocalMessage;
|
||||
import com.fsck.k9.mailstore.LocalStore;
|
||||
import com.fsck.k9.mailstore.LocalStore.PendingCommand;
|
||||
import com.fsck.k9.mailstore.MessageRemovalListener;
|
||||
import com.fsck.k9.mailstore.UnavailableStorageException;
|
||||
import com.fsck.k9.notification.NotificationController;
|
||||
|
@ -115,19 +121,8 @@ import com.fsck.k9.search.SqlQueryBuilder;
|
|||
public class MessagingController {
|
||||
public static final long INVALID_MESSAGE_ID = -1;
|
||||
|
||||
private static final String[] EMPTY_STRING_ARRAY = new String[0];
|
||||
private static final Set<Flag> SYNC_FLAGS = EnumSet.of(Flag.SEEN, Flag.FLAGGED, Flag.ANSWERED, Flag.FORWARDED);
|
||||
|
||||
private static final String PENDING_COMMAND_MOVE_OR_COPY = "com.fsck.k9.MessagingController.moveOrCopy";
|
||||
private static final String PENDING_COMMAND_MOVE_OR_COPY_BULK = "com.fsck.k9.MessagingController.moveOrCopyBulk";
|
||||
private static final String PENDING_COMMAND_MOVE_OR_COPY_BULK_NEW = "com.fsck.k9.MessagingController.moveOrCopyBulkNew";
|
||||
private static final String PENDING_COMMAND_EMPTY_TRASH = "com.fsck.k9.MessagingController.emptyTrash";
|
||||
private static final String PENDING_COMMAND_SET_FLAG_BULK = "com.fsck.k9.MessagingController.setFlagBulk";
|
||||
private static final String PENDING_COMMAND_SET_FLAG = "com.fsck.k9.MessagingController.setFlag";
|
||||
private static final String PENDING_COMMAND_APPEND = "com.fsck.k9.MessagingController.append";
|
||||
private static final String PENDING_COMMAND_MARK_ALL_AS_READ = "com.fsck.k9.MessagingController.markAllAsRead";
|
||||
private static final String PENDING_COMMAND_EXPUNGE = "com.fsck.k9.MessagingController.expunge";
|
||||
|
||||
|
||||
private static MessagingController inst = null;
|
||||
|
||||
|
@ -1726,13 +1721,11 @@ public class MessagingController {
|
|||
try {
|
||||
for (PendingCommand command : commands) {
|
||||
processingCommand = command;
|
||||
if (K9.DEBUG)
|
||||
if (K9.DEBUG) {
|
||||
Log.d(K9.LOG_TAG, "Processing pending command '" + command + "'");
|
||||
|
||||
String[] components = command.command.split("\\.");
|
||||
String commandTitle = components[components.length - 1];
|
||||
}
|
||||
for (MessagingListener l : getListeners()) {
|
||||
l.pendingCommandStarted(account, commandTitle);
|
||||
l.pendingCommandStarted(account, command.getCommandName());
|
||||
}
|
||||
/*
|
||||
* We specifically do not catch any exceptions here. If a command fails it is
|
||||
|
@ -1740,28 +1733,23 @@ public class MessagingController {
|
|||
* other command processes. This maintains the order of the commands.
|
||||
*/
|
||||
try {
|
||||
if (PENDING_COMMAND_APPEND.equals(command.command)) {
|
||||
processPendingAppend(command, account);
|
||||
} else if (PENDING_COMMAND_SET_FLAG_BULK.equals(command.command)) {
|
||||
processPendingSetFlag(command, account);
|
||||
} else if (PENDING_COMMAND_SET_FLAG.equals(command.command)) {
|
||||
processPendingSetFlagOld(command, account);
|
||||
} else if (PENDING_COMMAND_MARK_ALL_AS_READ.equals(command.command)) {
|
||||
processPendingMarkAllAsRead(command, account);
|
||||
} else if (PENDING_COMMAND_MOVE_OR_COPY_BULK.equals(command.command)) {
|
||||
processPendingMoveOrCopyOld2(command, account);
|
||||
} else if (PENDING_COMMAND_MOVE_OR_COPY_BULK_NEW.equals(command.command)) {
|
||||
processPendingMoveOrCopy(command, account);
|
||||
} else if (PENDING_COMMAND_MOVE_OR_COPY.equals(command.command)) {
|
||||
processPendingMoveOrCopyOld(command, account);
|
||||
} else if (PENDING_COMMAND_EMPTY_TRASH.equals(command.command)) {
|
||||
processPendingEmptyTrash(command, account);
|
||||
} else if (PENDING_COMMAND_EXPUNGE.equals(command.command)) {
|
||||
processPendingExpunge(command, account);
|
||||
if (command instanceof PendingAppend) {
|
||||
processPendingAppend((PendingAppend) command, account);
|
||||
} else if (command instanceof PendingSetFlag) {
|
||||
processPendingSetFlag((PendingSetFlag) command, account);
|
||||
} else if (command instanceof PendingMarkAllAsRead) {
|
||||
processPendingMarkAllAsRead((PendingMarkAllAsRead) command, account);
|
||||
} else if (command instanceof PendingMoveOrCopy) {
|
||||
processPendingMoveOrCopy((PendingMoveOrCopy) command, account);
|
||||
} else if (command instanceof PendingEmptyTrash) {
|
||||
processPendingEmptyTrash((PendingEmptyTrash) command, account);
|
||||
} else if (command instanceof PendingExpunge) {
|
||||
processPendingExpunge((PendingExpunge) command, account);
|
||||
}
|
||||
localStore.removePendingCommand(command);
|
||||
if (K9.DEBUG)
|
||||
if (K9.DEBUG) {
|
||||
Log.d(K9.LOG_TAG, "Done processing pending command '" + command + "'");
|
||||
}
|
||||
} catch (MessagingException me) {
|
||||
if (me.isPermanentFailure()) {
|
||||
addErrorMessage(account, null, me);
|
||||
|
@ -1774,7 +1762,7 @@ public class MessagingController {
|
|||
progress++;
|
||||
for (MessagingListener l : getListeners()) {
|
||||
l.synchronizeMailboxProgress(account, null, progress, todo);
|
||||
l.pendingCommandCompleted(account, commandTitle);
|
||||
l.pendingCommandCompleted(account, command.getCommandName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1798,13 +1786,13 @@ public class MessagingController {
|
|||
* created.
|
||||
* TODO update the local message UID instead of deleteing it
|
||||
*/
|
||||
private void processPendingAppend(PendingCommand command, Account account) throws MessagingException {
|
||||
private void processPendingAppend(PendingAppend command, Account account) throws MessagingException {
|
||||
Folder remoteFolder = null;
|
||||
LocalFolder localFolder = null;
|
||||
try {
|
||||
|
||||
String folder = command.arguments[0];
|
||||
String uid = command.arguments[1];
|
||||
String folder = command.folder;
|
||||
String uid = command.uid;
|
||||
|
||||
if (account.getErrorFolderName().equals(folder)) {
|
||||
return;
|
||||
|
@ -1924,16 +1912,7 @@ public class MessagingController {
|
|||
if (account.getErrorFolderName().equals(srcFolder)) {
|
||||
return;
|
||||
}
|
||||
PendingCommand command = new PendingCommand();
|
||||
command.command = PENDING_COMMAND_MOVE_OR_COPY_BULK_NEW;
|
||||
|
||||
int length = 4 + uids.length;
|
||||
command.arguments = new String[length];
|
||||
command.arguments[0] = srcFolder;
|
||||
command.arguments[1] = destFolder;
|
||||
command.arguments[2] = Boolean.toString(isCopy);
|
||||
command.arguments[3] = Boolean.toString(false);
|
||||
System.arraycopy(uids, 0, command.arguments, 4, uids.length);
|
||||
PendingCommand command = MessagingControllerCommands.createMoveOrCopyBulk(srcFolder, destFolder, isCopy, uids);
|
||||
queuePendingCommand(account, command);
|
||||
}
|
||||
|
||||
|
@ -1945,72 +1924,22 @@ public class MessagingController {
|
|||
if (account.getErrorFolderName().equals(srcFolder)) {
|
||||
return;
|
||||
}
|
||||
PendingCommand command = new PendingCommand();
|
||||
command.command = PENDING_COMMAND_MOVE_OR_COPY_BULK_NEW;
|
||||
|
||||
int length = 4 + uidMap.keySet().size() + uidMap.values().size();
|
||||
command.arguments = new String[length];
|
||||
command.arguments[0] = srcFolder;
|
||||
command.arguments[1] = destFolder;
|
||||
command.arguments[2] = Boolean.toString(isCopy);
|
||||
command.arguments[3] = Boolean.toString(true);
|
||||
System.arraycopy(uidMap.keySet().toArray(EMPTY_STRING_ARRAY), 0, command.arguments, 4, uidMap.keySet().size());
|
||||
System.arraycopy(uidMap.values().toArray(EMPTY_STRING_ARRAY), 0, command.arguments, 4 + uidMap.keySet().size(), uidMap.values().size());
|
||||
PendingCommand command = MessagingControllerCommands.createMoveOrCopyBulk(srcFolder, destFolder, isCopy, uidMap);
|
||||
queuePendingCommand(account, command);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert pending command to new format and call
|
||||
* {@link #processPendingMoveOrCopy(PendingCommand, Account)}.
|
||||
*
|
||||
* <p>
|
||||
* TODO: This method is obsolete and is only for transition from K-9 4.0 to K-9 4.2
|
||||
* Eventually, it should be removed.
|
||||
* </p>
|
||||
*
|
||||
* @param command
|
||||
* Pending move/copy command in old format.
|
||||
* @param account
|
||||
* The account the pending command belongs to.
|
||||
*
|
||||
* @throws MessagingException
|
||||
* In case of an error.
|
||||
*/
|
||||
private void processPendingMoveOrCopyOld2(PendingCommand command, Account account) throws MessagingException {
|
||||
PendingCommand newCommand = new PendingCommand();
|
||||
int len = command.arguments.length;
|
||||
newCommand.command = PENDING_COMMAND_MOVE_OR_COPY_BULK_NEW;
|
||||
newCommand.arguments = new String[len + 1];
|
||||
newCommand.arguments[0] = command.arguments[0];
|
||||
newCommand.arguments[1] = command.arguments[1];
|
||||
newCommand.arguments[2] = command.arguments[2];
|
||||
newCommand.arguments[3] = Boolean.toString(false);
|
||||
System.arraycopy(command.arguments, 3, newCommand.arguments, 4, len - 3);
|
||||
|
||||
processPendingMoveOrCopy(newCommand, account);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a pending trash message command.
|
||||
*/
|
||||
private void processPendingMoveOrCopy(PendingCommand command, Account account) throws MessagingException {
|
||||
private void processPendingMoveOrCopy(PendingMoveOrCopy command, Account account) throws MessagingException {
|
||||
Folder remoteSrcFolder = null;
|
||||
Folder remoteDestFolder = null;
|
||||
LocalFolder localDestFolder;
|
||||
try {
|
||||
String srcFolder = command.arguments[0];
|
||||
String srcFolder = command.srcFolder;
|
||||
if (account.getErrorFolderName().equals(srcFolder)) {
|
||||
return;
|
||||
}
|
||||
String destFolder = command.arguments[1];
|
||||
String isCopyS = command.arguments[2];
|
||||
String hasNewUidsS = command.arguments[3];
|
||||
|
||||
boolean hasNewUids = false;
|
||||
if (hasNewUidsS != null) {
|
||||
hasNewUids = Boolean.parseBoolean(hasNewUidsS);
|
||||
}
|
||||
String destFolder = command.destFolder;
|
||||
boolean isCopy = command.isCopy;
|
||||
|
||||
Store remoteStore = account.getRemoteStore();
|
||||
remoteSrcFolder = remoteStore.getFolder(srcFolder);
|
||||
|
@ -2019,36 +1948,13 @@ public class MessagingController {
|
|||
localDestFolder = (LocalFolder) localStore.getFolder(destFolder);
|
||||
List<Message> messages = new ArrayList<>();
|
||||
|
||||
/*
|
||||
* We split up the localUidMap into two parts while sending the command, here we assemble it back.
|
||||
*/
|
||||
Map<String, String> localUidMap = new HashMap<>();
|
||||
if (hasNewUids) {
|
||||
int offset = (command.arguments.length - 4) / 2;
|
||||
|
||||
for (int i = 4; i < 4 + offset; i++) {
|
||||
localUidMap.put(command.arguments[i], command.arguments[i + offset]);
|
||||
|
||||
String uid = command.arguments[i];
|
||||
Collection<String> uids = command.newUidMap != null ? command.newUidMap.keySet() : Arrays.asList(command.uids);
|
||||
for (String uid : uids) {
|
||||
if (!uid.startsWith(K9.LOCAL_UID_PREFIX)) {
|
||||
messages.add(remoteSrcFolder.getMessage(uid));
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
for (int i = 4; i < command.arguments.length; i++) {
|
||||
String uid = command.arguments[i];
|
||||
if (!uid.startsWith(K9.LOCAL_UID_PREFIX)) {
|
||||
messages.add(remoteSrcFolder.getMessage(uid));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean isCopy = false;
|
||||
if (isCopyS != null) {
|
||||
isCopy = Boolean.parseBoolean(isCopyS);
|
||||
}
|
||||
|
||||
if (!remoteSrcFolder.exists()) {
|
||||
throw new MessagingException("processingPendingMoveOrCopy: remoteFolder " + srcFolder + " does not exist", true);
|
||||
}
|
||||
|
@ -2092,11 +1998,14 @@ public class MessagingController {
|
|||
* 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 (!localUidMap.isEmpty() && remoteUidMap != null && !remoteUidMap.isEmpty()) {
|
||||
if (command.newUidMap != null && remoteUidMap != null && !remoteUidMap.isEmpty()) {
|
||||
for (Map.Entry<String, String> entry : remoteUidMap.entrySet()) {
|
||||
String remoteSrcUid = entry.getKey();
|
||||
String localDestUid = localUidMap.get(remoteSrcUid);
|
||||
String newUid = entry.getValue();
|
||||
String localDestUid = command.newUidMap.get(remoteSrcUid);
|
||||
if (localDestUid == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Message localDestMessage = localDestFolder.getMessage(localDestUid);
|
||||
if (localDestMessage != null) {
|
||||
|
@ -2115,18 +2024,11 @@ public class MessagingController {
|
|||
}
|
||||
|
||||
private void queueSetFlag(final Account account, final String folderName,
|
||||
final String newState, final String flag, final String[] uids) {
|
||||
final boolean newState, final Flag flag, final String[] uids) {
|
||||
putBackground("queueSetFlag " + account.getDescription() + ":" + folderName, null, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
PendingCommand command = new PendingCommand();
|
||||
command.command = PENDING_COMMAND_SET_FLAG_BULK;
|
||||
int length = 3 + uids.length;
|
||||
command.arguments = new String[length];
|
||||
command.arguments[0] = folderName;
|
||||
command.arguments[1] = newState;
|
||||
command.arguments[2] = flag;
|
||||
System.arraycopy(uids, 0, command.arguments, 3, uids.length);
|
||||
PendingCommand command = MessagingControllerCommands.createSetFlag(folderName, newState, flag, uids);
|
||||
queuePendingCommand(account, command);
|
||||
processPendingCommands(account);
|
||||
}
|
||||
|
@ -2135,16 +2037,15 @@ public class MessagingController {
|
|||
/**
|
||||
* Processes a pending mark read or unread command.
|
||||
*/
|
||||
private void processPendingSetFlag(PendingCommand command, Account account) throws MessagingException {
|
||||
String folder = command.arguments[0];
|
||||
private void processPendingSetFlag(PendingSetFlag command, Account account) throws MessagingException {
|
||||
String folder = command.folder;
|
||||
|
||||
if (account.getErrorFolderName().equals(folder)) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean newState = Boolean.parseBoolean(command.arguments[1]);
|
||||
|
||||
Flag flag = Flag.valueOf(command.arguments[2]);
|
||||
boolean newState = command.newState;
|
||||
Flag flag = command.flag;
|
||||
|
||||
Store remoteStore = account.getRemoteStore();
|
||||
Folder remoteFolder = remoteStore.getFolder(folder);
|
||||
|
@ -2158,8 +2059,7 @@ public class MessagingController {
|
|||
return;
|
||||
}
|
||||
List<Message> messages = new ArrayList<>();
|
||||
for (int i = 3; i < command.arguments.length; i++) {
|
||||
String uid = command.arguments[i];
|
||||
for (String uid : command.uids) {
|
||||
if (!uid.startsWith(K9.LOCAL_UID_PREFIX)) {
|
||||
messages.add(remoteFolder.getMessage(uid));
|
||||
}
|
||||
|
@ -2174,61 +2074,18 @@ public class MessagingController {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: This method is obsolete and is only for transition from K-9 2.0 to K-9 2.1
|
||||
// Eventually, it should be removed
|
||||
private void processPendingSetFlagOld(PendingCommand command, Account account) throws MessagingException {
|
||||
String folder = command.arguments[0];
|
||||
String uid = command.arguments[1];
|
||||
|
||||
if (account.getErrorFolderName().equals(folder)) {
|
||||
return;
|
||||
}
|
||||
if (K9.DEBUG)
|
||||
Log.d(K9.LOG_TAG, "processPendingSetFlagOld: folder = " + folder + ", uid = " + uid);
|
||||
|
||||
boolean newState = Boolean.parseBoolean(command.arguments[2]);
|
||||
|
||||
Flag flag = Flag.valueOf(command.arguments[3]);
|
||||
Folder remoteFolder = null;
|
||||
try {
|
||||
Store remoteStore = account.getRemoteStore();
|
||||
remoteFolder = remoteStore.getFolder(folder);
|
||||
if (!remoteFolder.exists()) {
|
||||
return;
|
||||
}
|
||||
remoteFolder.open(Folder.OPEN_MODE_RW);
|
||||
if (remoteFolder.getMode() != Folder.OPEN_MODE_RW) {
|
||||
return;
|
||||
}
|
||||
Message remoteMessage = null;
|
||||
if (!uid.startsWith(K9.LOCAL_UID_PREFIX)) {
|
||||
remoteMessage = remoteFolder.getMessage(uid);
|
||||
}
|
||||
if (remoteMessage == null) {
|
||||
return;
|
||||
}
|
||||
remoteMessage.setFlag(flag, newState);
|
||||
} finally {
|
||||
closeFolder(remoteFolder);
|
||||
}
|
||||
}
|
||||
private void queueExpunge(final Account account, final String folderName) {
|
||||
putBackground("queueExpunge " + account.getDescription() + ":" + folderName, null, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
PendingCommand command = new PendingCommand();
|
||||
command.command = PENDING_COMMAND_EXPUNGE;
|
||||
|
||||
command.arguments = new String[1];
|
||||
|
||||
command.arguments[0] = folderName;
|
||||
PendingCommand command = MessagingControllerCommands.createExpunge(folderName);
|
||||
queuePendingCommand(account, command);
|
||||
processPendingCommands(account);
|
||||
}
|
||||
});
|
||||
}
|
||||
private void processPendingExpunge(PendingCommand command, Account account) throws MessagingException {
|
||||
String folder = command.arguments[0];
|
||||
private void processPendingExpunge(PendingExpunge command, Account account) throws MessagingException {
|
||||
String folder = command.folder;
|
||||
|
||||
if (account.getErrorFolderName().equals(folder)) {
|
||||
return;
|
||||
|
@ -2254,73 +2111,8 @@ public class MessagingController {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// TODO: This method is obsolete and is only for transition from K-9 2.0 to K-9 2.1
|
||||
// Eventually, it should be removed
|
||||
private void processPendingMoveOrCopyOld(PendingCommand command, Account account) throws MessagingException {
|
||||
String srcFolder = command.arguments[0];
|
||||
String uid = command.arguments[1];
|
||||
String destFolder = command.arguments[2];
|
||||
String isCopyS = command.arguments[3];
|
||||
|
||||
boolean isCopy = false;
|
||||
if (isCopyS != null) {
|
||||
isCopy = Boolean.parseBoolean(isCopyS);
|
||||
}
|
||||
|
||||
if (account.getErrorFolderName().equals(srcFolder)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Store remoteStore = account.getRemoteStore();
|
||||
Folder remoteSrcFolder = remoteStore.getFolder(srcFolder);
|
||||
Folder remoteDestFolder = remoteStore.getFolder(destFolder);
|
||||
|
||||
if (!remoteSrcFolder.exists()) {
|
||||
throw new MessagingException("processPendingMoveOrCopyOld: remoteFolder " + srcFolder + " does not exist", true);
|
||||
}
|
||||
remoteSrcFolder.open(Folder.OPEN_MODE_RW);
|
||||
if (remoteSrcFolder.getMode() != Folder.OPEN_MODE_RW) {
|
||||
throw new MessagingException("processPendingMoveOrCopyOld: could not open remoteSrcFolder " + srcFolder + " read/write", true);
|
||||
}
|
||||
|
||||
Message remoteMessage = null;
|
||||
if (!uid.startsWith(K9.LOCAL_UID_PREFIX)) {
|
||||
remoteMessage = remoteSrcFolder.getMessage(uid);
|
||||
}
|
||||
if (remoteMessage == null) {
|
||||
throw new MessagingException("processPendingMoveOrCopyOld: remoteMessage " + uid + " does not exist", true);
|
||||
}
|
||||
|
||||
if (K9.DEBUG)
|
||||
Log.d(K9.LOG_TAG, "processPendingMoveOrCopyOld: source folder = " + srcFolder
|
||||
+ ", uid = " + uid + ", destination folder = " + destFolder + ", isCopy = " + isCopy);
|
||||
|
||||
if (!isCopy && destFolder.equals(account.getTrashFolderName())) {
|
||||
if (K9.DEBUG)
|
||||
Log.d(K9.LOG_TAG, "processPendingMoveOrCopyOld doing special case for deleting message");
|
||||
|
||||
remoteMessage.delete(account.getTrashFolderName());
|
||||
remoteSrcFolder.close();
|
||||
return;
|
||||
}
|
||||
|
||||
remoteDestFolder.open(Folder.OPEN_MODE_RW);
|
||||
if (remoteDestFolder.getMode() != Folder.OPEN_MODE_RW) {
|
||||
throw new MessagingException("processPendingMoveOrCopyOld: could not open remoteDestFolder " + srcFolder + " read/write", true);
|
||||
}
|
||||
|
||||
if (isCopy) {
|
||||
remoteSrcFolder.copyMessages(Collections.singletonList(remoteMessage), remoteDestFolder);
|
||||
} else {
|
||||
remoteSrcFolder.moveMessages(Collections.singletonList(remoteMessage), remoteDestFolder);
|
||||
}
|
||||
remoteSrcFolder.close();
|
||||
remoteDestFolder.close();
|
||||
}
|
||||
|
||||
private void processPendingMarkAllAsRead(PendingCommand command, Account account) throws MessagingException {
|
||||
String folder = command.arguments[0];
|
||||
private void processPendingMarkAllAsRead(PendingMarkAllAsRead command, Account account) throws MessagingException {
|
||||
String folder = command.folder;
|
||||
Folder remoteFolder = null;
|
||||
LocalFolder localFolder = null;
|
||||
try {
|
||||
|
@ -2443,9 +2235,7 @@ public class MessagingController {
|
|||
if (K9.DEBUG) {
|
||||
Log.i(K9.LOG_TAG, "Marking all messages in " + account.getDescription() + ":" + folder + " as read");
|
||||
}
|
||||
PendingCommand command = new PendingCommand();
|
||||
command.command = PENDING_COMMAND_MARK_ALL_AS_READ;
|
||||
command.arguments = new String[] { folder };
|
||||
PendingCommand command = MessagingControllerCommands.createMarkAllAsRead(folder);
|
||||
queuePendingCommand(account, command);
|
||||
processPendingCommands(account);
|
||||
}
|
||||
|
@ -2534,7 +2324,7 @@ public class MessagingController {
|
|||
// Send flag change to server
|
||||
List<String> value = entry.getValue();
|
||||
String[] uids = value.toArray(new String[value.size()]);
|
||||
queueSetFlag(account, folderName, Boolean.toString(newState), flag.toString(), uids);
|
||||
queueSetFlag(account, folderName, newState, flag, uids);
|
||||
processPendingCommands(account);
|
||||
}
|
||||
}
|
||||
|
@ -2602,7 +2392,7 @@ public class MessagingController {
|
|||
uids[i] = messages.get(i).getUid();
|
||||
}
|
||||
|
||||
queueSetFlag(account, folderName, Boolean.toString(newState), flag.toString(), uids);
|
||||
queueSetFlag(account, folderName, newState, flag, uids);
|
||||
processPendingCommands(account);
|
||||
} catch (MessagingException me) {
|
||||
addErrorMessage(account, null, me);
|
||||
|
@ -3034,9 +2824,7 @@ public class MessagingController {
|
|||
if (K9.DEBUG)
|
||||
Log.i(K9.LOG_TAG, "Moved sent message to folder '" + account.getSentFolderName() + "' (" + localSentFolder.getId() + ") ");
|
||||
|
||||
PendingCommand command = new PendingCommand();
|
||||
command.command = PENDING_COMMAND_APPEND;
|
||||
command.arguments = new String[] { localSentFolder.getName(), message.getUid() };
|
||||
PendingCommand command = MessagingControllerCommands.createAppend(localSentFolder.getName(), message.getUid());
|
||||
queuePendingCommand(account, command);
|
||||
processPendingCommands(account);
|
||||
}
|
||||
|
@ -3635,25 +3423,19 @@ public class MessagingController {
|
|||
for (Message message : messages) {
|
||||
// If the message was in the Outbox, then it has been copied to local Trash, and has
|
||||
// to be copied to remote trash
|
||||
PendingCommand command = new PendingCommand();
|
||||
command.command = PENDING_COMMAND_APPEND;
|
||||
command.arguments =
|
||||
new String[] {
|
||||
account.getTrashFolderName(),
|
||||
message.getUid()
|
||||
};
|
||||
PendingCommand command = MessagingControllerCommands.createAppend(account.getTrashFolderName(), message.getUid());
|
||||
queuePendingCommand(account, command);
|
||||
}
|
||||
processPendingCommands(account);
|
||||
} else if (account.getDeletePolicy() == DeletePolicy.ON_DELETE) {
|
||||
if (folder.equals(account.getTrashFolderName())) {
|
||||
queueSetFlag(account, folder, Boolean.toString(true), Flag.DELETED.toString(), uids);
|
||||
queueSetFlag(account, folder, true, Flag.DELETED, uids);
|
||||
} else {
|
||||
queueMoveOrCopy(account, folder, account.getTrashFolderName(), false, uids, uidMap);
|
||||
}
|
||||
processPendingCommands(account);
|
||||
} else if (account.getDeletePolicy() == DeletePolicy.MARK_AS_READ) {
|
||||
queueSetFlag(account, folder, Boolean.toString(true), Flag.SEEN.toString(), uids);
|
||||
queueSetFlag(account, folder, true, Flag.SEEN, uids);
|
||||
processPendingCommands(account);
|
||||
} else {
|
||||
if (K9.DEBUG)
|
||||
|
@ -3683,7 +3465,7 @@ public class MessagingController {
|
|||
}
|
||||
|
||||
@SuppressWarnings("UnusedParameters") // for consistency with other PendingCommand methods
|
||||
private void processPendingEmptyTrash(PendingCommand command, Account account) throws MessagingException {
|
||||
private void processPendingEmptyTrash(PendingEmptyTrash command, Account account) throws MessagingException {
|
||||
Store remoteStore = account.getRemoteStore();
|
||||
|
||||
Folder remoteFolder = remoteStore.getFolder(account.getTrashFolderName());
|
||||
|
@ -3729,9 +3511,7 @@ public class MessagingController {
|
|||
}
|
||||
|
||||
if (!isTrashLocalOnly) {
|
||||
PendingCommand command = new PendingCommand();
|
||||
command.command = PENDING_COMMAND_EMPTY_TRASH;
|
||||
command.arguments = EMPTY_STRING_ARRAY;
|
||||
PendingCommand command = MessagingControllerCommands.createEmptyTrash();
|
||||
queuePendingCommand(account, command);
|
||||
processPendingCommands(account);
|
||||
}
|
||||
|
@ -4224,12 +4004,7 @@ public class MessagingController {
|
|||
localMessage.setFlag(Flag.X_DOWNLOADED_FULL, true);
|
||||
|
||||
if (saveRemotely) {
|
||||
PendingCommand command = new PendingCommand();
|
||||
command.command = PENDING_COMMAND_APPEND;
|
||||
command.arguments = new String[] {
|
||||
localFolder.getName(),
|
||||
localMessage.getUid()
|
||||
};
|
||||
PendingCommand command = MessagingControllerCommands.createAppend(localFolder.getName(), localMessage.getUid());
|
||||
queuePendingCommand(account, command);
|
||||
processPendingCommands(account);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,137 @@
|
|||
package com.fsck.k9.controller;
|
||||
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.fsck.k9.mail.Flag;
|
||||
|
||||
|
||||
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_EXPUNGE = "expunge";
|
||||
static final String COMMAND_MOVE_OR_COPY = "move_or_copy";
|
||||
static final String COMMAND_EMPTY_TRASH = "empty_trash";
|
||||
|
||||
|
||||
public static PendingSetFlag createSetFlag(String folder, boolean newState, Flag flag, String[] uids) {
|
||||
return new PendingSetFlag(folder, newState, flag, uids);
|
||||
}
|
||||
|
||||
public static PendingExpunge createExpunge(String folderName) {
|
||||
return new PendingExpunge(folderName);
|
||||
}
|
||||
|
||||
public static PendingMarkAllAsRead createMarkAllAsRead(String folder) {
|
||||
return new PendingMarkAllAsRead(folder);
|
||||
}
|
||||
|
||||
public static PendingAppend createAppend(String folderName, String uid) {
|
||||
return new PendingAppend(folderName, uid);
|
||||
}
|
||||
|
||||
public static PendingEmptyTrash createEmptyTrash() {
|
||||
return new PendingEmptyTrash();
|
||||
}
|
||||
|
||||
public static PendingMoveOrCopy createMoveOrCopyBulk(String srcFolder, String destFolder, boolean isCopy, Map<String, String> uidMap) {
|
||||
return new PendingMoveOrCopy(srcFolder, destFolder, isCopy, null, uidMap);
|
||||
}
|
||||
|
||||
public static PendingMoveOrCopy createMoveOrCopyBulk(String srcFolder, String destFolder, boolean isCopy, String[] uids) {
|
||||
return new PendingMoveOrCopy(srcFolder, destFolder, isCopy, uids, null);
|
||||
}
|
||||
|
||||
|
||||
public static abstract class PendingCommand {
|
||||
public transient long databaseId;
|
||||
|
||||
public abstract String getCommandName();
|
||||
|
||||
private PendingCommand() { }
|
||||
}
|
||||
|
||||
public static class PendingMoveOrCopy extends PendingCommand {
|
||||
public final String srcFolder;
|
||||
public final String destFolder;
|
||||
public final boolean isCopy;
|
||||
public final String[] uids;
|
||||
public final Map<String, String> newUidMap;
|
||||
|
||||
public PendingMoveOrCopy(
|
||||
String srcFolder, String destFolder, boolean isCopy, String[] uids, Map<String, String> newUidMap) {
|
||||
this.srcFolder = srcFolder;
|
||||
this.destFolder = destFolder;
|
||||
this.isCopy = isCopy;
|
||||
this.uids = uids;
|
||||
this.newUidMap = newUidMap;
|
||||
}
|
||||
|
||||
public String getCommandName() {
|
||||
return COMMAND_MOVE_OR_COPY;
|
||||
}
|
||||
}
|
||||
|
||||
public static class PendingEmptyTrash extends PendingCommand {
|
||||
public String getCommandName() {
|
||||
return COMMAND_EMPTY_TRASH;
|
||||
}
|
||||
}
|
||||
|
||||
public static class PendingSetFlag extends PendingCommand {
|
||||
public final String folder;
|
||||
public final boolean newState;
|
||||
public final Flag flag;
|
||||
public final String[] uids;
|
||||
|
||||
public PendingSetFlag(String folder, boolean newState, Flag flag, String[] uids) {
|
||||
this.folder = folder;
|
||||
this.newState = newState;
|
||||
this.flag = flag;
|
||||
this.uids = uids;
|
||||
}
|
||||
|
||||
public String getCommandName() {
|
||||
return COMMAND_SET_FLAG;
|
||||
}
|
||||
}
|
||||
|
||||
public static class PendingAppend extends PendingCommand {
|
||||
public final String folder;
|
||||
public final String uid;
|
||||
|
||||
public PendingAppend(String folder, String uid) {
|
||||
this.folder = folder;
|
||||
this.uid = uid;
|
||||
}
|
||||
|
||||
public String getCommandName() {
|
||||
return COMMAND_APPEND;
|
||||
}
|
||||
}
|
||||
|
||||
public static class PendingMarkAllAsRead extends PendingCommand {
|
||||
public final String folder;
|
||||
|
||||
public PendingMarkAllAsRead(String folder) {
|
||||
this.folder = folder;
|
||||
}
|
||||
|
||||
public String getCommandName() {
|
||||
return COMMAND_MARK_ALL_AS_READ;
|
||||
}
|
||||
}
|
||||
|
||||
public static class PendingExpunge extends PendingCommand {
|
||||
public final String folder;
|
||||
|
||||
public PendingExpunge(String folder) {
|
||||
this.folder = folder;
|
||||
}
|
||||
|
||||
public String getCommandName() {
|
||||
return COMMAND_EXPUNGE;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
package com.fsck.k9.controller;
|
||||
|
||||
|
||||
import java.io.IOError;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fsck.k9.controller.MessagingControllerCommands.PendingAppend;
|
||||
import com.fsck.k9.controller.MessagingControllerCommands.PendingCommand;
|
||||
import com.fsck.k9.controller.MessagingControllerCommands.PendingEmptyTrash;
|
||||
import com.fsck.k9.controller.MessagingControllerCommands.PendingExpunge;
|
||||
import com.fsck.k9.controller.MessagingControllerCommands.PendingMarkAllAsRead;
|
||||
import com.fsck.k9.controller.MessagingControllerCommands.PendingMoveOrCopy;
|
||||
import com.fsck.k9.controller.MessagingControllerCommands.PendingSetFlag;
|
||||
import com.squareup.moshi.JsonAdapter;
|
||||
import com.squareup.moshi.Moshi;
|
||||
|
||||
|
||||
public class PendingCommandSerializer {
|
||||
private static final PendingCommandSerializer INSTANCE = new PendingCommandSerializer();
|
||||
|
||||
|
||||
private final Map<String, JsonAdapter<? extends PendingCommand>> adapters;
|
||||
|
||||
|
||||
private PendingCommandSerializer() {
|
||||
Moshi moshi = new Moshi.Builder().build();
|
||||
HashMap<String, JsonAdapter<? extends PendingCommand>> adapters = new HashMap<>();
|
||||
|
||||
adapters.put(MessagingControllerCommands.COMMAND_MOVE_OR_COPY, moshi.adapter(PendingMoveOrCopy.class));
|
||||
adapters.put(MessagingControllerCommands.COMMAND_APPEND, moshi.adapter(PendingAppend.class));
|
||||
adapters.put(MessagingControllerCommands.COMMAND_EMPTY_TRASH, moshi.adapter(PendingEmptyTrash.class));
|
||||
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));
|
||||
|
||||
this.adapters = Collections.unmodifiableMap(adapters);
|
||||
}
|
||||
|
||||
|
||||
public static PendingCommandSerializer getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
|
||||
public <T extends PendingCommand> String serialize(T command) {
|
||||
// noinspection unchecked, we know the map has correctly matching adapters
|
||||
JsonAdapter<T> adapter = (JsonAdapter<T>) adapters.get(command.getCommandName());
|
||||
if (adapter == null) {
|
||||
throw new IllegalArgumentException("Unsupported pending command type!");
|
||||
}
|
||||
return adapter.toJson(command);
|
||||
}
|
||||
|
||||
public PendingCommand unserialize(long databaseId, String commandName, String data) {
|
||||
JsonAdapter<? extends PendingCommand> adapter = adapters.get(commandName);
|
||||
if (adapter == null) {
|
||||
throw new IllegalArgumentException("Unsupported pending command type!");
|
||||
}
|
||||
try {
|
||||
PendingCommand command = adapter.fromJson(data);
|
||||
command.databaseId = databaseId;
|
||||
return command;
|
||||
} catch (IOException e) {
|
||||
throw new IOError(e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -32,7 +32,8 @@ import android.util.Log;
|
|||
import com.fsck.k9.Account;
|
||||
import com.fsck.k9.K9;
|
||||
import com.fsck.k9.Preferences;
|
||||
import com.fsck.k9.helper.UrlEncodingHelper;
|
||||
import com.fsck.k9.controller.PendingCommandSerializer;
|
||||
import com.fsck.k9.controller.MessagingControllerCommands.PendingCommand;
|
||||
import com.fsck.k9.helper.Utility;
|
||||
import com.fsck.k9.mail.Flag;
|
||||
import com.fsck.k9.mail.Folder;
|
||||
|
@ -134,7 +135,7 @@ public class LocalStore extends Store implements Serializable {
|
|||
*/
|
||||
private static final int THREAD_FLAG_UPDATE_BATCH_SIZE = 500;
|
||||
|
||||
public static final int DB_VERSION = 55;
|
||||
public static final int DB_VERSION = 56;
|
||||
|
||||
|
||||
public static String getColumnNameForFlag(Flag flag) {
|
||||
|
@ -169,6 +170,7 @@ public class LocalStore extends Store implements Serializable {
|
|||
private final MessagePreviewCreator messagePreviewCreator;
|
||||
private final MessageFulltextCreator messageFulltextCreator;
|
||||
private final AttachmentCounter attachmentCounter;
|
||||
private final PendingCommandSerializer pendingCommandSerializer;
|
||||
|
||||
/**
|
||||
* local://localhost/path/to/database/uuid.db
|
||||
|
@ -187,6 +189,7 @@ public class LocalStore extends Store implements Serializable {
|
|||
messagePreviewCreator = MessagePreviewCreator.newInstance();
|
||||
messageFulltextCreator = MessageFulltextCreator.newInstance();
|
||||
attachmentCounter = AttachmentCounter.newInstance();
|
||||
pendingCommandSerializer = PendingCommandSerializer.getInstance();
|
||||
|
||||
database.open();
|
||||
}
|
||||
|
@ -464,7 +467,7 @@ public class LocalStore extends Store implements Serializable {
|
|||
Cursor cursor = null;
|
||||
try {
|
||||
cursor = db.query("pending_commands",
|
||||
new String[] { "id", "command", "arguments" },
|
||||
new String[] { "id", "command", "data" },
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
|
@ -472,14 +475,11 @@ public class LocalStore extends Store implements Serializable {
|
|||
"id ASC");
|
||||
List<PendingCommand> commands = new ArrayList<>();
|
||||
while (cursor.moveToNext()) {
|
||||
PendingCommand command = new PendingCommand();
|
||||
command.mId = cursor.getLong(0);
|
||||
command.command = cursor.getString(1);
|
||||
String arguments = cursor.getString(2);
|
||||
command.arguments = arguments.split(",");
|
||||
for (int i = 0; i < command.arguments.length; i++) {
|
||||
command.arguments[i] = Utility.fastUrlDecode(command.arguments[i]);
|
||||
}
|
||||
long databaseId = cursor.getLong(0);
|
||||
String commandName = cursor.getString(1);
|
||||
String data = cursor.getString(2);
|
||||
PendingCommand command = pendingCommandSerializer.unserialize(
|
||||
databaseId, commandName, data);
|
||||
commands.add(command);
|
||||
}
|
||||
return commands;
|
||||
|
@ -491,12 +491,9 @@ public class LocalStore extends Store implements Serializable {
|
|||
}
|
||||
|
||||
public void addPendingCommand(PendingCommand command) throws MessagingException {
|
||||
for (int i = 0; i < command.arguments.length; i++) {
|
||||
command.arguments[i] = UrlEncodingHelper.encodeUtf8(command.arguments[i]);
|
||||
}
|
||||
final ContentValues cv = new ContentValues();
|
||||
cv.put("command", command.command);
|
||||
cv.put("arguments", Utility.combine(command.arguments, ','));
|
||||
cv.put("command", command.getCommandName());
|
||||
cv.put("data", pendingCommandSerializer.serialize(command));
|
||||
database.execute(false, new DbCallback<Void>() {
|
||||
@Override
|
||||
public Void doDbWork(final SQLiteDatabase db) throws WrappedException {
|
||||
|
@ -510,7 +507,7 @@ public class LocalStore extends Store implements Serializable {
|
|||
database.execute(false, new DbCallback<Void>() {
|
||||
@Override
|
||||
public Void doDbWork(final SQLiteDatabase db) throws WrappedException {
|
||||
db.delete("pending_commands", "id = ?", new String[] { Long.toString(command.mId) });
|
||||
db.delete("pending_commands", "id = ?", new String[] { Long.toString(command.databaseId) });
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
@ -526,25 +523,6 @@ public class LocalStore extends Store implements Serializable {
|
|||
});
|
||||
}
|
||||
|
||||
public static class PendingCommand {
|
||||
private long mId;
|
||||
public String command;
|
||||
public String[] arguments;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(command);
|
||||
sb.append(": ");
|
||||
for (String argument : arguments) {
|
||||
sb.append(", ");
|
||||
sb.append(argument);
|
||||
//sb.append("\n");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMoveCapable() {
|
||||
return true;
|
||||
|
|
|
@ -195,7 +195,7 @@ class StoreSchemaDefinition implements LockableDatabase.SchemaDefinition {
|
|||
|
||||
db.execSQL("DROP TABLE IF EXISTS pending_commands");
|
||||
db.execSQL("CREATE TABLE pending_commands " +
|
||||
"(id INTEGER PRIMARY KEY, command TEXT, arguments TEXT)");
|
||||
"(id INTEGER PRIMARY KEY, command TEXT, data TEXT)");
|
||||
|
||||
db.execSQL("DROP TRIGGER IF EXISTS delete_folder");
|
||||
db.execSQL("CREATE TRIGGER delete_folder BEFORE DELETE ON folders BEGIN DELETE FROM messages WHERE old.id = folder_id; END;");
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
package com.fsck.k9.mailstore.migrations;
|
||||
|
||||
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
|
||||
|
||||
public class MigrationTo56 {
|
||||
public static void migratePendingCommands(SQLiteDatabase db) {
|
||||
// TODO actually migrate
|
||||
db.execSQL("DROP TABLE IF EXISTS pending_commands");
|
||||
db.execSQL("CREATE TABLE pending_commands " +
|
||||
"(id INTEGER PRIMARY KEY, command TEXT, data TEXT)");
|
||||
}
|
||||
}
|
|
@ -64,6 +64,9 @@ public class Migrations {
|
|||
MigrationTo54.addPreviewTypeColumn(db);
|
||||
case 54:
|
||||
MigrationTo55.createFtsSearchTable(db, migrationsHelper);
|
||||
case 55:
|
||||
MigrationTo56.migratePendingCommands(db);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue