Skip to content

Commit 8f54b8f

Browse files
iequidoolink2xt
authored andcommitted
fix: Order of messages if outgoing reply is received earlier (#7169)
This fixes a scenario when an outgoing reply is received earlier than an incoming message for some reason like device B having `MvboxMove` enabled, sending the reply and going offline immediately, so the reply is in Inbox and it's processed by device A earlier because e.g. `MvboxMove` is disabled on it. Also if we add multi-transport later, this scenario will be just normal. This allows received outgoing messages to mingle with fresh incoming ones, i.e. sorts them together purely by timestamp by assigning `InFresh` state to received outgoing messages, but still returning `OutDelivered` by all APIs for compatibility. NB: We already do such a trick for `OutMdnRcvd`. As for messages sent locally, there's no need to make them more noticeable even if they are newer, so received outgoing messages are always added after them.
1 parent e52c40a commit 8f54b8f

File tree

5 files changed

+30
-17
lines changed

5 files changed

+30
-17
lines changed

src/events/payload.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ pub enum EventType {
3636
/// Emitted when an IMAP message has been moved
3737
ImapMessageMoved(String),
3838

39-
/// Emitted before going into IDLE on the Inbox folder.
39+
/// Emitted before going into IDLE on any folder.
4040
ImapInboxIdle,
4141

4242
/// Emitted when an new file in the $BLOBDIR was created

src/message.rs

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -85,16 +85,17 @@ impl MsgId {
8585
.sql
8686
.query_row_optional(
8787
concat!(
88-
"SELECT m.state, mdns.msg_id",
88+
"SELECT m.state, m.from_id, mdns.msg_id",
8989
" FROM msgs m LEFT JOIN msgs_mdns mdns ON mdns.msg_id=m.id",
9090
" WHERE id=?",
9191
" LIMIT 1",
9292
),
9393
(self,),
9494
|row| {
9595
let state: MessageState = row.get(0)?;
96-
let mdn_msg_id: Option<MsgId> = row.get(1)?;
97-
Ok(state.with_mdns(mdn_msg_id.is_some()))
96+
let from_id: ContactId = row.get(1)?;
97+
let mdn_msg_id: Option<MsgId> = row.get(2)?;
98+
Ok(state.with(from_id, mdn_msg_id.is_some()))
9899
},
99100
)
100101
.await?
@@ -551,22 +552,23 @@ impl Message {
551552
}
552553
_ => String::new(),
553554
};
555+
let from_id = row.get("from_id")?;
554556
let msg = Message {
555557
id: row.get("id")?,
556558
rfc724_mid: row.get::<_, String>("rfc724mid")?,
557559
in_reply_to: row
558560
.get::<_, Option<String>>("mime_in_reply_to")?
559561
.and_then(|in_reply_to| parse_message_id(&in_reply_to).ok()),
560562
chat_id: row.get("chat_id")?,
561-
from_id: row.get("from_id")?,
563+
from_id,
562564
to_id: row.get("to_id")?,
563565
timestamp_sort: row.get("timestamp")?,
564566
timestamp_sent: row.get("timestamp_sent")?,
565567
timestamp_rcvd: row.get("timestamp_rcvd")?,
566568
ephemeral_timer: row.get("ephemeral_timer")?,
567569
ephemeral_timestamp: row.get("ephemeral_timestamp")?,
568570
viewtype: row.get("type").unwrap_or_default(),
569-
state: state.with_mdns(mdn_msg_id.is_some()),
571+
state: state.with(from_id, mdn_msg_id.is_some()),
570572
download_state: row.get("download_state")?,
571573
error: Some(row.get::<_, String>("error")?)
572574
.filter(|error| !error.is_empty()),
@@ -1410,10 +1412,16 @@ impl MessageState {
14101412
)
14111413
}
14121414

1413-
/// Returns adjusted message state if the message has MDNs.
1414-
pub(crate) fn with_mdns(self, has_mdns: bool) -> Self {
1415+
/// Returns adjusted message state.
1416+
pub(crate) fn with(mut self, from_id: ContactId, has_mdns: bool) -> Self {
1417+
if MessageState::InFresh <= self
1418+
&& self <= MessageState::InSeen
1419+
&& from_id == ContactId::SELF
1420+
{
1421+
self = MessageState::OutDelivered;
1422+
}
14151423
if self == MessageState::OutDelivered && has_mdns {
1416-
return MessageState::OutMdnRcvd;
1424+
self = MessageState::OutMdnRcvd;
14171425
}
14181426
self
14191427
}

src/receive_imf.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1692,15 +1692,14 @@ async fn add_parts(
16921692
};
16931693

16941694
let state = if !mime_parser.incoming {
1695-
MessageState::OutDelivered
1695+
MessageState::InFresh
16961696
} else if seen || is_mdn || chat_id_blocked == Blocked::Yes || group_changes.silent
16971697
// No check for `hidden` because only reactions are such and they should be `InFresh`.
16981698
{
16991699
MessageState::InSeen
17001700
} else {
17011701
MessageState::InFresh
17021702
};
1703-
let in_fresh = state == MessageState::InFresh;
17041703

17051704
let sort_to_bottom = false;
17061705
let received = true;
@@ -1997,7 +1996,7 @@ async fn add_parts(
19971996
save_mime_modified |= mime_parser.is_mime_modified && !part_is_empty && !hidden;
19981997
let save_mime_modified = save_mime_modified && parts.peek().is_none();
19991998

2000-
let ephemeral_timestamp = if in_fresh {
1999+
let ephemeral_timestamp = if state == MessageState::InFresh {
20012000
0
20022001
} else {
20032002
match ephemeral_timer {
@@ -2109,6 +2108,8 @@ RETURNING id
21092108
ensure_and_debug_assert!(!row_id.is_special(), "Rowid {row_id} is special");
21102109
created_db_entries.push(row_id);
21112110
}
2111+
let has_mdns = false;
2112+
let state = state.with(from_id, has_mdns);
21122113

21132114
// Maybe set logging xdc and add gossip topics for webxdcs.
21142115
for (part, msg_id) in mime_parser.parts.iter().zip(&created_db_entries) {

src/tests/verified_chats.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -257,9 +257,9 @@ async fn test_old_message_4() -> Result<()> {
257257
Ok(())
258258
}
259259

260-
/// Alice is offline for some time.
261-
/// When they come online, first their sentbox is synced and then their inbox.
262-
/// This test tests that the messages are still in the right order.
260+
/// Alice's device#0 is offline for some time.
261+
/// When it comes online, it sees a message from another device and an incoming message. Messages
262+
/// may come from different folders.
263263
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
264264
async fn test_old_message_5() -> Result<()> {
265265
let alice = TestContext::new_alice().await;
@@ -289,7 +289,11 @@ async fn test_old_message_5() -> Result<()> {
289289
.await?
290290
.unwrap();
291291

292-
assert_eq!(msg_sent.sort_timestamp, msg_incoming.sort_timestamp);
292+
// If the messages come from the same folder and `msg_sent` is sent by Alice, it's better to
293+
// sort `msg_incoming` after it so that it's more visible. Messages coming from different
294+
// folders are a rare case now, but if Alice shares her account with someone else or has some
295+
// auto-reply bot, messages should be sorted just by "Date".
296+
assert!(msg_incoming.sort_timestamp < msg_sent.sort_timestamp);
293297
alice
294298
.golden_test_chat(msg_sent.chat_id, "test_old_message_5")
295299
.await;
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
Single#Chat#10: Bob [[email protected]] Icon: 4138c52e5bc1c576cda7dd44d088c07.png
22
--------------------------------------------------------------------------------
3-
Msg#10: Me (Contact#Contact#Self): Happy birthday, Bob! √
43
Msg#11: (Contact#Contact#10): Happy birthday to me, Alice! [FRESH]
4+
Msg#10: Me (Contact#Contact#Self): Happy birthday, Bob! √
55
--------------------------------------------------------------------------------

0 commit comments

Comments
 (0)