Skip to content

Commit e53336f

Browse files
iequidoolink2xt
authored andcommitted
fix: Make calc_sort_timestamp() a continuous function of message timestamp
This also simplifies the SQL query in `calc_sort_timestamp()` and prepares for creation of a db index for it so that it's fast. Currently it doesn't uses indexes effectively; if a chat has many messages, it's slow, i.e. O(n). This as well fixes ordering of delayed encrypted outgoing messages; before, they could be sorted above "Messages are end-to-end encrypted."
1 parent 268a5cf commit e53336f

File tree

4 files changed

+59
-27
lines changed

4 files changed

+59
-27
lines changed

src/chat.rs

Lines changed: 37 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,10 @@ impl ChatId {
298298
let chat = Chat::load_from_db(context, chat_id).await?;
299299

300300
if chat.is_encrypted(context).await? {
301-
chat_id.add_encrypted_msg(context, timestamp).await?;
301+
let respect_delayed_msgs = true;
302+
chat_id
303+
.add_encrypted_msg(context, timestamp, respect_delayed_msgs)
304+
.await?;
302305
}
303306

304307
info!(
@@ -459,15 +462,23 @@ impl ChatId {
459462
}
460463

461464
/// Adds message "Messages are end-to-end encrypted".
462-
async fn add_encrypted_msg(self, context: &Context, timestamp_sort: i64) -> Result<()> {
465+
async fn add_encrypted_msg(
466+
self,
467+
context: &Context,
468+
timestamp_sent: i64,
469+
respect_delayed_msgs: bool,
470+
) -> Result<()> {
463471
let text = stock_str::messages_e2e_encrypted(context).await;
464472
add_info_msg_with_cmd(
465473
context,
466474
self,
467475
&text,
468476
SystemMessage::ChatE2ee,
469-
timestamp_sort,
470-
None,
477+
// Create a time window for delayed encrypted messages so that they are sorted under
478+
// "Messages are end-to-end encrypted." This way time still monotonically increases and
479+
// there's no magic "N years ago" which should be adjusted in the future.
480+
timestamp_sent / if respect_delayed_msgs { 2 } else { 1 },
481+
Some(timestamp_sent),
471482
None,
472483
None,
473484
None,
@@ -1218,37 +1229,35 @@ impl ChatId {
12181229
)
12191230
.await?
12201231
} else if received {
1221-
// Received messages shouldn't mingle with just sent ones and appear somewhere in the
1222-
// middle of the chat, so we go after the newest non fresh message.
1223-
//
1224-
// But if a received outgoing message is older than some seen message, better sort the
1225-
// received message purely by timestamp. We could place it just before that seen
1226-
// message, but anyway the user may not notice it.
1232+
// Received incoming messages shouldn't mingle with just sent ones and appear somewhere
1233+
// in the middle of the chat, so we go after the newest non fresh message. Received
1234+
// outgoing messages are allowed to mingle with seen messages though to avoid seen
1235+
// replies appearing before messages sent from another device (cases like the user
1236+
// sharing the account with others or bots are rare, so let them break sometimes).
12271237
//
12281238
// NB: Received outgoing messages may break sorting of fresh incoming ones, but this
12291239
// shouldn't happen frequently. Seen incoming messages don't really break sorting of
12301240
// fresh ones, they rather mean that older incoming messages are actually seen as well.
12311241
context
12321242
.sql
12331243
.query_row_optional(
1234-
"SELECT MAX(timestamp), MAX(IIF(state=?,timestamp_sent,0))
1244+
"SELECT MAX(timestamp)
12351245
FROM msgs
12361246
WHERE chat_id=? AND hidden=0 AND state>?
12371247
HAVING COUNT(*) > 0",
1238-
(MessageState::InSeen, self, MessageState::InFresh),
1248+
(
1249+
self,
1250+
match incoming {
1251+
true => MessageState::InFresh,
1252+
false => MessageState::InSeen,
1253+
},
1254+
),
12391255
|row| {
12401256
let ts: i64 = row.get(0)?;
1241-
let ts_sent_seen: i64 = row.get(1)?;
1242-
Ok((ts, ts_sent_seen))
1257+
Ok(ts)
12431258
},
12441259
)
12451260
.await?
1246-
.and_then(|(ts, ts_sent_seen)| {
1247-
match incoming || ts_sent_seen <= message_timestamp {
1248-
true => Some(ts),
1249-
false => None,
1250-
}
1251-
})
12521261
} else {
12531262
None
12541263
};
@@ -2423,7 +2432,10 @@ impl ChatIdBlocked {
24232432
&& !chat.param.exists(Param::Devicetalk)
24242433
&& !chat.param.exists(Param::Selftalk)
24252434
{
2426-
chat_id.add_encrypted_msg(context, smeared_time).await?;
2435+
let respect_delayed_msgs = true;
2436+
chat_id
2437+
.add_encrypted_msg(context, smeared_time, respect_delayed_msgs)
2438+
.await?;
24272439
}
24282440

24292441
Ok(Self {
@@ -3449,8 +3461,10 @@ pub(crate) async fn create_group_ex(
34493461
chatlist_events::emit_chatlist_item_changed(context, chat_id);
34503462

34513463
if is_encrypted {
3452-
// Add "Messages are end-to-end encrypted." message.
3453-
chat_id.add_encrypted_msg(context, timestamp).await?;
3464+
let respect_delayed_msgs = false;
3465+
chat_id
3466+
.add_encrypted_msg(context, timestamp, respect_delayed_msgs)
3467+
.await?;
34543468
}
34553469

34563470
if !context.get_config_bool(Config::Bot).await?

src/tests/verified_chats.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -212,9 +212,11 @@ async fn test_degrade_verified_oneonone_chat() -> Result<()> {
212212
/// This test tests that the messages are still in the right order.
213213
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
214214
async fn test_old_message_4() -> Result<()> {
215-
let alice = TestContext::new_alice().await;
215+
let mut tcm = TestContextManager::new();
216+
let alice = &tcm.alice().await;
217+
let bob = &tcm.bob().await;
216218
let msg_incoming = receive_imf(
217-
&alice,
219+
alice,
218220
b"From: Bob <[email protected]>\n\
219221
220222
Message-ID: <[email protected]>\n\
@@ -227,7 +229,7 @@ async fn test_old_message_4() -> Result<()> {
227229
.unwrap();
228230

229231
let msg_sent = receive_imf(
230-
&alice,
232+
alice,
231233
b"From: [email protected]\n\
232234
To: Bob <[email protected]>\n\
233235
Message-ID: <[email protected]>\n\
@@ -242,6 +244,16 @@ async fn test_old_message_4() -> Result<()> {
242244
// The "Happy birthday" message should be shown first, and then the "Thanks" message
243245
assert!(msg_sent.sort_timestamp < msg_incoming.sort_timestamp);
244246

247+
// And now the same for encrypted messages.
248+
let msg_incoming = tcm.send_recv(bob, alice, "Thanks, Alice!").await;
249+
message::markseen_msgs(alice, vec![msg_incoming.id]).await?;
250+
let raw = include_bytes!("../../test-data/message/thunderbird_with_autocrypt.eml");
251+
let msg_sent = receive_imf(alice, raw, true).await?.unwrap();
252+
assert_eq!(msg_sent.chat_id, msg_incoming.chat_id);
253+
assert!(msg_sent.sort_timestamp < msg_incoming.timestamp_sort);
254+
alice
255+
.golden_test_chat(msg_sent.chat_id, "test_old_message_4")
256+
.await;
245257
Ok(())
246258
}
247259

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
2+
--------------------------------------------------------------------------------
3+
Msg#12: info (Contact#Contact#Info): Messages are end-to-end encrypted. [NOTICED][INFO]
4+
Msg#14🔒: Me (Contact#Contact#Self): Test – This is encrypted, signed, and has an Autocrypt Header without prefer-encrypt=mutual. √
5+
Msg#13🔒: (Contact#Contact#11): Thanks, Alice! [SEEN]
6+
--------------------------------------------------------------------------------
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
Group#Chat#11: Group [3 member(s)]
22
--------------------------------------------------------------------------------
3+
Msg#12: info (Contact#Contact#Info): Messages are end-to-end encrypted. [NOTICED][INFO]
34
Msg#13: info (Contact#Contact#Info): [email protected] invited you to join this group.
45

56
Waiting for the device of [email protected] to reply… [NOTICED][INFO]
67
Msg#15: info (Contact#Contact#Info): [email protected] replied, waiting for being added to the group… [NOTICED][INFO]
7-
Msg#12: info (Contact#Contact#Info): Messages are end-to-end encrypted. [NOTICED][INFO]
88
Msg#17🔒: (Contact#Contact#10): Member Me added by [email protected]. [FRESH][INFO]
99
--------------------------------------------------------------------------------

0 commit comments

Comments
 (0)