diff --git a/src/chat.rs b/src/chat.rs index 02f4d44ae..e6245c480 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -381,7 +381,14 @@ impl ChatId { msg.param.set_cmd(cmd); send_msg(context, self, &mut msg).await?; } else { - add_info_msg_with_cmd(context, self, msg_text, cmd).await?; + add_info_msg_with_cmd( + context, + self, + msg_text, + cmd, + dc_create_smeared_timestamp(context).await, + ) + .await?; } Ok(()) @@ -2981,6 +2988,7 @@ pub(crate) async fn add_info_msg_with_cmd( chat_id: ChatId, text: impl AsRef, cmd: SystemMessage, + timestamp: i64, ) -> Result { let rfc724_mid = dc_create_outgoing_rfc724_mid(None, "@device"); let ephemeral_timer = chat_id.get_ephemeral_timer(context).await?; @@ -2997,7 +3005,7 @@ pub(crate) async fn add_info_msg_with_cmd( chat_id, DC_CONTACT_ID_INFO, DC_CONTACT_ID_INFO, - dc_create_smeared_timestamp(context).await, + timestamp, Viewtype::Text, MessageState::InNoticed, text.as_ref().to_string(), @@ -3012,8 +3020,16 @@ pub(crate) async fn add_info_msg_with_cmd( Ok(msg_id) } -pub(crate) async fn add_info_msg(context: &Context, chat_id: ChatId, text: impl AsRef) { - if let Err(e) = add_info_msg_with_cmd(context, chat_id, text, SystemMessage::Unknown).await { +/// Adds info message with a given text and `timestamp` to the chat. +pub(crate) async fn add_info_msg( + context: &Context, + chat_id: ChatId, + text: impl AsRef, + timestamp: i64, +) { + if let Err(e) = + add_info_msg_with_cmd(context, chat_id, text, SystemMessage::Unknown, timestamp).await + { warn!(context, "Could not add info msg: {}", e); } } @@ -3637,7 +3653,7 @@ mod tests { let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo") .await .unwrap(); - add_info_msg(&t, chat_id, "foo info").await; + add_info_msg(&t, chat_id, "foo info", 200000).await; let msg = t.get_last_msg_in(chat_id).await; assert_eq!(msg.get_chat_id(), chat_id); @@ -3658,6 +3674,7 @@ mod tests { chat_id, "foo bar info", SystemMessage::EphemeralTimerChanged, + 10000, ) .await .unwrap(); diff --git a/src/dc_receive_imf.rs b/src/dc_receive_imf.rs index e35703645..b0f210c98 100644 --- a/src/dc_receive_imf.rs +++ b/src/dc_receive_imf.rs @@ -798,6 +798,12 @@ async fn add_parts( let location_kml_is = mime_parser.location_kml.is_some(); + // correct message_timestamp, it should not be used before, + // however, we cannot do this earlier as we need from_id to be set + let in_fresh = state == MessageState::InFresh; + let rcvd_timestamp = time(); + let sort_timestamp = calc_sort_timestamp(context, *sent_timestamp, chat_id, in_fresh).await?; + // Apply ephemeral timer changes to the chat. // // Only non-hidden timers are applied now. Timers from hidden @@ -825,6 +831,7 @@ async fn add_parts( context, chat_id, stock_ephemeral_timer_changed(context, ephemeral_timer, from_id).await, + sort_timestamp, ) .await; } @@ -868,6 +875,7 @@ async fn add_parts( context, chat_id, format!("Cannot set protection: {}", e), + sort_timestamp, ) .await; return Ok(chat_id); // do not return an error as this would result in retrying the message @@ -883,12 +891,6 @@ async fn add_parts( } } - // correct message_timestamp, it should not be used before, - // however, we cannot do this earlier as we need from_id to be set - let in_fresh = state == MessageState::InFresh; - let rcvd_timestamp = time(); - let sort_timestamp = calc_sort_timestamp(context, *sent_timestamp, chat_id, in_fresh).await?; - // Ensure replies to messages are sorted after the parent message. // // This is useful in a case where sender clocks are not diff --git a/src/e2ee.rs b/src/e2ee.rs index 5257a4358..702e44dd0 100644 --- a/src/e2ee.rs +++ b/src/e2ee.rs @@ -178,7 +178,9 @@ pub async fn try_decrypt( let mut signatures = HashSet::default(); if let Some(ref mut peerstate) = peerstate { - peerstate.handle_fingerprint_change(context).await?; + peerstate + .handle_fingerprint_change(context, message_time) + .await?; if let Some(key) = &peerstate.public_key { public_keyring_for_validate.add(key.clone()); } else if let Some(key) = &peerstate.gossip_key { diff --git a/src/location.rs b/src/location.rs index cc7ffc746..e09e81202 100644 --- a/src/location.rs +++ b/src/location.rs @@ -190,7 +190,7 @@ impl Kml { } } -// location streaming +/// Enables location streaming in chat identified by `chat_id` for `seconds` seconds. pub async fn send_locations_to_chat(context: &Context, chat_id: ChatId, seconds: i64) { let now = time(); if !(seconds < 0 || chat_id.is_special()) { @@ -221,7 +221,7 @@ pub async fn send_locations_to_chat(context: &Context, chat_id: ChatId, seconds: .unwrap_or_default(); } else if 0 == seconds && is_sending_locations_before { let stock_str = stock_str::msg_location_disabled(context).await; - chat::add_info_msg(context, chat_id, stock_str).await; + chat::add_info_msg(context, chat_id, stock_str, now).await; } context.emit_event(EventType::ChatModified(chat_id)); if 0 != seconds { @@ -716,7 +716,8 @@ pub(crate) async fn job_maybe_send_locations_ended( .await ); - if !(send_begin != 0 && time() <= send_until) { + let now = time(); + if !(send_begin != 0 && now <= send_until) { // still streaming - // may happen as several calls to dc_send_locations_to_chat() // do not un-schedule pending DC_MAYBE_SEND_LOC_ENDED jobs @@ -735,7 +736,7 @@ pub(crate) async fn job_maybe_send_locations_ended( ); let stock_str = stock_str::msg_location_disabled(context).await; - chat::add_info_msg(context, chat_id, stock_str).await; + chat::add_info_msg(context, chat_id, stock_str, now).await; context.emit_event(EventType::ChatModified(chat_id)); } } diff --git a/src/message.rs b/src/message.rs index 2e348d7cb..9f293bb03 100644 --- a/src/message.rs +++ b/src/message.rs @@ -19,8 +19,8 @@ use crate::constants::{ use crate::contact::{Contact, Origin}; use crate::context::Context; use crate::dc_tools::{ - dc_get_filebytes, dc_get_filemeta, dc_gm2local_offset, dc_read_file, dc_timestamp_to_str, - dc_truncate, time, + dc_create_smeared_timestamp, dc_get_filebytes, dc_get_filemeta, dc_gm2local_offset, + dc_read_file, dc_timestamp_to_str, dc_truncate, time, }; use crate::ephemeral::Timer as EphemeralTimer; use crate::events::EventType; @@ -1805,7 +1805,13 @@ async fn ndn_maybe_add_info_msg( // Tell the user which of the recipients failed if we know that (because in // a group, this might otherwise be unclear) let text = stock_str::failed_sending_to(context, contact.get_display_name()).await; - chat::add_info_msg(context, chat_id, text).await; + chat::add_info_msg( + context, + chat_id, + text, + dc_create_smeared_timestamp(context).await, + ) + .await; context.emit_event(EventType::ChatModified(chat_id)); } } diff --git a/src/mimeparser.rs b/src/mimeparser.rs index 595580ecb..c06ab5c13 100644 --- a/src/mimeparser.rs +++ b/src/mimeparser.rs @@ -1347,7 +1347,9 @@ async fn update_gossip_peerstates( peerstate = Some(p); } if let Some(peerstate) = peerstate { - peerstate.handle_fingerprint_change(context).await?; + peerstate + .handle_fingerprint_change(context, message_time) + .await?; } gossipped_addr.insert(header.addr.clone()); diff --git a/src/peerstate.rs b/src/peerstate.rs index ecf0a7bf1..669f35bb5 100644 --- a/src/peerstate.rs +++ b/src/peerstate.rs @@ -260,7 +260,11 @@ impl Peerstate { } /// Adds a warning to the chat corresponding to peerstate if fingerprint has changed. - pub(crate) async fn handle_fingerprint_change(&self, context: &Context) -> Result<()> { + pub(crate) async fn handle_fingerprint_change( + &self, + context: &Context, + timestamp: i64, + ) -> Result<()> { if self.fingerprint_changed { if let Some(contact_id) = context .sql @@ -273,7 +277,7 @@ impl Peerstate { let msg = stock_str::contact_setup_changed(context, self.addr.clone()).await; - chat::add_info_msg(context, chat_id, msg).await; + chat::add_info_msg(context, chat_id, msg, timestamp).await; emit_event!(context, EventType::ChatModified(chat_id)); } else { bail!("contact with peerstate.addr {:?} not found", &self.addr); diff --git a/src/qr.rs b/src/qr.rs index 3170e20d0..866df1fdd 100644 --- a/src/qr.rs +++ b/src/qr.rs @@ -11,6 +11,7 @@ use crate::config::Config; use crate::constants::Blocked; use crate::contact::{addr_normalize, may_be_valid_addr, Contact, Origin}; use crate::context::Context; +use crate::dc_tools::time; use crate::key::Fingerprint; use crate::log::LogExt; use crate::lot::{Lot, LotState}; @@ -160,7 +161,13 @@ async fn decode_openpgp(context: &Context, qr: &str) -> Lot { .await .log_err(context, "Failed to create (new) chat for contact") { - chat::add_info_msg(context, chat.id, format!("{} verified.", peerstate.addr)).await; + chat::add_info_msg( + context, + chat.id, + format!("{} verified.", peerstate.addr), + time(), + ) + .await; } } else if let Some(addr) = addr { lot.state = LotState::QrFprMismatch; diff --git a/src/securejoin.rs b/src/securejoin.rs index e6f254403..bdb56a131 100644 --- a/src/securejoin.rs +++ b/src/securejoin.rs @@ -14,6 +14,7 @@ use crate::config::Config; use crate::constants::{Blocked, Viewtype, DC_CONTACT_ID_LAST_SPECIAL}; use crate::contact::{Contact, Origin, VerifiedStatus}; use crate::context::Context; +use crate::dc_tools::time; use crate::e2ee::ensure_secret_key_exists; use crate::events::EventType; use crate::headerdef::HeaderDef; @@ -859,7 +860,7 @@ async fn secure_connection_established( "?" }; let msg = stock_str::contact_verified(context, addr).await; - chat::add_info_msg(context, contact_chat_id, msg).await; + chat::add_info_msg(context, contact_chat_id, msg, time()).await; emit_event!(context, EventType::ChatModified(contact_chat_id)); info!(context, "StockMessage::ContactVerified posted to 1:1 chat"); @@ -883,7 +884,7 @@ async fn could_not_establish_secure_connection( ) .await; - chat::add_info_msg(context, contact_chat_id, &msg).await; + chat::add_info_msg(context, contact_chat_id, &msg, time()).await; error!( context, "StockMessage::ContactNotVerified posted to 1:1 chat ({})", details