- Operating System (Linux/Mac/Windows/iOS/Android): Windows
- Core Version: 2.49.1
- Client Version: 2.49.0, latest main 100e09450.
Expected behavior
Chat remains unread.
Actual behavior
Chat becomes read.
Steps to reproduce the problem
- Receive a message.
- Go offline (airplane mode, or set an invalid proxy).
- Open the chat and read the message.
- Right-click the chat and mark it as unread.
- Go online.
Misc
Most annoyingly, going offline isn't even a requirement to reproduce this. All that is required is some delay between the MDN getting sent and it getting received. Which means that you try to mark the chat as unread immediately after reading a message (which is basically the primary way this feature is used) then "mark as unread" will basically not work.
Code:
|
for report in &mime_parser.mdn_reports { |
|
for msg_rfc724_mid in report |
|
.original_message_id |
|
.iter() |
|
.chain(&report.additional_message_ids) |
|
{ |
|
let Some(msg_id) = rfc724_mid_exists(context, msg_rfc724_mid).await? else { |
|
continue; |
|
}; |
|
let Some(msg) = Message::load_from_db_optional(context, msg_id).await? else { |
|
continue; |
|
}; |
|
if msg.state < MessageState::InFresh || msg.state >= MessageState::InSeen { |
|
continue; |
|
} |
|
if !mime_parser.was_encrypted() && msg.get_showpadlock() { |
|
warn!(context, "MDN: Not encrypted. Ignoring."); |
|
continue; |
|
} |
|
message::update_msg_state(context, msg_id, MessageState::InSeen).await?; |
|
if let Err(e) = msg_id.start_ephemeral_timer(context).await { |
|
error!(context, "start_ephemeral_timer for {msg_id}: {e:#}."); |
|
} |
|
if !mime_parser.has_chat_version() { |
|
continue; |
|
} |
|
archived_chats_maybe_noticed |= msg.state < MessageState::InNoticed |
|
&& msg.chat_visibility == ChatVisibility::Archived; |
|
updated_chats |
|
.entry(msg.chat_id) |
|
.and_modify(|pos| *pos = cmp::max(*pos, (msg.timestamp_sort, msg.id))) |
|
.or_insert((msg.timestamp_sort, msg.id)); |
|
} |
|
} |
|
for (chat_id, (timestamp_sort, msg_id)) in updated_chats { |
|
context |
|
.sql |
|
.execute( |
|
" |
|
UPDATE msgs SET state=? WHERE |
|
state=? AND |
|
hidden=0 AND |
|
chat_id=? AND |
|
(timestamp,id)<(?,?)", |
|
( |
|
MessageState::InNoticed, |
|
MessageState::InFresh, |
|
chat_id, |
|
timestamp_sort, |
|
msg_id, |
|
), |
|
) |
|
.await |
|
.context("UPDATE msgs.state")?; |
|
if chat_id.get_fresh_msg_cnt(context).await? == 0 { |
|
// Removes all notifications for the chat in UIs. |
|
context.emit_event(EventType::MsgsNoticed(chat_id)); |
|
} else { |
|
context.emit_msgs_changed_without_msg_id(chat_id); |
|
} |
|
chatlist_events::emit_chatlist_item_changed(context, chat_id); |
|
} |
|
/// Marks last incoming message in a chat as fresh. |
|
pub async fn markfresh_chat(context: &Context, chat_id: ChatId) -> Result<()> { |
|
let affected_rows = context |
|
.sql |
|
.execute( |
|
"UPDATE msgs |
|
SET state=?1 |
|
WHERE id=(SELECT id |
|
FROM msgs |
|
WHERE state IN (?1, ?2, ?3) AND hidden=0 AND chat_id=?4 |
|
ORDER BY timestamp DESC, id DESC |
|
LIMIT 1) |
|
AND state!=?1", |
|
( |
|
MessageState::InFresh, |
|
MessageState::InNoticed, |
|
MessageState::InSeen, |
|
chat_id, |
|
), |
|
) |
|
.await?; |
|
|
|
if affected_rows == 0 { |
|
return Ok(()); |
|
} |
|
|
|
context.emit_msgs_changed_without_msg_id(chat_id); |
|
chatlist_events::emit_chatlist_item_changed(context, chat_id); |
|
|
|
Ok(()) |
|
} |
Somewhat related:
Solution ideas
I'm not a big expert on Core, but what comes to mind:
- don't handle self-sent MDNs, at least from the same device.
- Have a timestamp on the MDNs, and have a timestamp on when the message was marked as unread.
- Do "mark as read" in some other way, instead of marking the last chat message as unread, e.g. have a property on the chat itself.
Expected behavior
Chat remains unread.
Actual behavior
Chat becomes read.
Steps to reproduce the problem
Misc
Most annoyingly, going offline isn't even a requirement to reproduce this. All that is required is some delay between the MDN getting sent and it getting received. Which means that you try to mark the chat as unread immediately after reading a message (which is basically the primary way this feature is used) then "mark as unread" will basically not work.
Code:
core/src/receive_imf.rs
Lines 939 to 1000 in 855153c
core/src/chat.rs
Lines 3364 to 3394 in f2f2dd4
Somewhat related:
Solution ideas
I'm not a big expert on Core, but what comes to mind: