From 2cf9c68040afd5e71e1849abf2f78adbf24d8a59 Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Mon, 24 Feb 2020 02:36:18 +0300 Subject: [PATCH] Implement MsgId.unlink() and use it in DeleteMsgOnImap Currently only trashed or hidden messages are deleted by DeleteMsgOnImap, so it is safe to remove database records. It is planned to delete messages on IMAP server after user-configurable time to cleanup the server even for messages displayed in chats. For such messages, we unlink them from the Message-ID, but keep the database record to display them. --- src/job.rs | 29 +++++++++++++++++++++++++++-- src/message.rs | 17 +++++++++++++++++ 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/src/job.rs b/src/job.rs index 2fb2174bc..521553f6b 100644 --- a/src/job.rs +++ b/src/job.rs @@ -462,7 +462,12 @@ impl Job { we delete the message from the server */ let mid = msg.rfc724_mid; let server_folder = msg.server_folder.as_ref().unwrap(); - let res = imap_inbox.delete_msg(context, &mid, server_folder, msg.server_uid); + let res = if msg.server_uid == 0 { + // Message is already deleted on IMAP server. + ImapActionResult::AlreadyDone + } else { + imap_inbox.delete_msg(context, &mid, server_folder, msg.server_uid) + }; match res { ImapActionResult::RetryLater => { return Status::RetryLater; @@ -473,7 +478,27 @@ impl Job { } } } - msg.id.delete_from_db(context); + if msg.chat_id.is_trash() || msg.hidden { + // Messages are stored in trash chat only to keep + // their server UID and Message-ID. Once message is + // deleted from the server, database record can be + // removed as well. + // + // Hidden messages are similar to trashed, but are + // related to some chat. We also delete their + // database records. + msg.id.delete_from_db(context); + } else { + // Remove server UID from the database record. + // + // We have either just removed the message from the + // server, in which case UID is not valid anymore, or + // we have more refernces to the same server UID, so + // we remove UID to reduce the number of messages + // pointing to the corresponding UID. Once the counter + // reaches zero, we will remove the message. + job_try!(msg.id.unlink(context)); + } Status::Finished(Ok(())) } else { /* eg. device messages have no Message-ID */ diff --git a/src/message.rs b/src/message.rs index 7a656e99c..9a0d5553c 100644 --- a/src/message.rs +++ b/src/message.rs @@ -119,6 +119,23 @@ impl MsgId { .ok(); } + /// Removes Message-ID, IMAP server UID, folder from the database + /// record. + /// + /// It is used to avoid trying to remove the message from the + /// server multiple times when there are multiple message records + /// pointing to the same server UID. + pub(crate) fn unlink(self, context: &Context) -> sql::Result<()> { + sql::execute( + context, + &context.sql, + "UPDATE msgs \ + SET rfc724_mid='', server_folder='', server_uid=0 \ + WHERE id=?", + params![self], + ) + } + /// Bad evil escape hatch. /// /// Avoid using this, eventually types should be cleaned up enough