From 1470a7da19489c234cdf611317e1f25b495c0b75 Mon Sep 17 00:00:00 2001 From: link2xt Date: Sat, 22 Aug 2026 18:18:17 +0000 Subject: [PATCH 1/3] fix: take timestamp_rcvd into account in estimate_deletion_cnt This did not affect actual message deletion, because select_expired_messages already takes timestamp_rcvd into account and does not delete system messages that say "Messages are end-to-end encrypted" too early. So it is a minor bug as estimate_deletion_cnt is meant to only roughly estimate the number of messages to be deleted. Still, there were no tests before, so now estimate_deletion_cnt is tested. --- src/ephemeral/ephemeral_tests.rs | 16 +++++++++++++++- src/message.rs | 9 +++++---- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/ephemeral/ephemeral_tests.rs b/src/ephemeral/ephemeral_tests.rs index a253a7cc4b..46d2806b3f 100644 --- a/src/ephemeral/ephemeral_tests.rs +++ b/src/ephemeral/ephemeral_tests.rs @@ -7,7 +7,7 @@ use crate::config::Config; use crate::constants::DC_CHAT_ID_ARCHIVED_LINK; use crate::download::DownloadState; use crate::location; -use crate::message::markseen_msgs; +use crate::message::{estimate_deletion_cnt, markseen_msgs}; use crate::receive_imf::receive_imf; use crate::test_utils; use crate::test_utils::{TestContext, TestContextManager}; @@ -280,12 +280,14 @@ async fn test_ephemeral_delete_msgs() -> Result<()> { // Set DeleteDeviceAfter to 1800s. Then send a saved message which will // still be deleted after 3600s because DeleteDeviceAfter doesn't apply to saved messages. + assert_eq!(estimate_deletion_cnt(t, false, 1800).await.unwrap(), 0); t.set_config(Config::DeleteDeviceAfter, Some("1800")) .await?; let now = time(); let msg = t.send_text(self_chat.id, "Message text").await; + assert_eq!(estimate_deletion_cnt(t, false, 1800).await.unwrap(), 0); check_msg_will_be_deleted(t, msg.sender_msg_id, &self_chat, now + 3559, time() + 3601) .await .unwrap(); @@ -894,6 +896,11 @@ async fn test_delete_device_after_unknown_viewtype() -> Result<()> { let bob = &tcm.bob().await; let chat = alice.create_chat(bob).await; + + // There may be a message created saying that all messages are encrypted + // with timestamp 0 so it is always at the top. + // It should still be not deleted because of the "received timestamp" that is recent. + assert_eq!(estimate_deletion_cnt(alice, false, 600).await.unwrap(), 0); alice .set_config(Config::DeleteDeviceAfter, Some("600")) .await?; @@ -901,6 +908,9 @@ async fn test_delete_device_after_unknown_viewtype() -> Result<()> { let mut msg = Message::new_text("Some message".to_string()); let _alice_sent_message = alice.send_msg(chat.id, &mut msg).await; + // New message should not be deleted as well yet. + assert_eq!(estimate_deletion_cnt(alice, false, 600).await.unwrap(), 0); + // Set message viewtype to unassigned // type 70 that was previously used for videochat invitations. alice @@ -910,6 +920,10 @@ async fn test_delete_device_after_unknown_viewtype() -> Result<()> { SystemTime::shift(Duration::from_secs(1000)); + // Now both the system message about the chat being encrypted + // and the message sent by Alice are going to be deleted. + assert_eq!(estimate_deletion_cnt(alice, false, 600).await.unwrap(), 2); + // This should not fail. delete_expired_messages(alice, time()).await?; alice diff --git a/src/message.rs b/src/message.rs index ac3c29fd27..6dab8ef5a0 100644 --- a/src/message.rs +++ b/src/message.rs @@ -2100,10 +2100,11 @@ pub async fn estimate_deletion_cnt( .count( "SELECT COUNT(*) FROM msgs m - WHERE m.id > ? - AND timestamp < ? - AND chat_id != ? - AND chat_id != ? AND hidden = 0;", + WHERE m.id > ?1 + AND timestamp < ?2 -- Sorting timestamp may be 0 for system messages + AND timestamp_rcvd < ?2 -- so we check 'received' timestamp as well. + AND chat_id != ?3 + AND chat_id != ?4 AND hidden = 0;", ( DC_MSG_ID_LAST_SPECIAL, threshold_timestamp, From ecd7c0b31c2dae81e398338159407b7108bec487 Mon Sep 17 00:00:00 2001 From: link2xt Date: Sat, 22 Aug 2026 00:55:07 +0000 Subject: [PATCH 2/3] refactor: turn DC_CHAT_ID_* into ChatId::* associated constants We already have it done for ContactId. --- deltachat-ffi/src/lib.rs | 9 ++-- src/calls/calls_tests.rs | 3 +- src/chat.rs | 41 +++++++++++-------- src/chat/chat_tests.rs | 30 +++++++------- src/chatlist.rs | 16 ++++---- src/constants.rs | 13 +----- src/contact.rs | 2 +- src/ephemeral.rs | 11 +++-- src/ephemeral/ephemeral_tests.rs | 7 ++-- src/events/chatlist_events.rs | 5 +-- src/location.rs | 3 +- src/message.rs | 14 +++---- src/message/message_tests.rs | 2 +- .../shared_secret_decryption_tests.rs | 7 ++-- src/receive_imf.rs | 29 ++++++------- src/receive_imf/receive_imf_tests.rs | 2 +- src/securejoin/securejoin_tests.rs | 5 +-- src/sql.rs | 8 ++-- src/test_utils.rs | 7 ++-- 19 files changed, 98 insertions(+), 116 deletions(-) diff --git a/deltachat-ffi/src/lib.rs b/deltachat-ffi/src/lib.rs index b4a3a3502b..5d0b8a69b8 100644 --- a/deltachat-ffi/src/lib.rs +++ b/deltachat-ffi/src/lib.rs @@ -1774,8 +1774,7 @@ pub unsafe extern "C" fn dc_set_chat_name( chat_id: u32, name: *const libc::c_char, ) -> libc::c_int { - if context.is_null() || chat_id <= constants::DC_CHAT_ID_LAST_SPECIAL.to_u32() || name.is_null() - { + if context.is_null() || chat_id <= ChatId::LAST_SPECIAL.to_u32() || name.is_null() { eprintln!("ignoring careless call to dc_set_chat_name()"); return 0; } @@ -1796,7 +1795,7 @@ pub unsafe extern "C" fn dc_set_chat_profile_image( chat_id: u32, image: *const libc::c_char, ) -> libc::c_int { - if context.is_null() || chat_id <= constants::DC_CHAT_ID_LAST_SPECIAL.to_u32() { + if context.is_null() || chat_id <= ChatId::LAST_SPECIAL.to_u32() { eprintln!("ignoring careless call to dc_set_chat_profile_image()"); return 0; } @@ -1958,7 +1957,7 @@ pub unsafe extern "C" fn dc_forward_msgs( if context.is_null() || msg_ids.is_null() || msg_cnt <= 0 - || chat_id <= constants::DC_CHAT_ID_LAST_SPECIAL.to_u32() + || chat_id <= ChatId::LAST_SPECIAL.to_u32() { eprintln!("ignoring careless call to dc_forward_msgs()"); return; @@ -2462,7 +2461,7 @@ pub unsafe extern "C" fn dc_send_locations_to_chat( chat_id: u32, seconds: libc::c_int, ) { - if context.is_null() || chat_id <= constants::DC_CHAT_ID_LAST_SPECIAL.to_u32() || seconds < 0 { + if context.is_null() || chat_id <= ChatId::LAST_SPECIAL.to_u32() || seconds < 0 { eprintln!("ignoring careless call to dc_send_locations_to_chat()"); return; } diff --git a/src/calls/calls_tests.rs b/src/calls/calls_tests.rs index 44bc159cf2..0a1e2a6170 100644 --- a/src/calls/calls_tests.rs +++ b/src/calls/calls_tests.rs @@ -1,7 +1,6 @@ use super::*; use crate::chat::forward_msgs; use crate::config::Config; -use crate::constants::DC_CHAT_ID_TRASH; use crate::message::MessageState; use crate::receive_imf::receive_imf; use crate::test_utils; @@ -678,7 +677,7 @@ async fn test_end_text_call() -> Result<()> { .await? .unwrap(); assert_eq!(received2.msg_ids.len(), 1); - assert_eq!(received2.chat_id, DC_CHAT_ID_TRASH); + assert_eq!(received2.chat_id, ChatId::TRASH); alice.assert_warn("does not refer to a call message").await; Ok(()) diff --git a/src/chat.rs b/src/chat.rs index 79991a7010..037e56675e 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -22,9 +22,7 @@ use crate::chatlist_events; use crate::color::str_to_color; use crate::config::Config; use crate::constants::{ - self, Blocked, Chattype, DC_CHAT_ID_ALLDONE_HINT, DC_CHAT_ID_ARCHIVED_LINK, - DC_CHAT_ID_LAST_SPECIAL, DC_CHAT_ID_TRASH, DC_RESEND_USER_AVATAR_DAYS, EDITED_PREFIX, - TIMESTAMP_SENT_TOLERANCE, + self, Blocked, Chattype, DC_RESEND_USER_AVATAR_DAYS, EDITED_PREFIX, TIMESTAMP_SENT_TOLERANCE, }; use crate::contact::{self, Contact, ContactId, Origin}; use crate::context::Context; @@ -135,6 +133,15 @@ impl fmt::Display for CantSendReason { pub struct ChatId(u32); impl ChatId { + /// messages that should be deleted get this chat_id; the messages are deleted from the working thread later then. This is also needed as rfc724_mid should be preset as long as the message is not deleted on the server (otherwise it is downloaded again) + pub const TRASH: ChatId = ChatId::new(3); + /// only an indicator in a chatlist + pub const ARCHIVED_LINK: ChatId = ChatId::new(6); + /// only an indicator in a chatlist + pub const ALLDONE_HINT: ChatId = ChatId::new(7); + /// larger chat IDs are "real" chats, their messages are "real" messages. + pub const LAST_SPECIAL: ChatId = ChatId::new(9); + /// Create a new [ChatId]. pub const fn new(id: u32) -> ChatId { ChatId(id) @@ -151,7 +158,7 @@ impl ChatId { /// /// This kind of chat ID can not be used for real chats. pub fn is_special(self) -> bool { - (0..=DC_CHAT_ID_LAST_SPECIAL.0).contains(&self.0) + (0..=Self::LAST_SPECIAL.0).contains(&self.0) } /// Chat ID for messages which need to be deleted. @@ -161,7 +168,7 @@ impl ChatId { /// as they are not deleted on the server so that their rfc724_mid /// remains known and downloading them again can be avoided. pub fn is_trash(self) -> bool { - self == DC_CHAT_ID_TRASH + self == Self::TRASH } /// Chat ID signifying there are **any** number of archived chats. @@ -171,7 +178,7 @@ impl ChatId { /// /// [`Chatlist`]: crate::chatlist::Chatlist pub fn is_archived_link(self) -> bool { - self == DC_CHAT_ID_ARCHIVED_LINK + self == Self::ARCHIVED_LINK } /// Virtual chat ID signalling there are **only** archived chats. @@ -183,12 +190,12 @@ impl ChatId { /// [`DC_GCL_ADD_ALLDONE_HINT`]: crate::constants::DC_GCL_ADD_ALLDONE_HINT /// [`Chatlist`]: crate::chatlist::Chatlist pub fn is_alldone_hint(self) -> bool { - self == DC_CHAT_ID_ALLDONE_HINT + self == Self::ALLDONE_HINT } /// Returns [`ChatId`] of a chat that `msg` belongs to. pub(crate) fn lookup_by_message(msg: &Message) -> Option { - if msg.chat_id == DC_CHAT_ID_TRASH { + if msg.chat_id == Self::TRASH { return None; } if msg.download_state == DownloadState::Undecipherable { @@ -578,7 +585,7 @@ impl ChatId { /// `msg_state` is the state of the message. Matters only for incoming messages currently. For /// multiple outgoing messages the function may be called once with MessageState::Undefined. /// Sending an appropriate event is up to the caller. - /// Also emits DC_EVENT_MSGS_CHANGED for DC_CHAT_ID_ARCHIVED_LINK when the number of archived + /// Also emits DC_EVENT_MSGS_CHANGED for ChatId::ARCHIVED_LINK when the number of archived /// chats with unread messages increases (which is possible if the chat is muted). pub async fn unarchive_if_not_muted( self, @@ -614,7 +621,7 @@ impl ChatId { .await?; if unread_cnt == 1 { // Added the first unread message in the chat. - context.emit_msgs_changed_without_msg_id(DC_CHAT_ID_ARCHIVED_LINK); + context.emit_msgs_changed_without_msg_id(ChatId::ARCHIVED_LINK); } return Ok(()); } @@ -680,7 +687,7 @@ impl ChatId { INSERT OR REPLACE INTO msgs (id, rfc724_mid, pre_rfc724_mid, timestamp, chat_id, deleted) SELECT id, rfc724_mid, pre_rfc724_mid, timestamp, ?, 1 FROM msgs WHERE chat_id=? ", - (DC_CHAT_ID_TRASH, self), + (ChatId::TRASH, self), )?; transaction.execute("DELETE FROM chats_contacts WHERE chat_id=?", (self,))?; transaction.execute("DELETE FROM chats WHERE id=?", (self,))?; @@ -1011,7 +1018,7 @@ SELECT id, rfc724_mid, pre_rfc724_mid, timestamp, ?, 1 FROM msgs WHERE chat_id=? AND y.chat_id<>x.chat_id AND y.chat_id>? GROUP BY y.chat_id", - (self, DC_CHAT_ID_LAST_SPECIAL), + (self, ChatId::LAST_SPECIAL), |row| { let chat_id: ChatId = row.get(0)?; let intersection: f64 = row.get(1)?; @@ -1029,7 +1036,7 @@ SELECT id, rfc724_mid, pre_rfc724_mid, timestamp, ?, 1 FROM msgs WHERE chat_id=? WHERE contact_id > ? AND chat_id > ? AND add_timestamp >= remove_timestamp GROUP BY chat_id", - (ContactId::LAST_SPECIAL, DC_CHAT_ID_LAST_SPECIAL), + (ContactId::LAST_SPECIAL, ChatId::LAST_SPECIAL), |row| { let chat_id: ChatId = row.get(0)?; let size: f64 = row.get(1)?; @@ -2369,7 +2376,7 @@ impl ChatIdBlocked { INNER JOIN chats_contacts j ON c.id=j.chat_id WHERE c.type=100 -- 100 = Chattype::Single - AND c.id>9 -- 9 = DC_CHAT_ID_LAST_SPECIAL + AND c.id>9 -- 9 = ChatId::LAST_SPECIAL AND j.contact_id=?;", (contact_id,), |row| { @@ -3489,7 +3496,7 @@ pub async fn get_chat_media( ( chat_id.is_none(), chat_id.unwrap_or_else(|| ChatId::new(0)), - DC_CHAT_ID_TRASH, + ChatId::TRASH, Viewtype::Webxdc, ), |row| { @@ -3512,7 +3519,7 @@ pub async fn get_chat_media( ( chat_id.is_none(), chat_id.unwrap_or_else(|| ChatId::new(0)), - DC_CHAT_ID_TRASH, + ChatId::TRASH, msg_type, if msg_type2 != Viewtype::Unknown { msg_type2 @@ -5384,7 +5391,7 @@ impl Context { /// a noticed chat is archived. Emitting events should be cheap, a false-positive `MsgsChanged` /// is ok. pub(crate) fn on_archived_chats_maybe_noticed(&self) { - self.emit_msgs_changed_without_msg_id(DC_CHAT_ID_ARCHIVED_LINK); + self.emit_msgs_changed_without_msg_id(ChatId::ARCHIVED_LINK); } } diff --git a/src/chat/chat_tests.rs b/src/chat/chat_tests.rs index 53be6cde18..5304bf14b7 100644 --- a/src/chat/chat_tests.rs +++ b/src/chat/chat_tests.rs @@ -77,7 +77,7 @@ async fn test_get_draft_no_draft() { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_get_draft_special_chat_id() { let t = TestContext::new().await; - let draft = DC_CHAT_ID_LAST_SPECIAL.get_draft(&t).await.unwrap(); + let draft = ChatId::LAST_SPECIAL.get_draft(&t).await.unwrap(); assert!(draft.is_none()); } @@ -1096,7 +1096,7 @@ async fn test_archive() { == ChatVisibility::Normal ); assert_eq!(get_chat_cnt(&t).await.unwrap(), 2); - assert_eq!(chatlist_len(&t, 0).await, 2); // including DC_CHAT_ID_ARCHIVED_LINK now + assert_eq!(chatlist_len(&t, 0).await, 2); // including ChatId::ARCHIVED_LINK now assert_eq!(chatlist_len(&t, DC_GCL_NO_SPECIALS).await, 1); assert_eq!(chatlist_len(&t, DC_GCL_ARCHIVED_ONLY).await, 1); @@ -1122,7 +1122,7 @@ async fn test_archive() { == ChatVisibility::Archived ); assert_eq!(get_chat_cnt(&t).await.unwrap(), 2); - assert_eq!(chatlist_len(&t, 0).await, 1); // only DC_CHAT_ID_ARCHIVED_LINK now + assert_eq!(chatlist_len(&t, 0).await, 1); // only ChatId::ARCHIVED_LINK now assert_eq!(chatlist_len(&t, DC_GCL_NO_SPECIALS).await, 0); assert_eq!(chatlist_len(&t, DC_GCL_ARCHIVED_ONLY).await, 2); @@ -1333,7 +1333,7 @@ async fn test_marknoticed_all_chats() -> Result<()> { chat_id: Some(alice_chat_archived_and_muted), }, EventType::ChatlistItemChanged { - chat_id: Some(DC_CHAT_ID_ARCHIVED_LINK), + chat_id: Some(ChatId::ARCHIVED_LINK), }, ] { assert!(emitted_events.iter().any(|Event { typ, .. }| typ == event)); @@ -1434,13 +1434,13 @@ async fn test_archive_fresh_msgs() -> Result<()> { bob_chat_id .set_visibility(&t, ChatVisibility::Archived) .await?; - assert_eq!(DC_CHAT_ID_ARCHIVED_LINK.get_fresh_msg_cnt(&t).await?, 0); + assert_eq!(ChatId::ARCHIVED_LINK.get_fresh_msg_cnt(&t).await?, 0); msg_from(&t, "bob", 2).await?; - assert_eq!(DC_CHAT_ID_ARCHIVED_LINK.get_fresh_msg_cnt(&t).await?, 1); + assert_eq!(ChatId::ARCHIVED_LINK.get_fresh_msg_cnt(&t).await?, 1); msg_from(&t, "bob", 3).await?; - assert_eq!(DC_CHAT_ID_ARCHIVED_LINK.get_fresh_msg_cnt(&t).await?, 1); + assert_eq!(ChatId::ARCHIVED_LINK.get_fresh_msg_cnt(&t).await?, 1); msg_from(&t, "claire", 4).await?; let claire_chat_id = t.get_last_msg().await.get_chat_id(); @@ -1454,7 +1454,7 @@ async fn test_archive_fresh_msgs() -> Result<()> { msg_from(&t, "claire", 7).await?; assert_eq!(bob_chat_id.get_fresh_msg_cnt(&t).await?, 2); assert_eq!(claire_chat_id.get_fresh_msg_cnt(&t).await?, 3); - assert_eq!(DC_CHAT_ID_ARCHIVED_LINK.get_fresh_msg_cnt(&t).await?, 2); + assert_eq!(ChatId::ARCHIVED_LINK.get_fresh_msg_cnt(&t).await?, 2); // mark one of the archived+muted chats as noticed: check that the archive-link counter is changed as well t.evtracker.clear_events(); @@ -1465,7 +1465,7 @@ async fn test_archive_fresh_msgs() -> Result<()> { matches!( ev, EventType::MsgsChanged { - chat_id: DC_CHAT_ID_ARCHIVED_LINK, + chat_id: ChatId::ARCHIVED_LINK, .. } ) @@ -1474,34 +1474,34 @@ async fn test_archive_fresh_msgs() -> Result<()> { assert_eq!( ev, EventType::MsgsChanged { - chat_id: DC_CHAT_ID_ARCHIVED_LINK, + chat_id: ChatId::ARCHIVED_LINK, msg_id: MsgId::new(0), } ); assert_eq!(bob_chat_id.get_fresh_msg_cnt(&t).await?, 2); assert_eq!(claire_chat_id.get_fresh_msg_cnt(&t).await?, 0); - assert_eq!(DC_CHAT_ID_ARCHIVED_LINK.get_fresh_msg_cnt(&t).await?, 1); + assert_eq!(ChatId::ARCHIVED_LINK.get_fresh_msg_cnt(&t).await?, 1); // receive some more messages msg_from(&t, "claire", 8).await?; assert_eq!(bob_chat_id.get_fresh_msg_cnt(&t).await?, 2); assert_eq!(claire_chat_id.get_fresh_msg_cnt(&t).await?, 1); - assert_eq!(DC_CHAT_ID_ARCHIVED_LINK.get_fresh_msg_cnt(&t).await?, 2); + assert_eq!(ChatId::ARCHIVED_LINK.get_fresh_msg_cnt(&t).await?, 2); assert_eq!(t.get_fresh_msgs().await?.len(), 0); msg_from(&t, "dave", 9).await?; let dave_chat_id = t.get_last_msg().await.get_chat_id(); dave_chat_id.accept(&t).await?; assert_eq!(dave_chat_id.get_fresh_msg_cnt(&t).await?, 1); - assert_eq!(DC_CHAT_ID_ARCHIVED_LINK.get_fresh_msg_cnt(&t).await?, 2); + assert_eq!(ChatId::ARCHIVED_LINK.get_fresh_msg_cnt(&t).await?, 2); assert_eq!(t.get_fresh_msgs().await?.len(), 1); // mark the archived-link as noticed: check that the real chats are noticed as well - marknoticed_chat(&t, DC_CHAT_ID_ARCHIVED_LINK).await?; + marknoticed_chat(&t, ChatId::ARCHIVED_LINK).await?; assert_eq!(bob_chat_id.get_fresh_msg_cnt(&t).await?, 0); assert_eq!(claire_chat_id.get_fresh_msg_cnt(&t).await?, 0); assert_eq!(dave_chat_id.get_fresh_msg_cnt(&t).await?, 1); - assert_eq!(DC_CHAT_ID_ARCHIVED_LINK.get_fresh_msg_cnt(&t).await?, 0); + assert_eq!(ChatId::ARCHIVED_LINK.get_fresh_msg_cnt(&t).await?, 0); assert_eq!(t.get_fresh_msgs().await?.len(), 1); Ok(()) diff --git a/src/chatlist.rs b/src/chatlist.rs index aaefe1b31a..eb9dd51e27 100644 --- a/src/chatlist.rs +++ b/src/chatlist.rs @@ -5,8 +5,8 @@ use std::sync::LazyLock; use crate::chat::{Chat, ChatId, ChatVisibility, update_special_chat_names}; use crate::constants::{ - Blocked, Chattype, DC_CHAT_ID_ALLDONE_HINT, DC_CHAT_ID_ARCHIVED_LINK, DC_GCL_ADD_ALLDONE_HINT, - DC_GCL_ARCHIVED_ONLY, DC_GCL_FOR_FORWARDING, DC_GCL_NO_SPECIALS, + Blocked, Chattype, DC_GCL_ADD_ALLDONE_HINT, DC_GCL_ARCHIVED_ONLY, DC_GCL_FOR_FORWARDING, + DC_GCL_NO_SPECIALS, }; use crate::contact::{Contact, ContactId}; use crate::context::Context; @@ -61,19 +61,19 @@ impl Chatlist { /// /// By default, the function adds some special entries to the list. /// These special entries can be identified by the ID returned by chatlist.get_chat_id(): - /// - DC_CHAT_ID_ARCHIVED_LINK (6) - this special chat is present if the user has + /// - ChatId::ARCHIVED_LINK (6) - this special chat is present if the user has /// archived *any* chat using dc_set_chat_visibility(). The UI should show a link as /// "Show archived chats", if the user clicks this item, the UI should show a /// list of all archived chats that can be created by this function hen using /// the DC_GCL_ARCHIVED_ONLY flag. - /// - DC_CHAT_ID_ALLDONE_HINT (7) - this special chat is present + /// - ChatId::ALLDONE_HINT (7) - this special chat is present /// if DC_GCL_ADD_ALLDONE_HINT is added to listflags /// and if there are only archived chats. /// /// The `listflags` is a combination of flags: /// - if the flag DC_GCL_ARCHIVED_ONLY is set, only archived chats are returned. /// if DC_GCL_ARCHIVED_ONLY is not set, only unarchived chats are returned and - /// the pseudo-chat DC_CHAT_ID_ARCHIVED_LINK is added if there are *any* archived + /// the pseudo-chat ChatId::ARCHIVED_LINK is added if there are *any* archived /// chats /// - the flag DC_GCL_FOR_FORWARDING sorts "Saved messages" to the top of the chatlist /// and hides the device-chat, contact requests and incoming broadcasts. @@ -81,7 +81,7 @@ impl Chatlist { /// - if the flag DC_GCL_NO_SPECIALS is set, archive link is not added /// to the list (may be used eg. for selecting chats on forwarding, the flag is /// not needed when DC_GCL_ARCHIVED_ONLY is already set) - /// - if the flag DC_GCL_ADD_ALLDONE_HINT is set, DC_CHAT_ID_ALLDONE_HINT + /// - if the flag DC_GCL_ADD_ALLDONE_HINT is set, ChatId::ALLDONE_HINT /// is added as needed. /// /// `query`: An optional query for filtering the list. Only chats matching this query @@ -272,9 +272,9 @@ ORDER BY timestamp DESC, id DESC LIMIT 1)" }; if !flag_no_specials && get_archived_cnt(context).await? > 0 { if ids.is_empty() && flag_add_alldone_hint { - ids.push((DC_CHAT_ID_ALLDONE_HINT, None)); + ids.push((ChatId::ALLDONE_HINT, None)); } - ids.insert(0, (DC_CHAT_ID_ARCHIVED_LINK, None)); + ids.insert(0, (ChatId::ARCHIVED_LINK, None)); } ids }; diff --git a/src/constants.rs b/src/constants.rs index 9a0aefd4d4..469a8ab42d 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -6,8 +6,6 @@ use deltachat_derive::{FromSql, ToSql}; use percent_encoding::{AsciiSet, NON_ALPHANUMERIC}; use serde::{Deserialize, Serialize}; -use crate::chat::ChatId; - pub static DC_VERSION_STR: &str = env!("CARGO_PKG_VERSION"); /// Set of characters to percent-encode in email addresses and names. @@ -70,15 +68,6 @@ pub(crate) const DC_RESEND_USER_AVATAR_DAYS: i64 = 14; // "90 days" has proven to be too short at some point (user were informed but there was no update) pub(crate) const DC_OUTDATED_WARNING_DAYS: i64 = 183; -/// messages that should be deleted get this chat_id; the messages are deleted from the working thread later then. This is also needed as rfc724_mid should be preset as long as the message is not deleted on the server (otherwise it is downloaded again) -pub const DC_CHAT_ID_TRASH: ChatId = ChatId::new(3); -/// only an indicator in a chatlist -pub const DC_CHAT_ID_ARCHIVED_LINK: ChatId = ChatId::new(6); -/// only an indicator in a chatlist -pub const DC_CHAT_ID_ALLDONE_HINT: ChatId = ChatId::new(7); -/// larger chat IDs are "real" chats, their messages are "real" messages. -pub const DC_CHAT_ID_LAST_SPECIAL: ChatId = ChatId::new(9); - /// Chat type. #[derive( Debug, @@ -101,7 +90,7 @@ pub const DC_CHAT_ID_LAST_SPECIAL: ChatId = ChatId::new(9); pub enum Chattype { /// A single chat (a chat with a single contact). /// - /// Created by [`ChatId::create_for_contact`]. + /// Created by [`crate::chat::ChatId::create_for_contact`]. Single = 100, /// Group chat. diff --git a/src/contact.rs b/src/contact.rs index 88d43bfe81..6fb0ad2497 100644 --- a/src/contact.rs +++ b/src/contact.rs @@ -892,7 +892,7 @@ impl Contact { blocked.is_none(), blocked.unwrap_or(Blocked::Not), Chattype::Single, - constants::DC_CHAT_ID_LAST_SPECIAL, + ChatId::LAST_SPECIAL, blocked.unwrap_or(Blocked::Not), ), ) diff --git a/src/ephemeral.rs b/src/ephemeral.rs index 19d1b1ca7c..d5b9a388ac 100644 --- a/src/ephemeral.rs +++ b/src/ephemeral.rs @@ -74,7 +74,6 @@ use tokio::time::timeout; use crate::chat::{ChatId, ChatIdBlocked, send_msg}; use crate::config::Config; -use crate::constants::{DC_CHAT_ID_LAST_SPECIAL, DC_CHAT_ID_TRASH}; use crate::contact::ContactId; use crate::context::Context; use crate::download::DownloadState; @@ -384,7 +383,7 @@ WHERE AND ephemeral_timestamp <= ? AND chat_id != ? "#, - (now, DC_CHAT_ID_TRASH), + (now, ChatId::TRASH), |row| { let id: MsgId = row.get("id")?; let chat_id: ChatId = row.get("chat_id")?; @@ -426,7 +425,7 @@ WHERE "#, ( threshold_timestamp, - DC_CHAT_ID_LAST_SPECIAL, + ChatId::LAST_SPECIAL, self_chat_id, device_chat_id, ), @@ -480,7 +479,7 @@ SELECT ?1, rfc724_mid, pre_rfc724_mid, timestamp, ? FROM msgs WHERE id=?1 let mut del_location_stmt = transaction.prepare("DELETE FROM locations WHERE independent=1 AND id=?")?; for (msg_id, chat_id, viewtype, location_id) in rows { - del_msg_stmt.execute((msg_id, DC_CHAT_ID_TRASH))?; + del_msg_stmt.execute((msg_id, ChatId::TRASH))?; if location_id > 0 { del_location_stmt.execute((location_id,))?; } @@ -537,7 +536,7 @@ async fn next_delete_device_after_timestamp(context: &Context) -> Result 0 "#, - (DC_CHAT_ID_TRASH, self_chat_id, device_chat_id), + (ChatId::TRASH, self_chat_id, device_chat_id), ) .await?; @@ -562,7 +561,7 @@ async fn next_expiration_timestamp(context: &Context) -> Option { AND chat_id != ? HAVING count(*) > 0 "#, - (DC_CHAT_ID_TRASH,), // Trash contains already deleted messages, skip them + (ChatId::TRASH,), // Trash contains already deleted messages, skip them ) .await { diff --git a/src/ephemeral/ephemeral_tests.rs b/src/ephemeral/ephemeral_tests.rs index 46d2806b3f..81e003612a 100644 --- a/src/ephemeral/ephemeral_tests.rs +++ b/src/ephemeral/ephemeral_tests.rs @@ -1,10 +1,9 @@ use super::*; use crate::chat::{ - ChatVisibility, MuteDuration, add_contact_to_chat, marknoticed_chat, remove_contact_from_chat, - set_muted, + ChatId, ChatVisibility, MuteDuration, add_contact_to_chat, marknoticed_chat, + remove_contact_from_chat, set_muted, }; use crate::config::Config; -use crate::constants::DC_CHAT_ID_ARCHIVED_LINK; use crate::download::DownloadState; use crate::location; use crate::message::{estimate_deletion_cnt, markseen_msgs}; @@ -798,7 +797,7 @@ async fn test_archived_ephemeral_timer() -> Result<()> { let bob_received_message_2 = tcm.send_recv(alice, bob, "Hello again!").await; assert_eq!(bob_received_message_2.state, MessageState::InFresh); - marknoticed_chat(bob, DC_CHAT_ID_ARCHIVED_LINK).await?; + marknoticed_chat(bob, ChatId::ARCHIVED_LINK).await?; SystemTime::shift(Duration::from_secs(100)); delete_expired_messages(bob, time()).await?; diff --git a/src/events/chatlist_events.rs b/src/events/chatlist_events.rs index 000bee717a..3180626a57 100644 --- a/src/events/chatlist_events.rs +++ b/src/events/chatlist_events.rs @@ -68,7 +68,6 @@ mod test_chatlist_events { self, ChatId, ChatVisibility, MuteDuration, create_broadcast, create_group, set_muted, }, config::Config, - constants::*, contact::Contact, message::{self, Message, MessageState}, reaction, @@ -206,8 +205,8 @@ mod test_chatlist_events { bob.recv_msg(&sent_msg).await; bob.evtracker.clear_events(); - chat::marknoticed_chat(&bob, DC_CHAT_ID_ARCHIVED_LINK).await?; - wait_for_chatlist_specific_item(&bob, DC_CHAT_ID_ARCHIVED_LINK).await; + chat::marknoticed_chat(&bob, ChatId::ARCHIVED_LINK).await?; + wait_for_chatlist_specific_item(&bob, ChatId::ARCHIVED_LINK).await; Ok(()) } diff --git a/src/location.rs b/src/location.rs index bd12767dc4..ce2e25a95a 100644 --- a/src/location.rs +++ b/src/location.rs @@ -19,7 +19,6 @@ use quick_xml::events::{BytesEnd, BytesStart, BytesText}; use tokio::time::timeout; use crate::chat::{self, ChatId}; -use crate::constants::DC_CHAT_ID_TRASH; use crate::contact::ContactId; use crate::context::Context; use crate::events::EventType; @@ -504,7 +503,7 @@ pub(crate) async fn delete_orphaned_poi(context: &Context) -> Result<()> { (SELECT location_id from MSGS LEFT JOIN locations ON locations.id=location_id WHERE location_id>0 -- This check makes the query faster by not looking for locations with ID 0 that don't exist. - AND msgs.chat_id != ?)", (DC_CHAT_ID_TRASH,)).await?; + AND msgs.chat_id != ?)", (ChatId::TRASH,)).await?; Ok(()) } diff --git a/src/message.rs b/src/message.rs index 6dab8ef5a0..db64daaa3f 100644 --- a/src/message.rs +++ b/src/message.rs @@ -17,7 +17,7 @@ use crate::blob::BlobObject; use crate::chat::{Chat, ChatId, ChatIdBlocked, ChatVisibility, send_msg}; use crate::chatlist_events; use crate::config::Config; -use crate::constants::{Blocked, Chattype, DC_CHAT_ID_TRASH, DC_MSG_ID_LAST_SPECIAL}; +use crate::constants::{Blocked, Chattype, DC_MSG_ID_LAST_SPECIAL}; use crate::contact::{self, Contact, ContactId}; use crate::context::Context; use crate::debug_logging::set_debug_logging_xdc; @@ -132,7 +132,7 @@ impl MsgId { INSERT OR REPLACE INTO msgs (id, rfc724_mid, pre_rfc724_mid, timestamp, chat_id, deleted) SELECT ?1, rfc724_mid, pre_rfc724_mid, timestamp, ?, ? FROM msgs WHERE id=?1 ", - (self, DC_CHAT_ID_TRASH, on_server), + (self, ChatId::TRASH, on_server), ) .await?; @@ -518,7 +518,7 @@ impl Message { FROM msgs m LEFT JOIN chats c ON c.id=m.chat_id LEFT JOIN msgs_mdns mdns ON mdns.msg_id=m.id - WHERE m.id=? AND chat_id!=3 -- DC_CHAT_ID_TRASH + WHERE m.id=? AND chat_id!=3 -- ChatId::TRASH LIMIT 1", (id,), |row| { @@ -602,7 +602,7 @@ impl Message { .sql .query_row_optional( "SELECT id FROM msgs WHERE rfc724_mid=? AND chat_id != ?", - (rfc724_mid, DC_CHAT_ID_TRASH), + (rfc724_mid, ChatId::TRASH), |row| { let msg_id: MsgId = row.get(0)?; Ok(msg_id) @@ -1319,7 +1319,7 @@ impl Message { .sql .query_get_value( "SELECT id FROM msgs WHERE starred=? AND chat_id!=?", - (self.id, DC_CHAT_ID_TRASH), + (self.id, ChatId::TRASH), ) .await?; Ok(res) @@ -2018,7 +2018,7 @@ pub(crate) async fn insert_tombstone(context: &Context, rfc724_mid: &str) -> Res .sql .insert( "INSERT INTO msgs(rfc724_mid, chat_id) VALUES (?,?)", - (rfc724_mid, DC_CHAT_ID_TRASH), + (rfc724_mid, ChatId::TRASH), ) .await?; let msg_id = MsgId::new(u32::try_from(row_id)?); @@ -2109,7 +2109,7 @@ pub async fn estimate_deletion_cnt( DC_MSG_ID_LAST_SPECIAL, threshold_timestamp, self_chat_id, - DC_CHAT_ID_TRASH, + ChatId::TRASH, ), ) .await?; diff --git a/src/message/message_tests.rs b/src/message/message_tests.rs index 50d4a653d9..e34cf8c2f7 100644 --- a/src/message/message_tests.rs +++ b/src/message/message_tests.rs @@ -338,7 +338,7 @@ async fn test_msg_seen_on_imap_when_downloaded() -> Result<()> { let rcvd_msg = receive_imf(alice, sent_msg.payload().as_bytes(), seen) .await? .unwrap(); - assert_eq!(rcvd_msg.chat_id, DC_CHAT_ID_TRASH); + assert_eq!(rcvd_msg.chat_id, ChatId::TRASH); let msg = Message::load_from_db(alice, msg.id).await?; assert_eq!(msg.download_state, DownloadState::Done); assert!(msg.param.get_bool(Param::WantsMdn).unwrap_or_default()); diff --git a/src/mimeparser/shared_secret_decryption_tests.rs b/src/mimeparser/shared_secret_decryption_tests.rs index a65caacfdf..beec12a1d1 100644 --- a/src/mimeparser/shared_secret_decryption_tests.rs +++ b/src/mimeparser/shared_secret_decryption_tests.rs @@ -1,6 +1,5 @@ use super::*; -use crate::chat::{create_broadcast, load_broadcast_secret}; -use crate::constants::DC_CHAT_ID_TRASH; +use crate::chat::{ChatId, create_broadcast, load_broadcast_secret}; use crate::key::{load_self_secret_key, self_fingerprint}; use crate::pgp; use crate::qr::{Qr, check_qr}; @@ -83,7 +82,7 @@ async fn test_shared_secret_decryption_ext( .expect("A trashed message should be created, otherwise we'll unnecessarily download it again"); if let Some(error_pattern) = expected_error { - assert!(rcvd.chat_id == DC_CHAT_ID_TRASH); + assert_eq!(rcvd.chat_id, ChatId::TRASH); assert_eq!( previous_highest_msg_id, get_highest_msg_id(recipient_ctx).await, @@ -112,7 +111,7 @@ async fn get_highest_msg_id(context: &Context) -> MsgId { .sql .query_get_value( "SELECT MAX(id) FROM msgs WHERE chat_id!=?", - (DC_CHAT_ID_TRASH,), + (ChatId::TRASH,), ) .await .unwrap() diff --git a/src/receive_imf.rs b/src/receive_imf.rs index ea24dff75f..9a0df5e2d9 100644 --- a/src/receive_imf.rs +++ b/src/receive_imf.rs @@ -18,7 +18,7 @@ use crate::chat::{ self, Chat, ChatId, ChatIdBlocked, ChatVisibility, is_contact_in_chat, save_broadcast_secret, }; use crate::config::Config; -use crate::constants::{self, Blocked, Chattype, DC_CHAT_ID_TRASH, EDITED_PREFIX}; +use crate::constants::{Blocked, Chattype, EDITED_PREFIX}; use crate::contact::{self, Contact, ContactId, Origin, mark_contact_id_as_verified}; use crate::context::Context; use crate::debug_logging::maybe_set_logging_xdc_inner; @@ -460,7 +460,7 @@ async fn get_to_and_past_contact_ids( /// e.g. has nonstandard MIME structure. /// /// If possible, creates a database entry to prevent the message from being -/// downloaded again, sets `chat_id=DC_CHAT_ID_TRASH` and returns `Ok(Some(…))`. +/// downloaded again, sets `chat_id=ChatId::TRASH` and returns `Ok(Some(…))`. /// If the message is so wrong that we didn't even create a database entry, /// returns `Ok(None)`. pub(crate) async fn receive_imf_inner( @@ -485,7 +485,7 @@ pub(crate) async fn receive_imf_inner( let trash = || async { let msg_ids = vec![insert_tombstone(context, rfc724_mid).await?]; Ok(Some(ReceivedMsg { - chat_id: DC_CHAT_ID_TRASH, + chat_id: ChatId::TRASH, state: MessageState::Undefined, hidden: false, sort_timestamp: 0, @@ -662,7 +662,7 @@ pub(crate) async fn receive_imf_inner( securejoin::HandshakeMessage::Done | securejoin::HandshakeMessage::Ignore => { let msg_id = insert_tombstone(context, rfc724_mid).await?; received_msg = Some(ReceivedMsg { - chat_id: DC_CHAT_ID_TRASH, + chat_id: ChatId::TRASH, state: MessageState::InSeen, hidden: false, sort_timestamp: mime_parser.timestamp_sent, @@ -1441,7 +1441,7 @@ async fn do_chat_assignment( match &chat_assignment { ChatAssignment::Trash => { - chat_id = Some(DC_CHAT_ID_TRASH); + chat_id = Some(ChatId::TRASH); } ChatAssignment::GroupChat { grpid } => { // Try to assign to a chat based on Chat-Group-ID. @@ -1571,7 +1571,7 @@ async fn do_chat_assignment( match &chat_assignment { ChatAssignment::Trash => { - chat_id = Some(DC_CHAT_ID_TRASH); + chat_id = Some(ChatId::TRASH); } ChatAssignment::GroupChat { grpid } => { if let Some((id, blocked)) = chat::get_chat_id_by_grpid(context, grpid).await? { @@ -1706,7 +1706,7 @@ async fn do_chat_assignment( } let chat_id = chat_id.unwrap_or_else(|| { info!(context, "No chat id for message (TRASH)."); - DC_CHAT_ID_TRASH + ChatId::TRASH }); Ok((chat_id, chat_id_blocked, chat_created)) } @@ -2010,7 +2010,7 @@ async fn add_parts( .as_ref() .is_some_and(|better_msg| better_msg.is_empty()) { - DC_CHAT_ID_TRASH + ChatId::TRASH } else { chat_id }; @@ -2200,7 +2200,7 @@ INSERT INTO msgs } else { "" }, - if trash { DC_CHAT_ID_TRASH } else { chat_id }, + if trash { ChatId::TRASH } else { chat_id }, if trash { ContactId::UNDEFINED } else { from_id }, if trash { ContactId::UNDEFINED } else { to_id }, sort_timestamp, @@ -2886,7 +2886,7 @@ async fn create_group( // The message was decrypted successfully, but contains a late "quit" or otherwise // unwanted message. info!(context, "Message belongs to unwanted group (TRASH)."); - Ok(Some((DC_CHAT_ID_TRASH, Blocked::Not))) + Ok(Some((ChatId::TRASH, Blocked::Not))) } } @@ -3925,7 +3925,7 @@ async fn create_adhoc_group( context, "Message removes member from unknown ad-hoc group (TRASH)." ); - return Ok(Some((DC_CHAT_ID_TRASH, Blocked::Not))); + return Ok(Some((ChatId::TRASH, Blocked::Not))); } let new_chat_id: ChatId = ChatId::create_multiuser_record( @@ -4217,12 +4217,7 @@ async fn lookup_key_contact_by_address( ) DESC, last_seen DESC, id DESC ", - ( - addr, - Chattype::Single, - constants::DC_CHAT_ID_LAST_SPECIAL, - Blocked::Not, - ), + (addr, Chattype::Single, ChatId::LAST_SPECIAL, Blocked::Not), |row| { let contact_id: ContactId = row.get(0)?; Ok(contact_id) diff --git a/src/receive_imf/receive_imf_tests.rs b/src/receive_imf/receive_imf_tests.rs index 1c728c9875..3808a3c1c4 100644 --- a/src/receive_imf/receive_imf_tests.rs +++ b/src/receive_imf/receive_imf_tests.rs @@ -348,7 +348,7 @@ async fn test_no_message_id_header() { !t.sql .exists( "SELECT COUNT(*) FROM msgs WHERE chat_id=?;", - (DC_CHAT_ID_TRASH,), + (ChatId::TRASH,), ) .await .unwrap() diff --git a/src/securejoin/securejoin_tests.rs b/src/securejoin/securejoin_tests.rs index f5801dd689..777c0a1d3f 100644 --- a/src/securejoin/securejoin_tests.rs +++ b/src/securejoin/securejoin_tests.rs @@ -4,10 +4,9 @@ use deltachat_contact_tools::EmailAddress; use regex::Regex; use super::*; -use crate::chat::{CantSendReason, add_contact_to_chat, remove_contact_from_chat}; +use crate::chat::{CantSendReason, ChatId, add_contact_to_chat, remove_contact_from_chat}; use crate::chatlist::Chatlist; use crate::constants::Chattype; -use crate::constants::DC_CHAT_ID_TRASH; use crate::key::self_fingerprint; use crate::mimeparser::{GossipedKey, SystemMessage}; use crate::qr::Qr; @@ -1534,7 +1533,7 @@ gU6dGXsFMe/RpRHrIAkMAaM5xkxMDRuRJDxiUdS/X+Y8 let received = receive_imf(alice, payload.as_bytes(), false) .await? .unwrap(); - assert_eq!(received.chat_id, DC_CHAT_ID_TRASH); + assert_eq!(received.chat_id, ChatId::TRASH); // Test that Alice sends vc-auth-required after processing vc-request. let sent = alice.pop_sent_msg().await; diff --git a/src/sql.rs b/src/sql.rs index c8bed0d40b..6a2de66e28 100644 --- a/src/sql.rs +++ b/src/sql.rs @@ -9,8 +9,8 @@ use rusqlite::{Connection, OpenFlags, Row, config::DbConfig, types::ValueRef}; use tokio::sync::RwLock; use crate::blob::BlobObject; +use crate::chat::ChatId; use crate::config::Config; -use crate::constants::DC_CHAT_ID_TRASH; use crate::context::Context; use crate::debug_logging::set_debug_logging_xdc; use crate::ephemeral::start_ephemeral_timers; @@ -842,7 +842,7 @@ pub async fn housekeeping(context: &Context) -> Result<()> { .execute( "DELETE FROM msgs_mdns WHERE msg_id NOT IN \ (SELECT id FROM msgs WHERE chat_id!=?)", - (DC_CHAT_ID_TRASH,), + (ChatId::TRASH,), ) .await .context("failed to remove old MDNs") @@ -854,7 +854,7 @@ pub async fn housekeeping(context: &Context) -> Result<()> { .execute( "DELETE FROM msgs_status_updates WHERE msg_id NOT IN \ (SELECT id FROM msgs WHERE chat_id!=?)", - (DC_CHAT_ID_TRASH,), + (ChatId::TRASH,), ) .await .context("failed to remove old webxdc status updates") @@ -1209,7 +1209,7 @@ async fn prune_tombstones(sql: &Sql) -> Result<()> { AND NOT EXISTS ( SELECT * FROM imap WHERE msgs.rfc724_mid=rfc724_mid AND target!='' )", - (DC_CHAT_ID_TRASH, timestamp_max), + (ChatId::TRASH, timestamp_max), ) .await?; Ok(()) diff --git a/src/test_utils.rs b/src/test_utils.rs index f9974960ab..810217fcc3 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -29,8 +29,7 @@ use crate::chat::{ }; use crate::chatlist::Chatlist; use crate::config::Config; -use crate::constants::{Blocked, Chattype}; -use crate::constants::{DC_CHAT_ID_TRASH, DC_GCL_NO_SPECIALS}; +use crate::constants::{Blocked, Chattype, DC_GCL_NO_SPECIALS}; use crate::contact::{ Contact, ContactId, Modifier, Origin, import_vcard, make_vcard, mark_contact_id_as_verified, }; @@ -774,7 +773,7 @@ ORDER BY id" receive_imf(self, msg.payload().as_bytes(), false) .await .unwrap() - .filter(|msg| msg.chat_id != DC_CHAT_ID_TRASH) + .filter(|msg| msg.chat_id != ChatId::TRASH) } /// Receives a message and asserts that it goes to trash chat. @@ -783,7 +782,7 @@ ORDER BY id" .await .unwrap() .unwrap(); - assert_eq!(received.chat_id, DC_CHAT_ID_TRASH); + assert_eq!(received.chat_id, ChatId::TRASH); } /// Gets the most recent message ID of a chat. From 789da081523a739da6d755ccc080143affca6a14 Mon Sep 17 00:00:00 2001 From: link2xt Date: Sat, 22 Aug 2026 01:01:15 +0000 Subject: [PATCH 3/3] refactor: turn DC_MSG_ID_* into MsgId::* associated constants --- deltachat-ffi/src/dc_array.rs | 3 +-- deltachat-ffi/src/lib.rs | 5 ++--- deltachat-jsonrpc/src/api.rs | 5 ++--- deltachat-repl/src/cmdline.rs | 4 ++-- src/constants.rs | 3 --- src/message.rs | 27 +++++++++++---------------- 6 files changed, 18 insertions(+), 29 deletions(-) diff --git a/deltachat-ffi/src/dc_array.rs b/deltachat-ffi/src/dc_array.rs index 98def5d0e4..56307758e3 100644 --- a/deltachat-ffi/src/dc_array.rs +++ b/deltachat-ffi/src/dc_array.rs @@ -1,5 +1,4 @@ use crate::chat::ChatItem; -use crate::constants::DC_MSG_ID_DAYMARKER; use crate::contact::ContactId; use crate::location::Location; use crate::message::MsgId; @@ -21,7 +20,7 @@ impl dc_array_t { Self::ContactIds(array) => array[index].to_u32(), Self::Chat(array) => match array[index] { ChatItem::Message { msg_id } => msg_id.to_u32(), - ChatItem::DayMarker { .. } => DC_MSG_ID_DAYMARKER, + ChatItem::DayMarker { .. } => MsgId::DAYMARKER.to_u32(), }, Self::Locations(array) => array[index].location_id, Self::Uint(array) => array[index], diff --git a/deltachat-ffi/src/lib.rs b/deltachat-ffi/src/lib.rs index 5d0b8a69b8..66e05403ad 100644 --- a/deltachat-ffi/src/lib.rs +++ b/deltachat-ffi/src/lib.rs @@ -23,7 +23,6 @@ use std::time::{Duration, SystemTime}; use anyhow::Context as _; use deltachat::chat::{ChatId, ChatVisibility, MessageListOptions, MuteDuration}; -use deltachat::constants::DC_MSG_ID_LAST_SPECIAL; use deltachat::contact::{Contact, ContactId, Origin}; use deltachat::context::{Context, ContextBuilder}; use deltachat::ephemeral::Timer as EphemeralTimer; @@ -2038,7 +2037,7 @@ pub unsafe extern "C" fn dc_get_msg(context: *mut dc_context_t, msg_id: u32) -> { Ok(msg) => msg, Err(_) => { - if msg_id <= constants::DC_MSG_ID_LAST_SPECIAL { + if MsgId::new(msg_id).is_special() { // C-core API returns empty messages, do the same message::Message::new(Viewtype::default()) } else { @@ -4407,7 +4406,7 @@ fn convert_and_prune_message_ids(msg_ids: *const u32, msg_cnt: libc::c_int) -> V let ids = unsafe { std::slice::from_raw_parts(msg_ids, msg_cnt as usize) }; let msg_ids: Vec = ids .iter() - .filter(|id| **id > DC_MSG_ID_LAST_SPECIAL) + .filter(|id| **id > MsgId::LAST_SPECIAL.to_u32()) .map(|id| MsgId::new(*id)) .collect(); diff --git a/deltachat-jsonrpc/src/api.rs b/deltachat-jsonrpc/src/api.rs index a44bde8314..e06cd64640 100644 --- a/deltachat-jsonrpc/src/api.rs +++ b/deltachat-jsonrpc/src/api.rs @@ -17,7 +17,6 @@ use deltachat::chat::{ }; use deltachat::chatlist::Chatlist; use deltachat::config::{Config, get_all_ui_config_keys}; -use deltachat::constants::DC_MSG_ID_DAYMARKER; use deltachat::contact::{Contact, ContactId, Origin, may_be_valid_addr}; use deltachat::context::get_info; use deltachat::ephemeral::Timer; @@ -1382,7 +1381,7 @@ impl CommandApi { /// /// * chat_id The chat ID of which the messages IDs should be queried. /// * _info_only: Deprecated, pass `false` here. - /// * `add_daymarker` - If `true`, add day markers as `DC_MSG_ID_DAYMARKER` to the result, + /// * `add_daymarker` - If `true`, add day markers as `MsgId::DAYMARKER` to the result, /// e.g. [1234, 1237, 9, 1239]. The day marker timestamp is the midnight one for the /// corresponding (following) day in the local timezone. async fn get_message_ids( @@ -1404,7 +1403,7 @@ impl CommandApi { .map(|chat_item| -> u32 { match chat_item { deltachat::chat::ChatItem::Message { msg_id } => msg_id.to_u32(), - deltachat::chat::ChatItem::DayMarker { .. } => DC_MSG_ID_DAYMARKER, + deltachat::chat::ChatItem::DayMarker { .. } => MsgId::DAYMARKER.to_u32(), } }) .collect()) diff --git a/deltachat-repl/src/cmdline.rs b/deltachat-repl/src/cmdline.rs index 7070d2824a..098936350f 100644 --- a/deltachat-repl/src/cmdline.rs +++ b/deltachat-repl/src/cmdline.rs @@ -228,7 +228,7 @@ async fn log_msg(context: &Context, prefix: impl AsRef, msg: &Message) { async fn log_msglist(context: &Context, msglist: &[MsgId]) -> Result<()> { let mut lines_out = 0; for &msg_id in msglist { - if msg_id == MsgId::new(DC_MSG_ID_DAYMARKER) { + if msg_id == MsgId::DAYMARKER { println!( "--------------------------------------------------------------------------------" ); @@ -630,7 +630,7 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu .into_iter() .map(|x| match x { ChatItem::Message { msg_id } => msg_id, - ChatItem::DayMarker { .. } => MsgId::new(DC_MSG_ID_DAYMARKER), + ChatItem::DayMarker { .. } => MsgId::DAYMARKER, }) .collect(); diff --git a/src/constants.rs b/src/constants.rs index 469a8ab42d..9ded94cfae 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -130,9 +130,6 @@ pub enum Chattype { InBroadcast = 165, } -pub const DC_MSG_ID_DAYMARKER: u32 = 9; -pub const DC_MSG_ID_LAST_SPECIAL: u32 = 9; - /// String that indicates that something is left out or truncated. pub(crate) const DC_ELLIPSIS: &str = "[...]"; // how many lines desktop can display when fullscreen (fullscreen at zoomlevel 1x) diff --git a/src/message.rs b/src/message.rs index db64daaa3f..f6def15ada 100644 --- a/src/message.rs +++ b/src/message.rs @@ -4,7 +4,7 @@ use std::collections::BTreeSet; use std::path::{Path, PathBuf}; use std::str; -use anyhow::{Context as _, Result, ensure, format_err}; +use anyhow::{Context as _, Result, ensure}; use deltachat_contact_tools::{VcardContact, parse_vcard}; use deltachat_derive::{FromSql, ToSql}; use humansize::BINARY; @@ -17,7 +17,7 @@ use crate::blob::BlobObject; use crate::chat::{Chat, ChatId, ChatIdBlocked, ChatVisibility, send_msg}; use crate::chatlist_events; use crate::config::Config; -use crate::constants::{Blocked, Chattype, DC_MSG_ID_LAST_SPECIAL}; +use crate::constants::{Blocked, Chattype}; use crate::contact::{self, Contact, ContactId}; use crate::context::Context; use crate::debug_logging::set_debug_logging_xdc; @@ -49,13 +49,18 @@ use crate::tools::{ pub struct MsgId(u32); impl MsgId { + /// Markers added before each day in a local timezone. + pub const DAYMARKER: MsgId = MsgId::new(9); + /// Largest reserved message ID. + pub const LAST_SPECIAL: MsgId = MsgId::new(9); + /// Create a new [MsgId]. - pub fn new(id: u32) -> MsgId { + pub const fn new(id: u32) -> MsgId { MsgId(id) } /// Create a new unset [MsgId]. - pub fn new_unset() -> MsgId { + pub const fn new_unset() -> MsgId { MsgId(0) } @@ -63,7 +68,7 @@ impl MsgId { /// /// This kind of message ID can not be used for real messages. pub fn is_special(self) -> bool { - self.0 <= DC_MSG_ID_LAST_SPECIAL + (0..=Self::LAST_SPECIAL.0).contains(&self.0) } /// Whether the message ID is unset. @@ -355,18 +360,8 @@ impl std::fmt::Display for MsgId { /// Allow converting [MsgId] to an SQLite type. /// /// This allows you to directly store [MsgId] into the database. -/// -/// # Errors -/// -/// This **does** ensure that no special message IDs are written into -/// the database and the conversion will fail if this is not the case. impl rusqlite::types::ToSql for MsgId { fn to_sql(&self) -> rusqlite::Result> { - if self.0 <= DC_MSG_ID_LAST_SPECIAL { - return Err(rusqlite::Error::ToSqlConversionFailure( - format_err!("Invalid MsgId {}", self.0).into(), - )); - } let val = rusqlite::types::Value::Integer(i64::from(self.0)); let out = rusqlite::types::ToSqlOutput::Owned(val); Ok(out) @@ -2106,7 +2101,7 @@ pub async fn estimate_deletion_cnt( AND chat_id != ?3 AND chat_id != ?4 AND hidden = 0;", ( - DC_MSG_ID_LAST_SPECIAL, + MsgId::LAST_SPECIAL, threshold_timestamp, self_chat_id, ChatId::TRASH,