feat: move the messages only from INBOX and Spam folders

We do not try to delete resent messages
anymore. Previously resent messages
were distinguised by having duplicate Message-ID,
but future Date, but now we need to download
the message before we even see the Date.
We now move the message to the destination folder
but do not fetch it.

It may not be a good idea to delete
the duplicate in multi-device setups anyway,
because the device which has a message
may delete the duplicate of a message
the other device missed.

To avoid triggering IMAP busy move loop
described in the comments
we now only move the messages
from INBOX and Spam folders.
This commit is contained in:
link2xt
2025-03-11 05:16:35 +00:00
committed by l
parent f4938465c3
commit 2f2a147efb
14 changed files with 94 additions and 167 deletions

View File

@@ -1234,7 +1234,7 @@ impl Message {
/// `References` header is not taken into account.
pub async fn parent(&self, context: &Context) -> Result<Option<Message>> {
if let Some(in_reply_to) = &self.in_reply_to {
if let Some((msg_id, _ts_sent)) = rfc724_mid_exists(context, in_reply_to).await? {
if let Some(msg_id) = rfc724_mid_exists(context, in_reply_to).await? {
let msg = Message::load_from_db_optional(context, msg_id).await?;
return Ok(msg);
}
@@ -2043,13 +2043,13 @@ pub async fn estimate_deletion_cnt(
pub(crate) async fn rfc724_mid_exists(
context: &Context,
rfc724_mid: &str,
) -> Result<Option<(MsgId, i64)>> {
) -> Result<Option<MsgId>> {
Ok(rfc724_mid_exists_ex(context, rfc724_mid, "1")
.await?
.map(|(id, ts_sent, _)| (id, ts_sent)))
.map(|(id, _)| id))
}
/// Returns [MsgId] and "sent" timestamp of the most recent message with given `rfc724_mid`
/// Returns [MsgId] of the most recent message with given `rfc724_mid`
/// (Message-ID header) and bool `expr` result if such messages exists in the db.
///
/// * `expr`: SQL expression additionally passed into `SELECT`. Evaluated to `true` iff it is true
@@ -2058,7 +2058,7 @@ pub(crate) async fn rfc724_mid_exists_ex(
context: &Context,
rfc724_mid: &str,
expr: &str,
) -> Result<Option<(MsgId, i64, bool)>> {
) -> Result<Option<(MsgId, bool)>> {
let rfc724_mid = rfc724_mid.trim_start_matches('<').trim_end_matches('>');
if rfc724_mid.is_empty() {
warn!(context, "Empty rfc724_mid passed to rfc724_mid_exists");
@@ -2076,9 +2076,8 @@ pub(crate) async fn rfc724_mid_exists_ex(
(rfc724_mid,),
|row| {
let msg_id: MsgId = row.get(0)?;
let timestamp_sent: i64 = row.get(1)?;
let expr_res: bool = row.get(2)?;
Ok((msg_id, timestamp_sent, expr_res))
Ok((msg_id, expr_res))
},
)
.await?;
@@ -2098,7 +2097,7 @@ pub(crate) async fn get_by_rfc724_mids(
) -> Result<Option<Message>> {
let mut latest = None;
for id in mids.iter().rev() {
let Some((msg_id, _)) = rfc724_mid_exists(context, id).await? else {
let Some(msg_id) = rfc724_mid_exists(context, id).await? else {
continue;
};
let Some(msg) = Message::load_from_db_optional(context, msg_id).await? else {