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