Skip to content

Commit 763334d

Browse files
Alexander Krotovlink2xt
Alexander Krotov
authored and
link2xt
committed
Sort message replies after parent message
1 parent be922ee commit 763334d

File tree

2 files changed

+69
-0
lines changed

2 files changed

+69
-0
lines changed

src/dc_receive_imf.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -698,6 +698,20 @@ async fn add_parts(
698698
let in_fresh = state == MessageState::InFresh;
699699
let rcvd_timestamp = time();
700700
let sort_timestamp = calc_sort_timestamp(context, *sent_timestamp, *chat_id, in_fresh).await;
701+
702+
// Ensure replies to messages are sorted after the parent message.
703+
//
704+
// This is useful in a case where sender clocks are not
705+
// synchronized and parent message has a Date: header with a
706+
// timestamp higher than reply timestamp.
707+
//
708+
// This does not help if parent message arrives later than the
709+
// reply.
710+
let parent_timestamp = mime_parser.get_parent_timestamp(context).await?;
711+
let sort_timestamp = parent_timestamp.map_or(sort_timestamp, |parent_timestamp| {
712+
std::cmp::max(sort_timestamp, parent_timestamp)
713+
});
714+
701715
*sent_timestamp = std::cmp::min(*sent_timestamp, rcvd_timestamp);
702716

703717
// unarchive chat

src/mimeparser.rs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1044,6 +1044,28 @@ impl MimeMessage {
10441044
message::handle_ndn(context, failure_report, error).await
10451045
}
10461046
}
1047+
1048+
/// Returns timestamp of the parent message.
1049+
///
1050+
/// If there is no parent message or it is not found in the
1051+
/// database, returns None.
1052+
pub async fn get_parent_timestamp(&self, context: &Context) -> Result<Option<i64>> {
1053+
let parent_timestamp = if let Some(field) = self
1054+
.get(HeaderDef::InReplyTo)
1055+
.and_then(|msgid| parse_message_id(msgid).ok())
1056+
{
1057+
context
1058+
.sql
1059+
.query_get_value_result(
1060+
"SELECT timestamp FROM msgs WHERE rfc724_mid=?",
1061+
paramsv![field],
1062+
)
1063+
.await?
1064+
} else {
1065+
None
1066+
};
1067+
Ok(parent_timestamp)
1068+
}
10471069
}
10481070

10491071
async fn update_gossip_peerstates(
@@ -1413,6 +1435,39 @@ mod tests {
14131435
assert!(mimeparser.chat_disposition_notification_to.is_none());
14141436
}
14151437

1438+
#[async_std::test]
1439+
async fn test_get_parent_timestamp() {
1440+
let context = TestContext::new().await;
1441+
let raw = b"From: [email protected]\n\
1442+
Content-Type: text/plain\n\
1443+
Chat-Version: 1.0\n\
1444+
In-Reply-To: <[email protected]>\n\
1445+
\n\
1446+
Some reply\n\
1447+
";
1448+
let mimeparser = MimeMessage::from_bytes(&context.ctx, &raw[..])
1449+
.await
1450+
.unwrap();
1451+
assert_eq!(
1452+
mimeparser.get_parent_timestamp(&context.ctx).await.unwrap(),
1453+
None
1454+
);
1455+
let timestamp = 1570435529;
1456+
context
1457+
.ctx
1458+
.sql
1459+
.execute(
1460+
"INSERT INTO msgs (rfc724_mid, timestamp) VALUES(?,?)",
1461+
paramsv!["[email protected]", timestamp],
1462+
)
1463+
.await
1464+
.expect("Failed to write to the database");
1465+
assert_eq!(
1466+
mimeparser.get_parent_timestamp(&context.ctx).await.unwrap(),
1467+
Some(timestamp)
1468+
);
1469+
}
1470+
14161471
#[async_std::test]
14171472
async fn test_mimeparser_with_context() {
14181473
let context = TestContext::new().await;

0 commit comments

Comments
 (0)