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
Rewrite IMAP expunge #2927
Rewrite IMAP expunge #2927
Conversation
b84a2cd
to
e137f12
Compare
@@ -998,6 +998,42 @@ public LocalMessage doDbWork(final SQLiteDatabase db) throws WrappedException, U | |||
} | |||
} | |||
|
|||
public Set<Long> getDeletedMessageUids() throws MessagingException { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is very similar to the method above. It should be possible to use one underlying method for most of this and just passing in a different query.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm also grumpy that there's no test, but there's no test for any LocalFolder stuff. Maybe I should look at that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@philipwhiuk done !
@@ -693,7 +693,7 @@ public void synchronizeMailboxSynchronous_withAccountPolicySetToExpungeOnPoll_sh | |||
|
|||
controller.synchronizeMailboxSynchronous(account, FOLDER_NAME, listener, null); | |||
|
|||
verify(remoteFolder).expunge(); | |||
verify(remoteFolder).expunge(anySet()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
anySet()
is pretty weak. Can't we verify we pass in the right IDs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
e137f12
to
e12d6b6
Compare
@@ -113,7 +113,7 @@ public abstract void setFlags(List<? extends Message> messages, Set<Flag> flags, | |||
|
|||
public abstract String getUidFromMessageId(Message message) throws MessagingException; | |||
|
|||
public void expunge() throws MessagingException | |||
public void expunge(List<Long> knownDeletedUids) throws MessagingException |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With the Folder
abstraction UIDs are opaque strings. UIDs being numbers is an implementation detail of ImapFolder
. So until we can replace this interface with something more flexible let's keep this interface clean.
Also, sometimes (e.g. when emptying the Trash folder) an unconstrained EXPUNGE makes sense. So I'd keep the original method and add a new one that better describes what it is about. My suggestion:
public void expungeUids(List<String> uids) throws MessagingException
} catch (IOException ioe) { | ||
throw ioExceptionHandler(connection, ioe); | ||
} | ||
} | ||
|
||
private void expungeWithoutUidPlus(Set<Long> knownDeletedUids) throws IOException, MessagingException { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know this is what RFC 4549 suggests when UID EXPUNGE
is not available, but I don't particularly like it. It has the potential to undelete messages when the connection is lost in the middle of the command sequence. It also requires passing all known deleted UIDs to the method.
By now UIDPLUS and with that UID EXPUNGE
should be widely available. So I'm fine with K-9 Mail not making the best effort when using legacy servers. Also, most users don't care about messages marked as deleted. So I'd say fall back to a plain EXPUNGE
when UID EXPUNGE
is not available. That is what we're doing right now, anyway.
@@ -1248,17 +1248,40 @@ public String getUidFromMessageId(Message message) throws MessagingException { | |||
} | |||
|
|||
@Override | |||
public void expunge() throws MessagingException { | |||
public void expunge(List<Long> knownDeletedUids) throws MessagingException { | |||
if (knownDeletedUids == null || knownDeletedUids.isEmpty()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Both cases are programming errors. So I'd rather throw an exception than returning silently.
|
||
private void setFlagsInternal(Set<Long> uids, final Set<Flag> flags, boolean value) | ||
throws MessagingException { | ||
if (uids.isEmpty()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, this should never happen. If it does we want to know about it, so throw an exception.
@@ -1228,7 +1256,7 @@ private void assertCommandWithIdsIssued(String expectedCommand) throws Messaging | |||
String command = commandPrefixes.get(i) + | |||
" " + ImapUtility.join(",", commandUids.get(i)) + " " + | |||
commandSuffixes.get(i); | |||
if (command.equals(expectedCommand)) { | |||
if (command.trim().equals(expectedCommand)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd rather fix the construction of command
above than trimming the erroneously added space at the end.
@@ -803,7 +803,7 @@ Upload any local messages that are marked as PENDING_UPLOAD (Drafts, Sent, Trash | |||
|
|||
if (Expunge.EXPUNGE_ON_POLL == account.getExpungePolicy()) { | |||
Timber.d("SYNC: Expunging folder %s:%s", account.getDescription(), folder); | |||
remoteFolder.expunge(); | |||
remoteFolder.expunge(localFolder.getAllMessageUids(true)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Eventually I want to get rid of 'expunge on sync'. For now I think preserving the current behavior by calling expunge()
rather than expungeUids()
is fine.
@@ -1830,7 +1830,7 @@ void processPendingAppend(PendingAppend command, Account account) throws Messagi | |||
if (remoteDate != null) { | |||
remoteMessage.setFlag(Flag.DELETED, true); | |||
if (Expunge.EXPUNGE_IMMEDIATELY == account.getExpungePolicy()) { | |||
remoteFolder.expunge(); | |||
remoteFolder.expunge(localFolder.getAllMessageUids(true)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With my suggestions applied this should only pass the UID of the current message to expungeUids()
.
@@ -1914,7 +1916,7 @@ void processPendingMoveOrCopy(PendingMoveOrCopy command, Account account) throws | |||
} | |||
if (!isCopy && Expunge.EXPUNGE_IMMEDIATELY == account.getExpungePolicy()) { | |||
Timber.i("processingPendingMoveOrCopy expunging folder %s:%s", account.getDescription(), srcFolder); | |||
remoteSrcFolder.expunge(); | |||
remoteSrcFolder.expunge(localSrcFolder.getAllMessageUids(true)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With my suggestions applied this should only pass the UIDs of the moved messages to expungeUids()
.
@@ -2020,10 +2026,11 @@ void processPendingExpunge(PendingExpunge command, Account account) throws Messa | |||
if (remoteFolder.getMode() != Folder.OPEN_MODE_RW) { | |||
return; | |||
} | |||
remoteFolder.expunge(); | |||
remoteFolder.expunge(localFolder.getAllMessageUids(true)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a manually triggered expunge and should therefore unconditionally expunge messages, i.e. call expunge()
without arguments.
try { | ||
if (remoteFolder.exists()) { | ||
remoteFolder.open(Folder.OPEN_MODE_RW); | ||
remoteFolder.setFlags(Collections.singleton(Flag.DELETED), true); | ||
if (Expunge.EXPUNGE_IMMEDIATELY == account.getExpungePolicy()) { | ||
remoteFolder.expunge(); | ||
remoteFolder.expunge(localFolder.getAllMessageUids(true)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same, this should be expunge()
without arguments.
e12d6b6
to
31b7cf8
Compare
@cketti Added the changes |
👍 @philipwhiuk: Are you satisfied with the changes as well? |
This PR rewrites the
expunge()
method inImapFolder
to ensure that only messages that were marked with the\Deleted
flag by K-9 Mail are expunged. This process is described in section 4.2.4 of RFC 4549Same as #2701