mirror of
https://github.com/chatmail/core.git
synced 2026-04-25 01:16:29 +03:00
Mark messages as seen in IMAP loop
MarkseenMsgOnImap job, that was responsible for marking messages as seen on IMAP and sending MDNs, has been removed. Messages waiting to be marked as seen are now stored in a single-column imap_markseen table consisting of foreign keys pointing to corresponding imap table records. Messages are marked as seen in batches in the inbox loop. UIDs are grouped by folders to reduce the number of requests, including folder selection requests. UID grouping logic has been factored out of move_delete_messages into UidGrouper iterator to avoid code duplication. Messages are marked as seen right before fetching from the inbox folder. This ensures that even if new messages arrive into inbox while the connection has another folder selected to mark messages there, all messages are fetched before going IDLE. Ideally marking messages as seen should be done after fetching and moving, as it is a low-priority task, but this requires skipping IDLE if UIDNEXT has advanced since previous time inbox has been selected. This is outside of the scope of this change. MDNs are now queued independently of marking the messages as seen. SendMdn job is created directly rather than after marking the message as seen on IMAP. Previously sending MDNs was done in MarkseenMsgOnImap avoid duplicate MDN sending by setting $MDNSent flag together with \Seen flag and skipping MDN sending if the flag is already set. This is not the case anymore as $MDNSent flag support has been removed in9c077c98cdand duplicate MDN sending in multi-device case is avoided by synchronizing Seen status since833e5f46ccas long as the server supports CONDSTORE extension.
This commit is contained in:
@@ -9,6 +9,7 @@ use rusqlite::types::ValueRef;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::chat::{self, Chat, ChatId};
|
||||
use crate::config::Config;
|
||||
use crate::constants::{
|
||||
Blocked, Chattype, VideochatType, DC_CHAT_ID_TRASH, DC_DESIRED_TEXT_LEN, DC_MSG_ID_LAST_SPECIAL,
|
||||
};
|
||||
@@ -21,6 +22,7 @@ use crate::dc_tools::{
|
||||
use crate::download::DownloadState;
|
||||
use crate::ephemeral::{start_ephemeral_timers_msgids, Timer as EphemeralTimer};
|
||||
use crate::events::EventType;
|
||||
use crate::imap::markseen_on_imap;
|
||||
use crate::job::{self, Action};
|
||||
use crate::log::LogExt;
|
||||
use crate::mimeparser::{parse_message_id, FailureReport, SystemMessage};
|
||||
@@ -1294,6 +1296,9 @@ pub async fn markseen_msgs(context: &Context, msg_ids: Vec<MsgId>) -> Result<()>
|
||||
m.chat_id AS chat_id,
|
||||
m.state AS state,
|
||||
m.ephemeral_timer AS ephemeral_timer,
|
||||
m.param AS param,
|
||||
m.from_id AS from_id,
|
||||
m.rfc724_mid AS rfc724_mid,
|
||||
c.blocked AS blocked
|
||||
FROM msgs m LEFT JOIN chats c ON c.id=m.chat_id
|
||||
WHERE m.id IN ({}) AND m.chat_id>9",
|
||||
@@ -1304,12 +1309,18 @@ pub async fn markseen_msgs(context: &Context, msg_ids: Vec<MsgId>) -> Result<()>
|
||||
let id: MsgId = row.get("id")?;
|
||||
let chat_id: ChatId = row.get("chat_id")?;
|
||||
let state: MessageState = row.get("state")?;
|
||||
let param: Params = row.get::<_, String>("param")?.parse().unwrap_or_default();
|
||||
let from_id: ContactId = row.get("from_id")?;
|
||||
let rfc724_mid: String = row.get("rfc724_mid")?;
|
||||
let blocked: Option<Blocked> = row.get("blocked")?;
|
||||
let ephemeral_timer: EphemeralTimer = row.get("ephemeral_timer")?;
|
||||
Ok((
|
||||
id,
|
||||
chat_id,
|
||||
state,
|
||||
param,
|
||||
from_id,
|
||||
rfc724_mid,
|
||||
blocked.unwrap_or_default(),
|
||||
ephemeral_timer,
|
||||
))
|
||||
@@ -1318,30 +1329,52 @@ pub async fn markseen_msgs(context: &Context, msg_ids: Vec<MsgId>) -> Result<()>
|
||||
)
|
||||
.await?;
|
||||
|
||||
if msgs
|
||||
.iter()
|
||||
.any(|(_id, _chat_id, _state, _blocked, ephemeral_timer)| {
|
||||
if msgs.iter().any(
|
||||
|(_id, _chat_id, _state, _param, _from_id, _rfc724_mid, _blocked, ephemeral_timer)| {
|
||||
*ephemeral_timer != EphemeralTimer::Disabled
|
||||
})
|
||||
{
|
||||
},
|
||||
) {
|
||||
start_ephemeral_timers_msgids(context, &msg_ids)
|
||||
.await
|
||||
.context("failed to start ephemeral timers")?;
|
||||
}
|
||||
|
||||
let mut updated_chat_ids = BTreeSet::new();
|
||||
for (id, curr_chat_id, curr_state, curr_blocked, _curr_ephemeral_timer) in msgs.into_iter() {
|
||||
for (
|
||||
id,
|
||||
curr_chat_id,
|
||||
curr_state,
|
||||
curr_param,
|
||||
curr_from_id,
|
||||
curr_rfc724_mid,
|
||||
curr_blocked,
|
||||
_curr_ephemeral_timer,
|
||||
) in msgs.into_iter()
|
||||
{
|
||||
if curr_blocked == Blocked::Not
|
||||
&& (curr_state == MessageState::InFresh || curr_state == MessageState::InNoticed)
|
||||
{
|
||||
update_msg_state(context, id, MessageState::InSeen).await?;
|
||||
info!(context, "Seen message {}.", id);
|
||||
|
||||
job::add(
|
||||
context,
|
||||
job::Job::new(Action::MarkseenMsgOnImap, id.to_u32(), Params::new(), 0),
|
||||
)
|
||||
.await?;
|
||||
markseen_on_imap(context, &curr_rfc724_mid).await?;
|
||||
|
||||
// Read receipts for system messages are never sent. These messages have no place to
|
||||
// display received read receipt anyway. And since their text is locally generated,
|
||||
// quoting them is dangerous as it may contain contact names. E.g., for original message
|
||||
// "Group left by me", a read receipt will quote "Group left by <name>", and the name can
|
||||
// be a display name stored in address book rather than the name sent in the From field by
|
||||
// the user.
|
||||
if curr_param.get_bool(Param::WantsMdn).unwrap_or_default()
|
||||
&& curr_param.get_cmd() == SystemMessage::Unknown
|
||||
{
|
||||
let mdns_enabled = context.get_config_bool(Config::MdnsEnabled).await?;
|
||||
if mdns_enabled {
|
||||
if let Err(err) = job::send_mdn(context, id, curr_from_id).await {
|
||||
warn!(context, "could not send out mdn for {}: {}", id, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
updated_chat_ids.insert(curr_chat_id);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user