Move code to upload messages to Backend implementations

This commit is contained in:
cketti 2018-06-17 17:43:32 +02:00
parent 80c76e6fb9
commit 455315f62e
13 changed files with 156 additions and 115 deletions

View file

@ -57,4 +57,10 @@ interface Backend {
@Throws(MessagingException::class)
fun fetchMessage(folderServerId: String, messageServerId: String, fetchProfile: FetchProfile): Message
@Throws(MessagingException::class)
fun findByMessageId(folderServerId: String, messageId: String): String?
@Throws(MessagingException::class)
fun uploadMessage(folderServerId: String, message: Message): String?
}

View file

@ -0,0 +1,19 @@
package com.fsck.k9.backend.imap
import com.fsck.k9.mail.Folder
import com.fsck.k9.mail.store.imap.ImapStore
internal class CommandFindByMessageId(private val imapStore: ImapStore) {
fun findByMessageId(folderServerId: String, messageId: String): String? {
val folder = imapStore.getFolder(folderServerId)
try {
folder.open(Folder.OPEN_MODE_RW)
return folder.getUidFromMessageId(messageId)
} finally {
folder.close()
}
}
}

View file

@ -0,0 +1,24 @@
package com.fsck.k9.backend.imap
import com.fsck.k9.mail.Folder
import com.fsck.k9.mail.Message
import com.fsck.k9.mail.store.imap.ImapStore
internal class CommandUploadMessage(private val imapStore: ImapStore) {
fun uploadMessage(folderServerId: String, message: Message): String? {
val folder = imapStore.getFolder(folderServerId)
try {
folder.open(Folder.OPEN_MODE_RW)
val localUid = message.uid
val uidMap = folder.appendMessages(listOf(message))
return uidMap[localUid]
} finally {
folder.close()
}
}
}

View file

@ -30,6 +30,8 @@ public class ImapBackend implements Backend {
private final CommandDeleteAll commandDeleteAll;
private final CommandSearch commandSearch;
private final CommandFetchMessage commandFetchMessage;
private final CommandFindByMessageId commandFindByMessageId;
private final CommandUploadMessage commandUploadMessage;
public ImapBackend(String accountName, BackendStorage backendStorage, ImapStore imapStore) {
@ -42,6 +44,8 @@ public class ImapBackend implements Backend {
commandDeleteAll = new CommandDeleteAll(imapStore);
commandSearch = new CommandSearch(imapStore);
commandFetchMessage = new CommandFetchMessage(imapStore);
commandFindByMessageId = new CommandFindByMessageId(imapStore);
commandUploadMessage = new CommandUploadMessage(imapStore);
}
@Override
@ -121,4 +125,16 @@ public class ImapBackend implements Backend {
@NotNull FetchProfile fetchProfile) throws MessagingException {
return commandFetchMessage.fetchMessage(folderServerId, messageServerId, fetchProfile);
}
@Nullable
@Override
public String findByMessageId(@NotNull String folderServerId, @NotNull String messageId) throws MessagingException {
return commandFindByMessageId.findByMessageId(folderServerId, messageId);
}
@Nullable
@Override
public String uploadMessage(@NotNull String folderServerId, @NotNull Message message) throws MessagingException {
return commandUploadMessage.uploadMessage(folderServerId, message);
}
}

View file

@ -77,4 +77,12 @@ class Pop3Backend(accountName: String, backendStorage: BackendStorage, pop3Store
override fun fetchMessage(folderServerId: String, messageServerId: String, fetchProfile: FetchProfile): Message {
return commandFetchMessage.fetchMessage(folderServerId, messageServerId, fetchProfile)
}
override fun findByMessageId(folderServerId: String, messageId: String): String? {
return null
}
override fun uploadMessage(folderServerId: String, message: Message): String? {
throw UnsupportedOperationException("not supported")
}
}

View file

@ -0,0 +1,23 @@
package com.fsck.k9.backend.webdav
import com.fsck.k9.mail.Folder
import com.fsck.k9.mail.Message
import com.fsck.k9.mail.store.webdav.WebDavStore
internal class CommandUploadMessage(private val webDavStore: WebDavStore) {
fun uploadMessage(folderServerId: String, message: Message): String? {
val folder = webDavStore.getFolder(folderServerId)
try {
folder.open(Folder.OPEN_MODE_RW)
folder.appendMessages(listOf(message))
return null
} finally {
folder.close()
}
}
}

View file

@ -20,6 +20,7 @@ class WebDavBackend(accountName: String, backendStorage: BackendStorage, webDavS
private val commandMoveOrCopyMessages = CommandMoveOrCopyMessages(webDavStore)
private val commandDeleteAll = CommandDeleteAll(webDavStore)
private val commandFetchMessage = CommandFetchMessage(webDavStore)
private val commandUploadMessage = CommandUploadMessage(webDavStore)
override val supportsSeenFlag: Boolean = true
override val supportsExpunge: Boolean = true
@ -82,4 +83,12 @@ class WebDavBackend(accountName: String, backendStorage: BackendStorage, webDavS
override fun fetchMessage(folderServerId: String, messageServerId: String, fetchProfile: FetchProfile): Message {
return commandFetchMessage.fetchMessage(folderServerId, messageServerId, fetchProfile)
}
override fun findByMessageId(folderServerId: String, messageId: String): String? {
return null
}
override fun uploadMessage(folderServerId: String, message: Message): String? {
return commandUploadMessage.uploadMessage(folderServerId, message)
}
}

View file

@ -1425,7 +1425,6 @@ public class MessagingController {
* TODO update the local message UID instead of deleting it
*/
void processPendingAppend(PendingAppend command, Account account) throws MessagingException {
Folder remoteFolder = null;
LocalFolder localFolder = null;
try {
@ -1440,38 +1439,31 @@ public class MessagingController {
return;
}
RemoteStore remoteStore = account.getRemoteStore();
remoteFolder = remoteStore.getFolder(folder);
if (!remoteFolder.exists()) {
Timber.w("Remote folder doesn't exist: %s", folder);
return;
}
remoteFolder.open(Folder.OPEN_MODE_RW);
if (remoteFolder.getMode() != Folder.OPEN_MODE_RW) {
return;
}
Message remoteMessage = null;
if (!localMessage.getUid().startsWith(K9.LOCAL_UID_PREFIX)) {
remoteMessage = remoteFolder.getMessage(localMessage.getUid());
//FIXME: This should never happen. Throw in debug builds.
return;
}
if (remoteMessage == null) {
Backend backend = getBackend(account);
if (localMessage.isSet(Flag.X_REMOTE_COPY_STARTED)) {
Timber.w("Local message with uid %s has flag %s already set, checking for remote message with " +
"same message id", localMessage.getUid(), X_REMOTE_COPY_STARTED);
String rUid = remoteFolder.getUidFromMessageId(localMessage);
if (rUid != null) {
String messageServerId = backend.findByMessageId(folder, localMessage.getMessageId());
if (messageServerId != null) {
Timber.w("Local message has flag %s already set, and there is a remote message with uid %s, " +
"assuming message was already copied and aborting this copy",
X_REMOTE_COPY_STARTED, rUid);
X_REMOTE_COPY_STARTED, messageServerId);
String oldUid = localMessage.getUid();
localMessage.setUid(rUid);
localMessage.setUid(messageServerId);
localFolder.changeUid(localMessage);
for (MessagingListener l : getListeners()) {
l.messageUidChanged(account, folder, oldUid, localMessage.getUid());
}
return;
} else {
Timber.w("No remote message with message-id found, proceeding with append");
@ -1487,70 +1479,22 @@ public class MessagingController {
localFolder.fetch(Collections.singletonList(localMessage), fp, null);
String oldUid = localMessage.getUid();
localMessage.setFlag(Flag.X_REMOTE_COPY_STARTED, true);
remoteFolder.appendMessages(Collections.singletonList(localMessage));
if (localMessage.getUid().startsWith(K9.LOCAL_UID_PREFIX)) {
String messageServerId = backend.uploadMessage(folder, localMessage);
if (messageServerId == null) {
// We didn't get the server UID of the uploaded message. Remove the local message now. The uploaded
// version will be downloaded during the next sync.
localFolder.destroyMessages(Collections.singletonList(localMessage));
} else {
localMessage.setUid(messageServerId);
localFolder.changeUid(localMessage);
for (MessagingListener l : getListeners()) {
l.messageUidChanged(account, folder, oldUid, localMessage.getUid());
}
}
} else {
/*
* If the remote message exists we need to determine which copy to keep.
*/
/*
* See if the remote message is newer than ours.
*/
FetchProfile fp = new FetchProfile();
fp.add(FetchProfile.Item.ENVELOPE);
remoteFolder.fetch(Collections.singletonList(remoteMessage), fp, null);
Date localDate = localMessage.getInternalDate();
Date remoteDate = remoteMessage.getInternalDate();
if (remoteDate != null && remoteDate.compareTo(localDate) > 0) {
/*
* If the remote message is newer than ours we'll just
* delete ours and move on. A sync will get the server message
* if we need to be able to see it.
*/
localMessage.destroy();
} else {
/*
* Otherwise we'll upload our message and then delete the remote message.
*/
fp = new FetchProfile();
fp.add(FetchProfile.Item.BODY);
localFolder.fetch(Collections.singletonList(localMessage), fp, null);
String oldUid = localMessage.getUid();
localMessage.setFlag(Flag.X_REMOTE_COPY_STARTED, true);
remoteFolder.appendMessages(Collections.singletonList(localMessage));
if (localMessage.getUid().startsWith(K9.LOCAL_UID_PREFIX)) {
// We didn't get the server UID of the uploaded message. Remove the local message now. The
// uploaded version will be downloaded during the next sync.
localFolder.destroyMessages(Collections.singletonList(localMessage));
} else {
localFolder.changeUid(localMessage);
for (MessagingListener l : getListeners()) {
l.messageUidChanged(account, folder, oldUid, localMessage.getUid());
}
}
if (remoteDate != null) {
remoteMessage.setFlag(Flag.DELETED, true);
if (Expunge.EXPUNGE_IMMEDIATELY == account.getExpungePolicy()) {
remoteFolder.expungeUids(Collections.singletonList(remoteMessage.getUid()));
}
}
}
}
} finally {
closeFolder(remoteFolder);
closeFolder(localFolder);
}
}

View file

@ -1775,7 +1775,7 @@ public class LocalFolder extends Folder<LocalMessage> {
}
@Override
public String getUidFromMessageId(Message message) throws MessagingException {
public String getUidFromMessageId(String messageId) throws MessagingException {
throw new MessagingException("Cannot call getUidFromMessageId on LocalFolder");
}

View file

@ -111,7 +111,7 @@ public abstract class Folder<T extends Message> {
public abstract void setFlags(Set<Flag> flags, boolean value) throws MessagingException;
public abstract String getUidFromMessageId(Message message) throws MessagingException;
public abstract String getUidFromMessageId(String messageId) throws MessagingException;
public void expunge() throws MessagingException
{}

View file

@ -1177,8 +1177,8 @@ public class ImapFolder extends Folder<ImapMessage> {
String newUid = appendList.getString(2);
if (!TextUtils.isEmpty(newUid)) {
message.setUid(newUid);
uidMap.put(message.getUid(), newUid);
message.setUid(newUid);
continue;
}
}
@ -1189,7 +1189,8 @@ public class ImapFolder extends Folder<ImapMessage> {
* This part is executed in case the server does not support UIDPLUS or does
* not implement the APPENDUID response code.
*/
String newUid = getUidFromMessageId(message);
String messageId = extractMessageId(message);
String newUid = messageId != null ? getUidFromMessageId(messageId) : null;
if (K9MailLib.isDebug()) {
Timber.d("Got UID %s for message for %s", newUid, getLogId());
}
@ -1211,22 +1212,13 @@ public class ImapFolder extends Folder<ImapMessage> {
}
}
@Override
public String getUidFromMessageId(Message message) throws MessagingException {
/*
* Try to find the UID of the message we just appended using the
* Message-ID header.
*/
private String extractMessageId(Message message) {
String[] messageIdHeader = message.getHeader("Message-ID");
if (messageIdHeader.length == 0) {
if (K9MailLib.isDebug()) {
Timber.d("Did not get a message-id in order to search for UID for %s", getLogId());
}
return null;
return messageIdHeader.length == 0 ? null : messageIdHeader[0];
}
String messageId = messageIdHeader[0];
@Override
public String getUidFromMessageId(String messageId) throws MessagingException {
if (K9MailLib.isDebug()) {
Timber.d("Looking for UID for message with message-id %s for %s", messageId, getLogId());
}

View file

@ -533,7 +533,7 @@ public class Pop3Folder extends Folder<Pop3Message> {
}
@Override
public String getUidFromMessageId(Message message) throws MessagingException {
public String getUidFromMessageId(String messageId) throws MessagingException {
return null;
}

View file

@ -700,7 +700,7 @@ public class WebDavFolder extends Folder<WebDavMessage> {
}
@Override
public String getUidFromMessageId(Message message) throws MessagingException {
public String getUidFromMessageId(String messageId) throws MessagingException {
Timber.e("Unimplemented method getUidFromMessageId in WebDavStore.WebDavFolder could lead to duplicate messages "
+ " being uploaded to the Sent folder");
return null;