diff --git a/deltachat-ffi/src/lib.rs b/deltachat-ffi/src/lib.rs index 3fea176b0..6728c8a2e 100644 --- a/deltachat-ffi/src/lib.rs +++ b/deltachat-ffi/src/lib.rs @@ -31,7 +31,7 @@ use rand::Rng; use deltachat::chat::{ChatId, ChatVisibility, MuteDuration, ProtectionStatus}; use deltachat::constants::DC_MSG_ID_LAST_SPECIAL; -use deltachat::contact::{Contact, Origin}; +use deltachat::contact::{Contact, ContactId, Origin}; use deltachat::context::Context; use deltachat::ephemeral::Timer as EphemeralTimer; use deltachat::key::DcKey; @@ -493,14 +493,16 @@ pub unsafe extern "C" fn dc_event_get_data1_int(event: *mut dc_event_t) -> libc: | EventType::ChatEphemeralTimerModified { chat_id, .. } => chat_id.to_u32() as libc::c_int, EventType::ContactsChanged(id) | EventType::LocationChanged(id) => { let id = id.unwrap_or_default(); - id as libc::c_int + id.to_u32() as libc::c_int } EventType::ConfigureProgress { progress, .. } | EventType::ImexProgress(progress) => { *progress as libc::c_int } EventType::ImexFileWritten(_) => 0, EventType::SecurejoinInviterProgress { contact_id, .. } - | EventType::SecurejoinJoinerProgress { contact_id, .. } => *contact_id as libc::c_int, + | EventType::SecurejoinJoinerProgress { contact_id, .. } => { + contact_id.to_u32() as libc::c_int + } EventType::WebxdcStatusUpdate(msg_id) => msg_id.to_u32() as libc::c_int, } } @@ -715,7 +717,11 @@ pub unsafe extern "C" fn dc_get_chatlist( let ctx = &*context; let qs = to_opt_string_lossy(query_str); - let qi = if query_id == 0 { None } else { Some(query_id) }; + let qi = if query_id == 0 { + None + } else { + Some(ContactId::new(query_id)) + }; block_on(async move { match chatlist::Chatlist::try_load(ctx, flags as usize, qs.as_deref(), qi) @@ -743,7 +749,7 @@ pub unsafe extern "C" fn dc_create_chat_by_contact_id( let ctx = &*context; block_on(async move { - ChatId::create_for_contact(ctx, contact_id) + ChatId::create_for_contact(ctx, ContactId::new(contact_id)) .await .log_err(ctx, "Failed to create chat from contact_id") .map(|id| id.to_u32()) @@ -763,7 +769,7 @@ pub unsafe extern "C" fn dc_get_chat_id_by_contact_id( let ctx = &*context; block_on(async move { - ChatId::lookup_by_contact(ctx, contact_id) + ChatId::lookup_by_contact(ctx, ContactId::new(contact_id)) .await .log_err(ctx, "Failed to get chat for contact_id") .unwrap_or_default() // unwraps the Result @@ -1340,7 +1346,10 @@ pub unsafe extern "C" fn dc_get_chat_contacts( let arr = dc_array_t::from( chat::get_chat_contacts(ctx, ChatId::new(chat_id)) .await - .unwrap_or_log_default(ctx, "Failed get_chat_contacts"), + .unwrap_or_log_default(ctx, "Failed get_chat_contacts") + .iter() + .map(|id| id.to_u32()) + .collect::>(), ); Box::into_raw(Box::new(arr)) }) @@ -1450,7 +1459,7 @@ pub unsafe extern "C" fn dc_is_contact_in_chat( block_on(chat::is_contact_in_chat( ctx, ChatId::new(chat_id), - contact_id, + ContactId::new(contact_id), )) .log_err(ctx, "is_contact_in_chat failed") .unwrap_or_default() as libc::c_int @@ -1471,7 +1480,7 @@ pub unsafe extern "C" fn dc_add_contact_to_chat( block_on(chat::add_contact_to_chat( ctx, ChatId::new(chat_id), - contact_id, + ContactId::new(contact_id), )) .log_err(ctx, "Failed to add contact") .is_ok() as libc::c_int @@ -1492,7 +1501,7 @@ pub unsafe extern "C" fn dc_remove_contact_from_chat( block_on(chat::remove_contact_from_chat( ctx, ChatId::new(chat_id), - contact_id, + ContactId::new(contact_id), )) .log_err(ctx, "Failed to remove contact") .is_ok() as libc::c_int @@ -1827,7 +1836,8 @@ pub unsafe extern "C" fn dc_lookup_contact_id_by_addr( Contact::lookup_id_by_addr(ctx, &to_string_lossy(addr), Origin::IncomingReplyTo) .await .unwrap_or_log_default(ctx, "failed to lookup id") - .unwrap_or(0) + .map(|id| id.to_u32()) + .unwrap_or_default() }) } @@ -1847,6 +1857,7 @@ pub unsafe extern "C" fn dc_create_contact( block_on(async move { Contact::create(ctx, &name, &to_string_lossy(addr)) .await + .map(|id| id.to_u32()) .unwrap_or(0) }) } @@ -1885,7 +1896,9 @@ pub unsafe extern "C" fn dc_get_contacts( block_on(async move { match Contact::get_all(ctx, flags, query).await { - Ok(contacts) => Box::into_raw(Box::new(dc_array_t::from(contacts))), + Ok(contacts) => Box::into_raw(Box::new(dc_array_t::from( + contacts.iter().map(|id| id.to_u32()).collect::>(), + ))), Err(_) => ptr::null_mut(), } }) @@ -1922,7 +1935,10 @@ pub unsafe extern "C" fn dc_get_blocked_contacts( Contact::get_all_blocked(ctx) .await .log_err(ctx, "Can't get blocked contacts") - .unwrap_or_default(), + .unwrap_or_default() + .iter() + .map(|id| id.to_u32()) + .collect::>(), ))) }) } @@ -1933,18 +1949,18 @@ pub unsafe extern "C" fn dc_block_contact( contact_id: u32, block: libc::c_int, ) { - if context.is_null() || contact_id <= constants::DC_CONTACT_ID_LAST_SPECIAL as u32 { + if context.is_null() || contact_id <= constants::DC_CONTACT_ID_LAST_SPECIAL.to_u32() { eprintln!("ignoring careless call to dc_block_contact()"); return; } let ctx = &*context; block_on(async move { if block == 0 { - Contact::unblock(ctx, contact_id) + Contact::unblock(ctx, ContactId::new(contact_id)) .await .ok_or_log_msg(ctx, "Can't unblock contact"); } else { - Contact::block(ctx, contact_id) + Contact::block(ctx, ContactId::new(contact_id)) .await .ok_or_log_msg(ctx, "Can't block contact"); } @@ -1963,7 +1979,7 @@ pub unsafe extern "C" fn dc_get_contact_encrinfo( let ctx = &*context; block_on(async move { - Contact::get_encrinfo(ctx, contact_id) + Contact::get_encrinfo(ctx, ContactId::new(contact_id)) .await .map(|s| s.strdup()) .unwrap_or_else(|e| { @@ -1978,14 +1994,14 @@ pub unsafe extern "C" fn dc_delete_contact( context: *mut dc_context_t, contact_id: u32, ) -> libc::c_int { - if context.is_null() || contact_id <= constants::DC_CONTACT_ID_LAST_SPECIAL as u32 { + if context.is_null() || contact_id <= constants::DC_CONTACT_ID_LAST_SPECIAL.to_u32() { eprintln!("ignoring careless call to dc_delete_contact()"); return 0; } let ctx = &*context; block_on(async move { - match Contact::delete(ctx, contact_id).await { + match Contact::delete(ctx, ContactId::new(contact_id)).await { Ok(_) => 1, Err(_) => 0, } @@ -2004,7 +2020,7 @@ pub unsafe extern "C" fn dc_get_contact( let ctx = &*context; block_on(async move { - Contact::get_by_id(ctx, contact_id) + Contact::get_by_id(ctx, ContactId::new(contact_id)) .await .map(|contact| Box::into_raw(Box::new(ContactWrapper { context, contact }))) .unwrap_or_else(|_| ptr::null_mut()) @@ -2427,7 +2443,7 @@ pub unsafe extern "C" fn dc_array_get_contact_id( return 0; } - (*array).get_location(index).contact_id + (*array).get_location(index).contact_id.to_u32() } #[no_mangle] pub unsafe extern "C" fn dc_array_get_msg_id( @@ -2943,7 +2959,7 @@ pub unsafe extern "C" fn dc_msg_get_from_id(msg: *mut dc_msg_t) -> u32 { return 0; } let ffi_msg = &*msg; - ffi_msg.message.get_from_id() + ffi_msg.message.get_from_id().to_u32() } #[no_mangle] @@ -3654,7 +3670,7 @@ pub unsafe extern "C" fn dc_contact_get_id(contact: *mut dc_contact_t) -> u32 { return 0; } let ffi_contact = &*contact; - ffi_contact.contact.get_id() + ffi_contact.contact.get_id().to_u32() } #[no_mangle] diff --git a/deltachat-ffi/src/lot.rs b/deltachat-ffi/src/lot.rs index 1b64bbd1d..9426ef425 100644 --- a/deltachat-ffi/src/lot.rs +++ b/deltachat-ffi/src/lot.rs @@ -111,19 +111,19 @@ impl Lot { match self { Self::Summary(_) => Default::default(), Self::Qr(qr) => match qr { - Qr::AskVerifyContact { contact_id, .. } => *contact_id, + Qr::AskVerifyContact { contact_id, .. } => contact_id.to_u32(), Qr::AskVerifyGroup { .. } => Default::default(), - Qr::FprOk { contact_id } => *contact_id, - Qr::FprMismatch { contact_id } => contact_id.unwrap_or_default(), + Qr::FprOk { contact_id } => contact_id.to_u32(), + Qr::FprMismatch { contact_id } => contact_id.unwrap_or_default().to_u32(), Qr::FprWithoutAddr { .. } => Default::default(), Qr::Account { .. } => Default::default(), Qr::WebrtcInstance { .. } => Default::default(), - Qr::Addr { contact_id } => *contact_id, + Qr::Addr { contact_id } => contact_id.to_u32(), Qr::Url { .. } => Default::default(), Qr::Text { .. } => Default::default(), - Qr::WithdrawVerifyContact { contact_id, .. } => *contact_id, + Qr::WithdrawVerifyContact { contact_id, .. } => contact_id.to_u32(), Qr::WithdrawVerifyGroup { .. } => Default::default(), - Qr::ReviveVerifyContact { contact_id, .. } => *contact_id, + Qr::ReviveVerifyContact { contact_id, .. } => contact_id.to_u32(), Qr::ReviveVerifyGroup { .. } => Default::default(), }, Self::Error(_) => Default::default(), diff --git a/examples/repl/cmdline.rs b/examples/repl/cmdline.rs index df86235d1..e44f6d868 100644 --- a/examples/repl/cmdline.rs +++ b/examples/repl/cmdline.rs @@ -209,7 +209,7 @@ async fn log_msg(context: &Context, prefix: impl AsRef, msg: &Message) { contact_id, msgtext.unwrap_or_default(), if msg.has_html() { "[HAS-HTML]️" } else { "" }, - if msg.get_from_id() == 1 { + if msg.get_from_id() == DC_CONTACT_ID_SELF { "" } else if msg.get_state() == MessageState::InSeen { "[SEEN]" @@ -267,7 +267,7 @@ async fn log_msglist(context: &Context, msglist: &[MsgId]) -> Result<()> { Ok(()) } -async fn log_contactlist(context: &Context, contacts: &[u32]) -> Result<()> { +async fn log_contactlist(context: &Context, contacts: &[ContactId]) -> Result<()> { for contact_id in contacts { let mut line2 = "".to_string(); let contact = Contact::get_by_id(context, *contact_id).await?; @@ -296,7 +296,7 @@ async fn log_contactlist(context: &Context, contacts: &[u32]) -> Result<()> { let peerstate = Peerstate::from_addr(context, addr) .await .expect("peerstate error"); - if peerstate.is_some() && *contact_id != 1 { + if peerstate.is_some() && *contact_id != DC_CONTACT_ID_SELF { line2 = format!( ", prefer-encrypt={}", peerstate.as_ref().unwrap().prefer_encrypt @@ -714,7 +714,7 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu } "createchat" => { ensure!(!arg1.is_empty(), "Argument missing."); - let contact_id: u32 = arg1.parse()?; + let contact_id = ContactId::new(arg1.parse()?); let chat_id = ChatId::create_for_contact(&context, contact_id).await?; println!("Single#{} created successfully.", chat_id,); @@ -742,7 +742,7 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu ensure!(sel_chat.is_some(), "No chat selected"); ensure!(!arg1.is_empty(), "Argument missing."); - let contact_id_0: u32 = arg1.parse()?; + let contact_id_0 = ContactId::new(arg1.parse()?); chat::add_contact_to_chat(&context, sel_chat.as_ref().unwrap().get_id(), contact_id_0) .await?; println!("Contact added to chat."); @@ -750,7 +750,7 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu "removemember" => { ensure!(sel_chat.is_some(), "No chat selected."); ensure!(!arg1.is_empty(), "Argument missing."); - let contact_id_1: u32 = arg1.parse()?; + let contact_id_1 = ContactId::new(arg1.parse()?); chat::remove_contact_from_chat( &context, sel_chat.as_ref().unwrap().get_id(), @@ -1134,7 +1134,7 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu "contactinfo" => { ensure!(!arg1.is_empty(), "Argument missing."); - let contact_id: u32 = arg1.parse()?; + let contact_id = ContactId::new(arg1.parse()?); let contact = Contact::get_by_id(&context, contact_id).await?; let name_n_addr = contact.get_name_n_addr(); @@ -1169,16 +1169,16 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu } "delcontact" => { ensure!(!arg1.is_empty(), "Argument missing."); - Contact::delete(&context, arg1.parse()?).await?; + Contact::delete(&context, ContactId::new(arg1.parse()?)).await?; } "block" => { ensure!(!arg1.is_empty(), "Argument missing."); - let contact_id = arg1.parse()?; + let contact_id = ContactId::new(arg1.parse()?); Contact::block(&context, contact_id).await?; } "unblock" => { ensure!(!arg1.is_empty(), "Argument missing."); - let contact_id = arg1.parse()?; + let contact_id = ContactId::new(arg1.parse()?); Contact::unblock(&context, contact_id).await?; } "listblocked" => { diff --git a/src/chat.rs b/src/chat.rs index d92c800f1..5a56fd804 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -20,7 +20,7 @@ use crate::constants::{ DC_CONTACT_ID_LAST_SPECIAL, DC_CONTACT_ID_SELF, DC_GCM_ADDDAYMARKER, DC_GCM_INFO_ONLY, DC_RESEND_USER_AVATAR_DAYS, }; -use crate::contact::{addr_cmp, Contact, Origin, VerifiedStatus}; +use crate::contact::{addr_cmp, Contact, ContactId, Origin, VerifiedStatus}; use crate::context::Context; use crate::dc_receive_imf::ReceivedMsg; use crate::dc_tools::{ @@ -153,7 +153,10 @@ impl ChatId { /// Returns the [`ChatId`] for the 1:1 chat with `contact_id` if it exists. /// /// If it does not exist, `None` is returned. - pub async fn lookup_by_contact(context: &Context, contact_id: u32) -> Result> { + pub async fn lookup_by_contact( + context: &Context, + contact_id: ContactId, + ) -> Result> { ChatIdBlocked::lookup_by_contact(context, contact_id) .await .map(|lookup| lookup.map(|chat| chat.id)) @@ -166,7 +169,7 @@ impl ChatId { /// This is an internal API, if **a user action** needs to get a chat /// [`ChatId::create_for_contact`] should be used as this also scales up the /// [`Contact`]'s origin. - pub async fn get_for_contact(context: &Context, contact_id: u32) -> Result { + pub async fn get_for_contact(context: &Context, contact_id: ContactId) -> Result { ChatIdBlocked::get_for_contact(context, contact_id, Blocked::Not) .await .map(|chat| chat.id) @@ -176,7 +179,7 @@ impl ChatId { /// /// This should be used when **a user action** creates a chat 1:1, it ensures the chat /// exists, is unblocked and scales the [`Contact`]'s origin. - pub async fn create_for_contact(context: &Context, contact_id: u32) -> Result { + pub async fn create_for_contact(context: &Context, contact_id: ContactId) -> Result { ChatId::create_for_contact_with_blocked(context, contact_id, Blocked::Not).await } @@ -185,7 +188,7 @@ impl ChatId { /// `create_blocked` won't block already unblocked chats again. pub(crate) async fn create_for_contact_with_blocked( context: &Context, - contact_id: u32, + contact_id: ContactId, create_blocked: Blocked, ) -> Result { let chat_id = match ChatIdBlocked::lookup_by_contact(context, contact_id).await? { @@ -420,7 +423,7 @@ impl ChatId { context: &Context, protect: ProtectionStatus, promote: bool, - from_id: u32, + from_id: ContactId, ) -> Result<()> { let msg_text = context.stock_protection_msg(protect, from_id).await; let cmd = match protect { @@ -1628,7 +1631,11 @@ pub(crate) async fn get_broadcast_icon(context: &Context) -> Result { Ok(icon) } -async fn update_special_chat_name(context: &Context, contact_id: u32, name: String) -> Result<()> { +async fn update_special_chat_name( + context: &Context, + contact_id: ContactId, + name: String, +) -> Result<()> { if let Some(chat_id) = ChatId::lookup_by_contact(context, contact_id).await? { // the `!= name` condition avoids unneeded writes context @@ -1675,9 +1682,15 @@ impl ChatIdBlocked { /// Searches the database for the 1:1 chat with this contact. /// /// If no chat is found `None` is returned. - pub async fn lookup_by_contact(context: &Context, contact_id: u32) -> Result> { + pub async fn lookup_by_contact( + context: &Context, + contact_id: ContactId, + ) -> Result> { ensure!(context.sql.is_open().await, "Database not available"); - ensure!(contact_id > 0, "Invalid contact id requested"); + ensure!( + contact_id > ContactId::new(0), + "Invalid contact id requested" + ); context .sql @@ -1706,11 +1719,14 @@ impl ChatIdBlocked { /// state. pub async fn get_for_contact( context: &Context, - contact_id: u32, + contact_id: ContactId, create_blocked: Blocked, ) -> Result { ensure!(context.sql.is_open().await, "Database not available"); - ensure!(contact_id > 0, "Invalid contact id requested"); + ensure!( + contact_id > ContactId::new(0), + "Invalid contact id requested" + ); if let Some(res) = Self::lookup_by_contact(context, contact_id).await? { // Already exists, no need to create. @@ -1914,7 +1930,7 @@ async fn prepare_msg_common( pub async fn is_contact_in_chat( context: &Context, chat_id: ChatId, - contact_id: u32, + contact_id: ContactId, ) -> Result { // this function works for group and for normal chats, however, it is more useful // for group chats. @@ -1925,7 +1941,7 @@ pub async fn is_contact_in_chat( .sql .exists( "SELECT COUNT(*) FROM chats_contacts WHERE chat_id=? AND contact_id=?;", - paramsv![chat_id, contact_id as i32], + paramsv![chat_id, contact_id], ) .await?; Ok(exists) @@ -2227,9 +2243,12 @@ pub async fn get_chat_msgs( |row: &rusqlite::Row| { // is_info logic taken from Message.is_info() let params = row.get::<_, String>("param")?; - let (from_id, to_id) = (row.get::<_, u32>("from_id")?, row.get::<_, u32>("to_id")?); - let is_info_msg: bool = from_id == DC_CONTACT_ID_INFO as u32 - || to_id == DC_CONTACT_ID_INFO as u32 + let (from_id, to_id) = ( + row.get::<_, ContactId>("from_id")?, + row.get::<_, ContactId>("to_id")?, + ); + let is_info_msg: bool = from_id == DC_CONTACT_ID_INFO + || to_id == DC_CONTACT_ID_INFO || match Params::from_str(¶ms) { Ok(p) => { let cmd = p.get_cmd(); @@ -2530,7 +2549,7 @@ pub async fn get_next_media( } /// Returns a vector of contact IDs for given chat ID. -pub async fn get_chat_contacts(context: &Context, chat_id: ChatId) -> Result> { +pub async fn get_chat_contacts(context: &Context, chat_id: ChatId) -> Result> { // Normal chats do not include SELF. Group chats do (as it may happen that one is deleted from a // groupchat but the chats stays visible, moreover, this makes displaying lists easier) @@ -2544,7 +2563,7 @@ pub async fn get_chat_contacts(context: &Context, chat_id: ChatId) -> Result(0), + |row| row.get::<_, ContactId>(0), |ids| ids.collect::, _>>().map_err(Into::into), ) .await?; @@ -2651,13 +2670,13 @@ pub async fn create_broadcast_list(context: &Context) -> Result { pub(crate) async fn add_to_chat_contacts_table( context: &Context, chat_id: ChatId, - contact_id: u32, + contact_id: ContactId, ) -> Result<()> { context .sql .execute( "INSERT INTO chats_contacts (chat_id, contact_id) VALUES(?, ?)", - paramsv![chat_id, contact_id as i32], + paramsv![chat_id, contact_id], ) .await?; Ok(()) @@ -2667,13 +2686,13 @@ pub(crate) async fn add_to_chat_contacts_table( pub(crate) async fn remove_from_chat_contacts_table( context: &Context, chat_id: ChatId, - contact_id: u32, + contact_id: ContactId, ) -> Result<()> { context .sql .execute( "DELETE FROM chats_contacts WHERE chat_id=? AND contact_id=?", - paramsv![chat_id, contact_id as i32], + paramsv![chat_id, contact_id], ) .await?; Ok(()) @@ -2683,7 +2702,7 @@ pub(crate) async fn remove_from_chat_contacts_table( pub async fn add_contact_to_chat( context: &Context, chat_id: ChatId, - contact_id: u32, + contact_id: ContactId, ) -> Result<()> { add_contact_to_chat_ex(context, chat_id, contact_id, false).await?; Ok(()) @@ -2692,7 +2711,7 @@ pub async fn add_contact_to_chat( pub(crate) async fn add_contact_to_chat_ex( context: &Context, chat_id: ChatId, - contact_id: u32, + contact_id: ContactId, from_handshake: bool, ) -> Result { ensure!(!chat_id.is_special(), "can not add member to special chats"); @@ -2769,9 +2788,8 @@ pub(crate) async fn add_contact_to_chat_ex( if chat.typ == Chattype::Group && chat.is_promoted() { msg.viewtype = Viewtype::Text; - msg.text = Some( - stock_str::msg_add_member(context, contact.get_addr(), DC_CONTACT_ID_SELF as u32).await, - ); + msg.text = + Some(stock_str::msg_add_member(context, contact.get_addr(), DC_CONTACT_ID_SELF).await); msg.param.set_cmd(SystemMessage::MemberAddedToGroup); msg.param.set(Param::Arg, contact.get_addr()); msg.param.set_int(Param::Arg2, from_handshake.into()); @@ -2874,7 +2892,7 @@ pub async fn set_muted(context: &Context, chat_id: ChatId, duration: MuteDuratio pub async fn remove_contact_from_chat( context: &Context, chat_id: ChatId, - contact_id: u32, + contact_id: ContactId, ) -> Result<()> { ensure!( !chat_id.is_special(), @@ -2903,15 +2921,14 @@ pub async fn remove_contact_from_chat( msg.viewtype = Viewtype::Text; if contact.id == DC_CONTACT_ID_SELF { set_group_explicitly_left(context, &chat.grpid).await?; - msg.text = Some( - stock_str::msg_group_left(context, DC_CONTACT_ID_SELF as u32).await, - ); + msg.text = + Some(stock_str::msg_group_left(context, DC_CONTACT_ID_SELF).await); } else { msg.text = Some( stock_str::msg_del_member( context, contact.get_addr(), - DC_CONTACT_ID_SELF as u32, + DC_CONTACT_ID_SELF, ) .await, ); @@ -3004,13 +3021,8 @@ pub async fn set_chat_name(context: &Context, chat_id: ChatId, new_name: &str) - if chat.is_promoted() && !chat.is_mailing_list() && chat.typ != Chattype::Broadcast { msg.viewtype = Viewtype::Text; msg.text = Some( - stock_str::msg_grp_name( - context, - &chat.name, - &new_name, - DC_CONTACT_ID_SELF as u32, - ) - .await, + stock_str::msg_grp_name(context, &chat.name, &new_name, DC_CONTACT_ID_SELF) + .await, ); msg.param.set_cmd(SystemMessage::GroupNameChanged); if !chat.name.is_empty() { @@ -3063,7 +3075,7 @@ pub async fn set_chat_profile_image( if new_image.as_ref().is_empty() { chat.param.remove(Param::ProfileImage); msg.param.remove(Param::Arg); - msg.text = Some(stock_str::msg_grp_img_deleted(context, DC_CONTACT_ID_SELF as u32).await); + msg.text = Some(stock_str::msg_grp_img_deleted(context, DC_CONTACT_ID_SELF).await); } else { let mut image_blob = match BlobObject::from_path(context, Path::new(new_image.as_ref())) { Ok(blob) => Ok(blob), @@ -3077,7 +3089,7 @@ pub async fn set_chat_profile_image( image_blob.recode_to_avatar_size(context).await?; chat.param.set(Param::ProfileImage, image_blob.as_name()); msg.param.set(Param::Arg, image_blob.as_name()); - msg.text = Some(stock_str::msg_grp_img_changed(context, DC_CONTACT_ID_SELF as u32).await); + msg.text = Some(stock_str::msg_grp_img_changed(context, DC_CONTACT_ID_SELF).await); } chat.update_param(context).await?; if chat.is_promoted() && !chat.is_mailing_list() { @@ -3905,7 +3917,7 @@ mod tests { async fn test_self_talk() -> Result<()> { let t = TestContext::new_alice().await; let chat = &t.get_self_chat().await; - assert_eq!(DC_CONTACT_ID_SELF, 1); + assert_eq!(DC_CONTACT_ID_SELF, ContactId::new(1)); assert!(!chat.id.is_special()); assert!(chat.is_self_talk()); assert!(chat.visibility == ChatVisibility::Normal); @@ -4322,7 +4334,7 @@ mod tests { let contact1 = Contact::create(&context.ctx, "bob", "bob@mail.de") .await .unwrap(); - assert_ne!(contact1, 0); + assert_ne!(contact1, ContactId::new(0)); let chat_id = ChatId::create_for_contact(&context.ctx, contact1) .await @@ -4527,7 +4539,7 @@ mod tests { // create contact, then unblocked chat let contact_id = Contact::create(&ctx, "", "bob@foo.de").await.unwrap(); - assert_ne!(contact_id, 0); + assert_ne!(contact_id, ContactId::new(0)); let found = ChatId::lookup_by_contact(&ctx, contact_id).await.unwrap(); assert!(found.is_none()); @@ -4553,10 +4565,14 @@ mod tests { assert_eq!(chat2.blocked, Blocked::Yes); // test nonexistent contact - let found = ChatId::lookup_by_contact(&ctx, 1234).await.unwrap(); + let found = ChatId::lookup_by_contact(&ctx, ContactId::new(1234)) + .await + .unwrap(); assert!(found.is_none()); - let found = ChatIdBlocked::lookup_by_contact(&ctx, 1234).await.unwrap(); + let found = ChatIdBlocked::lookup_by_contact(&ctx, ContactId::new(1234)) + .await + .unwrap(); assert!(found.is_none()); } diff --git a/src/chatlist.rs b/src/chatlist.rs index 075c83227..bae795bbd 100644 --- a/src/chatlist.rs +++ b/src/chatlist.rs @@ -8,7 +8,7 @@ use crate::constants::{ DC_CONTACT_ID_SELF, DC_CONTACT_ID_UNDEFINED, DC_GCL_ADD_ALLDONE_HINT, DC_GCL_ARCHIVED_ONLY, DC_GCL_FOR_FORWARDING, DC_GCL_NO_SPECIALS, }; -use crate::contact::Contact; +use crate::contact::{Contact, ContactId}; use crate::context::Context; use crate::ephemeral::delete_expired_messages; use crate::message::{Message, MessageState, MsgId}; @@ -85,7 +85,7 @@ impl Chatlist { context: &Context, listflags: usize, query: Option<&str>, - query_contact_id: Option, + query_contact_id: Option, ) -> Result { let flag_archived_only = 0 != listflags & DC_GCL_ARCHIVED_ONLY; let flag_for_forwarding = 0 != listflags & DC_GCL_FOR_FORWARDING; @@ -147,7 +147,7 @@ impl Chatlist { AND c.id IN(SELECT chat_id FROM chats_contacts WHERE contact_id=?2) GROUP BY c.id ORDER BY c.archived=?3 DESC, IFNULL(m.timestamp,c.created_timestamp) DESC, m.id DESC;", - paramsv![MessageState::OutDraft, query_contact_id as i32, ChatVisibility::Pinned], + paramsv![MessageState::OutDraft, query_contact_id, ChatVisibility::Pinned], process_row, process_rows, ).await? diff --git a/src/constants.rs b/src/constants.rs index 7fa3f347b..294718e1a 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -4,6 +4,7 @@ use once_cell::sync::Lazy; use serde::{Deserialize, Serialize}; use crate::chat::ChatId; +use crate::contact::ContactId; pub static DC_VERSION_STR: Lazy = Lazy::new(|| env!("CARGO_PKG_VERSION").to_string()); @@ -179,11 +180,11 @@ pub const DC_ELLIPSIS: &str = "[...]"; /// `char`s), not Unicode Grapheme Clusters. pub const DC_DESIRED_TEXT_LEN: usize = 5000; -pub const DC_CONTACT_ID_UNDEFINED: u32 = 0; -pub const DC_CONTACT_ID_SELF: u32 = 1; -pub const DC_CONTACT_ID_INFO: u32 = 2; -pub const DC_CONTACT_ID_DEVICE: u32 = 5; -pub const DC_CONTACT_ID_LAST_SPECIAL: u32 = 9; +pub const DC_CONTACT_ID_UNDEFINED: ContactId = ContactId::new(0); +pub const DC_CONTACT_ID_SELF: ContactId = ContactId::new(1); +pub const DC_CONTACT_ID_INFO: ContactId = ContactId::new(2); +pub const DC_CONTACT_ID_DEVICE: ContactId = ContactId::new(5); +pub const DC_CONTACT_ID_LAST_SPECIAL: ContactId = ContactId::new(9); // decorative address that is used for DC_CONTACT_ID_DEVICE // when an api that returns an email is called. diff --git a/src/contact.rs b/src/contact.rs index 651283cca..a08e7b0e3 100644 --- a/src/contact.rs +++ b/src/contact.rs @@ -1,12 +1,14 @@ //! Contacts module use std::convert::{TryFrom, TryInto}; +use std::fmt; use anyhow::{bail, ensure, Context as _, Result}; use async_std::path::PathBuf; use deltachat_derive::{FromSql, ToSql}; use once_cell::sync::Lazy; use regex::Regex; +use serde::{Deserialize, Serialize}; use crate::aheader::EncryptPreference; use crate::chat::ChatId; @@ -27,6 +29,67 @@ use crate::param::{Param, Params}; use crate::peerstate::{Peerstate, PeerstateVerifiedStatus}; use crate::{chat, stock_str}; +/// Contact ID, including reserved IDs. +/// +/// Some contact IDs are reserved to identify special contacts. This +/// type can represent both the special as well as normal contacts. +#[derive( + Debug, Copy, Clone, Default, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize, +)] +pub struct ContactId(u32); + +impl ContactId { + /// Creates a new [`ContactId`]. + pub const fn new(id: u32) -> ContactId { + ContactId(id) + } + + /// Bad evil escape hatch, do not use. + pub const fn to_u32(&self) -> u32 { + self.0 + } +} + +impl fmt::Display for ContactId { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.0) + // TODO: Something like this + // if self == DC_CONTACT_ID_UNDEFINED { + // write!(f, "Contact#Undefined") + // } else if self == DC_CONTACT_ID_SELF { + // write!(f, "Contact#Self") + // } else if self == DC_CONTACT_ID_INFO { + // write!(f, "Contact#Info") + // } else if self == DC_CONTACT_ID_DEVICE { + // write!(f, "Contact#Device") + // } else if self <= DC_CONTACT_ID_LAST_SPECIAL { + // write!(f, "Contact#Special{}", self.0) + // } else { + // write!(f, "Contact#{}", self.0) + // } + } +} + +/// Allow converting [`ContactId`] to an SQLite type. +impl rusqlite::types::ToSql for ContactId { + fn to_sql(&self) -> rusqlite::Result { + let val = rusqlite::types::Value::Integer(i64::from(self.0)); + let out = rusqlite::types::ToSqlOutput::Owned(val); + Ok(out) + } +} + +/// Allow converting an SQLite integer directly into [`ContactId`]. +impl rusqlite::types::FromSql for ContactId { + fn column_result(value: rusqlite::types::ValueRef) -> rusqlite::types::FromSqlResult { + i64::column_result(value).and_then(|val| { + val.try_into() + .map(ContactId::new) + .map_err(|_| rusqlite::types::FromSqlError::OutOfRange(val)) + }) + } +} + /// An object representing a single contact in memory. /// /// The contact object is not updated. @@ -48,7 +111,7 @@ pub struct Contact { /// `dc_set_config` using "addr". /// /// Normal contact IDs are larger than these special ones (larger than DC_CONTACT_ID_LAST_SPECIAL). - pub id: u32, + pub id: ContactId, /// Contact name. It is recommended to use `Contact::get_name`, /// `Contact::get_display_name` or `Contact::get_name_n_addr` to access this field. @@ -183,7 +246,7 @@ impl Default for VerifiedStatus { } impl Contact { - pub async fn load_from_db(context: &Context, contact_id: u32) -> Result { + pub async fn load_from_db(context: &Context, contact_id: ContactId) -> Result { let mut contact = context .sql .query_row( @@ -191,7 +254,7 @@ impl Contact { c.authname, c.param, c.status FROM contacts c WHERE c.id=?;", - paramsv![contact_id as i32], + paramsv![contact_id], |row| { let name: String = row.get(0)?; let addr: String = row.get(1)?; @@ -245,18 +308,18 @@ impl Contact { } /// Check if a contact is blocked. - pub async fn is_blocked_load(context: &Context, id: u32) -> Result { + pub async fn is_blocked_load(context: &Context, id: ContactId) -> Result { let blocked = Self::load_from_db(context, id).await?.blocked; Ok(blocked) } /// Block the given contact. - pub async fn block(context: &Context, id: u32) -> Result<()> { + pub async fn block(context: &Context, id: ContactId) -> Result<()> { set_block_contact(context, id, true).await } /// Unblock the given contact. - pub async fn unblock(context: &Context, id: u32) -> Result<()> { + pub async fn unblock(context: &Context, id: ContactId) -> Result<()> { set_block_contact(context, id, false).await } @@ -269,7 +332,7 @@ impl Contact { /// a bunch of addresses. /// /// May result in a `#DC_EVENT_CONTACTS_CHANGED` event. - pub async fn create(context: &Context, name: &str, addr: &str) -> Result { + pub async fn create(context: &Context, name: &str, addr: &str) -> Result { let name = improve_single_line_input(name); ensure!(!addr.is_empty(), "Cannot create contact with empty address"); @@ -292,12 +355,12 @@ impl Contact { } /// Mark messages from a contact as noticed. - pub async fn mark_noticed(context: &Context, id: u32) -> Result<()> { + pub async fn mark_noticed(context: &Context, id: ContactId) -> Result<()> { context .sql .execute( "UPDATE msgs SET state=? WHERE from_id=? AND state=?;", - paramsv![MessageState::InNoticed, id as i32, MessageState::InFresh], + paramsv![MessageState::InNoticed, id, MessageState::InFresh], ) .await?; Ok(()) @@ -313,7 +376,7 @@ impl Contact { context: &Context, addr: &str, min_origin: Origin, - ) -> Result> { + ) -> Result> { if addr.is_empty() { bail!("lookup_id_by_addr: empty address"); } @@ -333,7 +396,7 @@ impl Contact { AND id>?2 AND origin>=?3 AND blocked=0;", paramsv![ addr_normalized, - DC_CONTACT_ID_LAST_SPECIAL as i32, + DC_CONTACT_ID_LAST_SPECIAL, min_origin as u32, ], ) @@ -371,7 +434,7 @@ impl Contact { name: &str, addr: &str, mut origin: Origin, - ) -> Result<(u32, Modifier)> { + ) -> Result<(ContactId, Modifier)> { let mut sth_modified = Modifier::None; ensure!(!addr.is_empty(), "Can not add_or_lookup empty address"); @@ -500,7 +563,7 @@ impl Contact { paramsv![Chattype::Single, isize::try_from(row_id)?] ).await?; if let Some(chat_id) = chat_id { - let contact = Contact::get_by_id(context, row_id as u32).await?; + let contact = Contact::get_by_id(context, ContactId::new(row_id)).await?; let chat_name = contact.get_display_name(); match context .sql @@ -557,7 +620,7 @@ impl Contact { } } - Ok((row_id, sth_modified)) + Ok((ContactId::new(row_id), sth_modified)) } /// Add a number of contacts. @@ -617,7 +680,7 @@ impl Contact { context: &Context, listflags: u32, query: Option>, - ) -> Result> { + ) -> Result> { let self_addr = context .get_config(Config::ConfiguredAddr) .await? @@ -644,16 +707,16 @@ impl Contact { ORDER BY LOWER(iif(c.name='',c.authname,c.name)||c.addr),c.id;", paramsv![ self_addr, - DC_CONTACT_ID_LAST_SPECIAL as i32, + DC_CONTACT_ID_LAST_SPECIAL, Origin::IncomingReplyTo, s3str_like_cmd, s3str_like_cmd, if flag_verified_only { 0i32 } else { 1i32 }, ], - |row| row.get::<_, i32>(0), + |row| row.get::<_, ContactId>(0), |ids| { for id in ids { - ret.push(id? as u32); + ret.push(id?); } Ok(()) }, @@ -690,13 +753,13 @@ impl Contact { ORDER BY LOWER(iif(name='',authname,name)||addr),id;", paramsv![ self_addr, - DC_CONTACT_ID_LAST_SPECIAL as i32, + DC_CONTACT_ID_LAST_SPECIAL, Origin::IncomingReplyTo ], - |row| row.get::<_, i32>(0), + |row| row.get::<_, ContactId>(0), |ids| { for id in ids { - ret.push(id? as u32); + ret.push(id?); } Ok(()) }, @@ -767,7 +830,7 @@ impl Contact { } /// Get blocked contacts. - pub async fn get_all_blocked(context: &Context) -> Result> { + pub async fn get_all_blocked(context: &Context) -> Result> { Contact::update_blocked_mailinglist_contacts(context) .await .context("cannot update blocked mailinglist contacts")?; @@ -776,8 +839,8 @@ impl Contact { .sql .query_map( "SELECT id FROM contacts WHERE id>? AND blocked!=0 ORDER BY LOWER(iif(name='',authname,name)||addr),id;", - paramsv![DC_CONTACT_ID_LAST_SPECIAL as i32], - |row| row.get::<_, u32>(0), + paramsv![DC_CONTACT_ID_LAST_SPECIAL], + |row| row.get::<_, ContactId>(0), |ids| { ids.collect::, _>>() .map_err(Into::into) @@ -792,7 +855,7 @@ impl Contact { /// This function returns a string explaining the encryption state /// of the contact and if the connection is encrypted the /// fingerprints of the keys involved. - pub async fn get_encrinfo(context: &Context, contact_id: u32) -> Result { + pub async fn get_encrinfo(context: &Context, contact_id: ContactId) -> Result { ensure!( contact_id > DC_CONTACT_ID_LAST_SPECIAL, "Can not provide encryption info for special contact" @@ -861,7 +924,7 @@ impl Contact { /// possible as the contact is in use. In this case, the contact can be blocked. /// /// May result in a `#DC_EVENT_CONTACTS_CHANGED` event. - pub async fn delete(context: &Context, contact_id: u32) -> Result<()> { + pub async fn delete(context: &Context, contact_id: ContactId) -> Result<()> { ensure!( contact_id > DC_CONTACT_ID_LAST_SPECIAL, "Can not delete special contact" @@ -871,17 +934,14 @@ impl Contact { .sql .count( "SELECT COUNT(*) FROM chats_contacts WHERE contact_id=?;", - paramsv![contact_id as i32], + paramsv![contact_id], ) .await?; if count_chats == 0 { match context .sql - .execute( - "DELETE FROM contacts WHERE id=?;", - paramsv![contact_id as i32], - ) + .execute("DELETE FROM contacts WHERE id=?;", paramsv![contact_id]) .await { Ok(_) => { @@ -907,7 +967,7 @@ impl Contact { /// For contact DC_CONTACT_ID_SELF (1), the function returns sth. /// like "Me" in the selected language and the email address /// defined by dc_set_config(). - pub async fn get_by_id(context: &Context, contact_id: u32) -> Result { + pub async fn get_by_id(context: &Context, contact_id: ContactId) -> Result { let contact = Contact::load_from_db(context, contact_id).await?; Ok(contact) @@ -919,7 +979,7 @@ impl Contact { .sql .execute( "UPDATE contacts SET param=? WHERE id=?", - paramsv![self.param.to_string(), self.id as i32], + paramsv![self.param.to_string(), self.id], ) .await?; Ok(()) @@ -931,14 +991,14 @@ impl Contact { .sql .execute( "UPDATE contacts SET status=? WHERE id=?", - paramsv![self.status, self.id as i32], + paramsv![self.status, self.id], ) .await?; Ok(()) } /// Get the ID of the contact. - pub fn get_id(&self) -> u32 { + pub fn get_id(&self) -> ContactId { self.id } @@ -1065,7 +1125,7 @@ impl Contact { pub async fn addr_equals_contact( context: &Context, addr: &str, - contact_id: u32, + contact_id: ContactId, ) -> Result { if addr.is_empty() { return Ok(false); @@ -1091,13 +1151,13 @@ impl Contact { .sql .count( "SELECT COUNT(*) FROM contacts WHERE id>?;", - paramsv![DC_CONTACT_ID_LAST_SPECIAL as i32], + paramsv![DC_CONTACT_ID_LAST_SPECIAL], ) .await?; Ok(count) } - pub async fn real_exists_by_id(context: &Context, contact_id: u32) -> Result { + pub async fn real_exists_by_id(context: &Context, contact_id: ContactId) -> Result { if contact_id <= DC_CONTACT_ID_LAST_SPECIAL { return Ok(false); } @@ -1106,7 +1166,7 @@ impl Contact { .sql .exists( "SELECT COUNT(*) FROM contacts WHERE id=?;", - paramsv![contact_id as i32], + paramsv![contact_id], ) .await?; Ok(exists) @@ -1114,14 +1174,14 @@ impl Contact { pub async fn scaleup_origin_by_id( context: &Context, - contact_id: u32, + contact_id: ContactId, origin: Origin, ) -> Result<()> { context .sql .execute( "UPDATE contacts SET origin=? WHERE id=? AND origin (String, String) { } } -async fn set_block_contact(context: &Context, contact_id: u32, new_blocking: bool) -> Result<()> { +async fn set_block_contact( + context: &Context, + contact_id: ContactId, + new_blocking: bool, +) -> Result<()> { ensure!( contact_id > DC_CONTACT_ID_LAST_SPECIAL, "Can't block special contact {}", @@ -1179,7 +1243,7 @@ async fn set_block_contact(context: &Context, contact_id: u32, new_blocking: boo .sql .execute( "UPDATE contacts SET blocked=? WHERE id=?;", - paramsv![i32::from(new_blocking), contact_id as i32], + paramsv![i32::from(new_blocking), contact_id], ) .await?; @@ -1230,7 +1294,7 @@ WHERE type=? AND id IN ( /// this typically happens if we see message with our own profile image, sent from another device. pub(crate) async fn set_profile_image( context: &Context, - contact_id: u32, + contact_id: ContactId, profile_image: &AvatarAction, was_encrypted: bool, ) -> Result<()> { @@ -1277,7 +1341,7 @@ pub(crate) async fn set_profile_image( /// between Delta Chat devices. pub(crate) async fn set_status( context: &Context, - contact_id: u32, + contact_id: ContactId, status: String, encrypted: bool, has_chat_version: bool, @@ -1303,7 +1367,7 @@ pub(crate) async fn set_status( /// Updates last seen timestamp of the contact if it is earlier than the given `timestamp`. pub(crate) async fn update_last_seen( context: &Context, - contact_id: u32, + contact_id: ContactId, timestamp: i64, ) -> Result<()> { ensure!( @@ -1474,7 +1538,7 @@ mod tests { Origin::IncomingReplyTo, ) .await?; - assert_ne!(id, 0); + assert_ne!(id, ContactId::new(0)); let contact = Contact::load_from_db(&context.ctx, id).await.unwrap(); assert_eq!(contact.get_name(), ""); @@ -1629,7 +1693,7 @@ mod tests { // check SELF let contact = Contact::load_from_db(&t, DC_CONTACT_ID_SELF).await.unwrap(); - assert_eq!(DC_CONTACT_ID_SELF, 1); + assert_eq!(DC_CONTACT_ID_SELF, ContactId::new(1)); assert_eq!(contact.get_name(), stock_str::self_msg(&t).await); assert_eq!(contact.get_addr(), ""); // we're not configured assert!(!contact.is_blocked()); diff --git a/src/dc_receive_imf.rs b/src/dc_receive_imf.rs index 44ad9ec54..de1a8c537 100644 --- a/src/dc_receive_imf.rs +++ b/src/dc_receive_imf.rs @@ -18,7 +18,7 @@ use crate::constants::{ DC_CONTACT_ID_SELF, }; use crate::contact::{ - addr_cmp, may_be_valid_addr, normalize_name, Contact, Origin, VerifiedStatus, + addr_cmp, may_be_valid_addr, normalize_name, Contact, ContactId, Origin, VerifiedStatus, }; use crate::context::Context; use crate::dc_tools::{dc_create_id, dc_extract_grpid_from_rfc724_mid, dc_smeared_time}; @@ -199,7 +199,7 @@ pub(crate) async fn dc_receive_imf_inner( .map_or(rcvd_timestamp, |value| min(value, rcvd_timestamp)); if mime_parser.is_system_message == SystemMessage::LocationStreamingEnabled { - let better_msg = stock_str::msg_location_enabled_by(context, from_id as u32).await; + let better_msg = stock_str::msg_location_enabled_by(context, from_id).await; set_better_msg(&mut mime_parser, &better_msg); } @@ -283,7 +283,7 @@ pub(crate) async fn dc_receive_imf_inner( } if let Some(avatar_action) = &mime_parser.user_avatar { - if from_id != 0 + if from_id != ContactId::new(0) && context .update_contacts_timestamp(from_id, Param::AvatarTimestamp, sent_timestamp) .await? @@ -311,7 +311,7 @@ pub(crate) async fn dc_receive_imf_inner( // Ignore MDNs though, as they never contain the signature even if user has set it. if mime_parser.mdn_reports.is_empty() && is_partial_download.is_none() - && from_id != 0 + && from_id != ContactId::new(0) && context .update_contacts_timestamp(from_id, Param::StatusTimestamp, sent_timestamp) .await? @@ -387,7 +387,7 @@ pub async fn from_field_to_contact_id( context: &Context, from_address_list: &[SingleInfo], prevent_rename: bool, -) -> Result<(u32, bool, Origin)> { +) -> Result<(ContactId, bool, Origin)> { let from_ids = dc_add_or_lookup_contacts_by_address_list( context, from_address_list, @@ -420,7 +420,7 @@ pub async fn from_field_to_contact_id( "mail has an empty From header: {:?}", from_address_list ); - Ok((0, false, Origin::Unknown)) + Ok((ContactId::new(0), false, Origin::Unknown)) } } @@ -431,11 +431,11 @@ async fn add_parts( imf_raw: &[u8], incoming: bool, server_folder: &str, - to_ids: &[u32], + to_ids: &[ContactId], rfc724_mid: &str, sent_timestamp: i64, rcvd_timestamp: i64, - from_id: u32, + from_id: ContactId, seen: bool, is_partial_download: Option, needs_delete_job: &mut bool, @@ -488,7 +488,7 @@ async fn add_parts( // - outgoing messages introduce a chat with the first to: address if they are sent by a messenger // - incoming messages introduce a chat only for known contacts if they are sent by a messenger // (of course, the user can add other chats manually later) - let to_id: u32; + let to_id: ContactId; let state: MessageState; if incoming { @@ -524,7 +524,7 @@ async fn add_parts( securejoin_seen = false; } - let test_normal_chat = if from_id == 0 { + let test_normal_chat = if from_id == ContactId::new(0) { Default::default() } else { ChatIdBlocked::lookup_by_contact(context, from_id).await? @@ -583,7 +583,7 @@ async fn add_parts( // In lookup_chat_by_reply() and create_or_lookup_group(), it can happen that the message is put into a chat // but the From-address is not a member of this chat. if let Some(chat_id) = chat_id { - if !chat::is_contact_in_chat(context, chat_id, from_id as u32).await? { + if !chat::is_contact_in_chat(context, chat_id, from_id).await? { let chat = Chat::load_from_db(context, chat_id).await?; if chat.is_protected() { let s = stock_str::unknown_sender_for_chat(context).await; @@ -1031,9 +1031,7 @@ async fn add_parts( } set_better_msg( mime_parser, - context - .stock_protection_msg(new_status, from_id as u32) - .await, + context.stock_protection_msg(new_status, from_id).await, ); } } @@ -1156,8 +1154,8 @@ INSERT INTO msgs stmt.execute(paramsv![ rfc724_mid, chat_id, - if trash { 0 } else { i64::from(from_id) }, - if trash { 0 } else { i64::from(to_id) }, + if trash { ContactId::new(0) } else { from_id }, + if trash { ContactId::new(0) } else { to_id }, sort_timestamp, sent_timestamp, rcvd_timestamp, @@ -1256,7 +1254,7 @@ async fn save_locations( context: &Context, mime_parser: &MimeMessage, chat_id: ChatId, - from_id: u32, + from_id: ContactId, msg_id: MsgId, ) -> Result<()> { if chat_id.is_special() { @@ -1335,8 +1333,8 @@ async fn lookup_chat_by_reply( context: &Context, mime_parser: &mut MimeMessage, parent: &Option, - from_id: u32, - to_ids: &[u32], + from_id: ContactId, + to_ids: &[ContactId], ) -> Result> { // Try to assign message to the same chat as the parent message. @@ -1376,10 +1374,10 @@ async fn lookup_chat_by_reply( /// If it returns false, it shall be assigned to the parent chat. async fn is_probably_private_reply( context: &Context, - to_ids: &[u32], + to_ids: &[ContactId], mime_parser: &MimeMessage, parent_chat_id: ChatId, - from_id: u32, + from_id: ContactId, ) -> Result { // Usually we don't want to show private replies in the parent chat, but in the // 1:1 chat with the sender. @@ -1416,18 +1414,18 @@ async fn create_or_lookup_group( mime_parser: &mut MimeMessage, allow_creation: bool, create_blocked: Blocked, - from_id: u32, - to_ids: &[u32], + from_id: ContactId, + to_ids: &[ContactId], ) -> Result> { let grpid = if let Some(grpid) = try_getting_grpid(mime_parser) { grpid } else if allow_creation { - let mut member_ids: Vec = to_ids.to_vec(); - if !member_ids.contains(&(from_id as u32)) { - member_ids.push(from_id as u32); + let mut member_ids: Vec = to_ids.to_vec(); + if !member_ids.contains(&(from_id)) { + member_ids.push(from_id); } - if !member_ids.contains(&(DC_CONTACT_ID_SELF as u32)) { - member_ids.push(DC_CONTACT_ID_SELF as u32); + if !member_ids.contains(&(DC_CONTACT_ID_SELF)) { + member_ids.push(DC_CONTACT_ID_SELF); } let res = create_adhoc_group(context, mime_parser, create_blocked, &member_ids) @@ -1561,8 +1559,8 @@ async fn apply_group_changes( mime_parser: &mut MimeMessage, sent_timestamp: i64, chat_id: ChatId, - from_id: u32, - to_ids: &[u32], + from_id: ContactId, + to_ids: &[ContactId], ) -> Result<()> { let mut chat = Chat::load_from_db(context, chat_id).await?; if chat.typ != Chattype::Group { @@ -1626,8 +1624,7 @@ async fn apply_group_changes( send_event_chat_modified = true; } - let better_msg = - stock_str::msg_grp_name(context, old_name, grpname, from_id as u32).await; + let better_msg = stock_str::msg_grp_name(context, old_name, grpname, from_id).await; set_better_msg(mime_parser, &better_msg); mime_parser.is_system_message = SystemMessage::GroupNameChanged; } @@ -1953,7 +1950,7 @@ async fn create_adhoc_group( context: &Context, mime_parser: &MimeMessage, create_blocked: Blocked, - member_ids: &[u32], + member_ids: &[ContactId], ) -> Result> { if mime_parser.is_mailinglist_message() { info!( @@ -2023,7 +2020,7 @@ async fn create_adhoc_group( /// This ensures that different Delta Chat clients generate the same group ID unless some of them /// are hidden in BCC. This group ID is sent by DC in the messages sent to this chat, /// so having the same ID prevents group split. -async fn create_adhoc_grp_id(context: &Context, member_ids: &[u32]) -> Result { +async fn create_adhoc_grp_id(context: &Context, member_ids: &[ContactId]) -> Result { let member_ids_str = member_ids .iter() .map(|x| x.to_string()) @@ -2070,8 +2067,8 @@ fn hex_hash(s: &str) -> String { async fn check_verified_properties( context: &Context, mimeparser: &MimeMessage, - from_id: u32, - to_ids: &[u32], + from_id: ContactId, + to_ids: &[ContactId], ) -> Result<()> { let contact = Contact::load_from_db(context, from_id).await?; @@ -2118,7 +2115,7 @@ async fn check_verified_properties( .iter() .copied() .filter(|id| *id != DC_CONTACT_ID_SELF) - .collect::>(); + .collect::>(); if to_ids.is_empty() { return Ok(()); @@ -2301,7 +2298,7 @@ async fn dc_add_or_lookup_contacts_by_address_list( address_list: &[SingleInfo], origin: Origin, prevent_rename: bool, -) -> Result> { +) -> Result> { let mut contact_ids = BTreeSet::new(); for info in address_list.iter() { let addr = &info.addr; @@ -2317,7 +2314,7 @@ async fn dc_add_or_lookup_contacts_by_address_list( .insert(add_or_lookup_contact_by_addr(context, display_name, addr, origin).await?); } - Ok(contact_ids.into_iter().collect::>()) + Ok(contact_ids.into_iter().collect::>()) } /// Add contacts to database on receiving messages. @@ -2326,7 +2323,7 @@ async fn add_or_lookup_contact_by_addr( display_name: Option<&str>, addr: &str, origin: Origin, -) -> Result { +) -> Result { if context.is_self_addr(addr).await? { return Ok(DC_CONTACT_ID_SELF); } @@ -2334,8 +2331,6 @@ async fn add_or_lookup_contact_by_addr( let (row_id, _modified) = Contact::add_or_lookup(context, &display_name_normalized, addr, origin).await?; - ensure!(row_id > 0, "could not add contact: {:?}", addr); - Ok(row_id) } diff --git a/src/ephemeral.rs b/src/ephemeral.rs index 38f59f241..d42e6cc43 100644 --- a/src/ephemeral.rs +++ b/src/ephemeral.rs @@ -69,6 +69,7 @@ use crate::chat::{send_msg, ChatId}; use crate::constants::{ Viewtype, DC_CHAT_ID_LAST_SPECIAL, DC_CHAT_ID_TRASH, DC_CONTACT_ID_DEVICE, DC_CONTACT_ID_SELF, }; +use crate::contact::ContactId; use crate::context::Context; use crate::dc_tools::time; use crate::download::MIN_DELETE_SERVER_AFTER; @@ -212,7 +213,7 @@ impl ChatId { pub(crate) async fn stock_ephemeral_timer_changed( context: &Context, timer: Timer, - from_id: u32, + from_id: ContactId, ) -> String { match timer { Timer::Disabled => stock_str::msg_ephemeral_timer_disabled(context, from_id).await, @@ -823,8 +824,8 @@ mod tests { // Check that if there is a message left, the text and metadata are gone if let Ok(msg) = Message::load_from_db(t, msg_id).await { - assert_eq!(msg.from_id, 0); - assert_eq!(msg.to_id, 0); + assert_eq!(msg.from_id, ContactId::new(0)); + assert_eq!(msg.to_id, ContactId::new(0)); assert!(msg.text.is_none_or_empty(), "{:?}", msg.text); let rawtxt: Option = t .sql diff --git a/src/events.rs b/src/events.rs index 4fea31a99..8ecbf23aa 100644 --- a/src/events.rs +++ b/src/events.rs @@ -7,6 +7,7 @@ use async_std::path::PathBuf; use strum::EnumProperty; use crate::chat::ChatId; +use crate::contact::ContactId; use crate::ephemeral::Timer as EphemeralTimer; use crate::message::MsgId; @@ -252,7 +253,7 @@ pub enum EventType { /// /// @param data1 (int) If set, this is the contact_id of an added contact that should be selected. #[strum(props(id = "2030"))] - ContactsChanged(Option), + ContactsChanged(Option), /// Location of one or more contact has changed. /// @@ -260,7 +261,7 @@ pub enum EventType { /// If the locations of several contacts have been changed, /// eg. after calling dc_delete_all_locations(), this parameter is set to `None`. #[strum(props(id = "2035"))] - LocationChanged(Option), + LocationChanged(Option), /// Inform about the configuration progress started by configure(). #[strum(props(id = "2041"))] @@ -304,7 +305,10 @@ pub enum EventType { /// 800=vg-member-added-received received, shown as "bob@addr securely joined GROUP", only sent for the verified-group-protocol. /// 1000=Protocol finished for this contact. #[strum(props(id = "2060"))] - SecurejoinInviterProgress { contact_id: u32, progress: usize }, + SecurejoinInviterProgress { + contact_id: ContactId, + progress: usize, + }, /// Progress information of a secure-join handshake from the view of the joiner /// (Bob, the person who scans the QR code). @@ -315,7 +319,10 @@ pub enum EventType { /// 400=vg-/vc-request-with-auth sent, typically shown as "alice@addr verified, introducing myself." /// (Bob has verified alice and waits until Alice does the same for him) #[strum(props(id = "2061"))] - SecurejoinJoinerProgress { contact_id: u32, progress: usize }, + SecurejoinJoinerProgress { + contact_id: ContactId, + progress: usize, + }, /// The connectivity to the server changed. /// This means that you should refresh the connectivity view diff --git a/src/job.rs b/src/job.rs index 174dd33b0..c06258c50 100644 --- a/src/job.rs +++ b/src/job.rs @@ -9,7 +9,7 @@ use deltachat_derive::{FromSql, ToSql}; use rand::{thread_rng, Rng}; use crate::config::Config; -use crate::contact::{normalize_name, Contact, Modifier, Origin}; +use crate::contact::{normalize_name, Contact, ContactId, Modifier, Origin}; use crate::context::Context; use crate::dc_tools::time; use crate::events::EventType; @@ -224,7 +224,7 @@ impl Job { async fn get_additional_mdn_jobs( &self, context: &Context, - contact_id: u32, + contact_id: ContactId, ) -> Result<(Vec, Vec)> { // Extract message IDs from job parameters let res: Vec<(u32, MsgId)> = context @@ -271,7 +271,7 @@ impl Job { return Status::Finished(Err(format_err!("MDNs are disabled"))); } - let contact_id = self.foreign_id; + let contact_id = ContactId::new(self.foreign_id); let contact = job_try!(Contact::load_from_db(context, contact_id).await); if contact.is_blocked() { return Status::Finished(Err(format_err!("Contact is blocked"))); @@ -685,7 +685,11 @@ async fn send_mdn(context: &Context, msg: &Message) -> Result<()> { let mut param = Params::new(); param.set(Param::MsgId, msg.id.to_u32().to_string()); - add(context, Job::new(Action::SendMdn, msg.from_id, param, 0)).await?; + add( + context, + Job::new(Action::SendMdn, msg.from_id.to_u32(), param, 0), + ) + .await?; Ok(()) } diff --git a/src/location.rs b/src/location.rs index 6f1505a78..b092c750a 100644 --- a/src/location.rs +++ b/src/location.rs @@ -8,6 +8,7 @@ use quick_xml::events::{BytesEnd, BytesStart, BytesText}; use crate::chat::{self, ChatId}; use crate::config::Config; use crate::constants::{Viewtype, DC_CONTACT_ID_SELF}; +use crate::contact::ContactId; use crate::context::Context; use crate::dc_tools::time; use crate::events::EventType; @@ -25,7 +26,7 @@ pub struct Location { pub longitude: f64, pub accuracy: f64, pub timestamp: i64, - pub contact_id: u32, + pub contact_id: ContactId, pub msg_id: u32, pub chat_id: ChatId, pub marker: Option, @@ -558,7 +559,7 @@ pub async fn set_msg_location_id(context: &Context, msg_id: MsgId, location_id: pub(crate) async fn save( context: &Context, chat_id: ChatId, - contact_id: u32, + contact_id: ContactId, locations: &[Location], independent: bool, ) -> Result> { @@ -585,12 +586,12 @@ pub(crate) async fn save( conn.prepare_cached("SELECT id FROM locations WHERE timestamp=? AND from_id=?")?; let mut stmt_insert = conn.prepare_cached(stmt_insert)?; - let exists = stmt_test.exists(paramsv![timestamp, contact_id as i32])?; + let exists = stmt_test.exists(paramsv![timestamp, contact_id])?; if independent || !exists { stmt_insert.execute(paramsv![ timestamp, - contact_id as i32, + contact_id, chat_id, latitude, longitude, diff --git a/src/message.rs b/src/message.rs index d8d672c33..736e5f2bb 100644 --- a/src/message.rs +++ b/src/message.rs @@ -1,7 +1,6 @@ //! # Messages and their identifiers. use std::collections::BTreeSet; -use std::convert::TryInto; use anyhow::{ensure, format_err, Context as _, Result}; use async_std::path::{Path, PathBuf}; @@ -14,7 +13,7 @@ use crate::constants::{ Blocked, Chattype, VideochatType, Viewtype, DC_CHAT_ID_TRASH, DC_CONTACT_ID_INFO, DC_CONTACT_ID_SELF, DC_DESIRED_TEXT_LEN, DC_MSG_ID_LAST_SPECIAL, }; -use crate::contact::{Contact, Origin}; +use crate::contact::{Contact, ContactId, Origin}; use crate::context::Context; use crate::dc_tools::{ dc_create_smeared_timestamp, dc_get_filebytes, dc_get_filemeta, dc_gm2local_offset, @@ -240,8 +239,8 @@ impl Default for MessengerMessage { #[derive(Debug, Clone, Default, Serialize, Deserialize)] pub struct Message { pub(crate) id: MsgId, - pub(crate) from_id: u32, - pub(crate) to_id: u32, + pub(crate) from_id: ContactId, + pub(crate) to_id: ContactId, pub(crate) chat_id: ChatId, pub(crate) viewtype: Viewtype, pub(crate) state: MessageState, @@ -456,7 +455,7 @@ impl Message { self.id } - pub fn get_from_id(&self) -> u32 { + pub fn get_from_id(&self) -> ContactId { self.from_id } @@ -1049,7 +1048,7 @@ pub async fn get_msg_info(context: &Context, msg_id: MsgId) -> Result { "SELECT contact_id, timestamp_sent FROM msgs_mdns WHERE msg_id=?;", paramsv![msg_id], |row| { - let contact_id: i32 = row.get(0)?; + let contact_id: ContactId = row.get(0)?; let ts: i64 = row.get(1)?; Ok((contact_id, ts)) }, @@ -1061,7 +1060,7 @@ pub async fn get_msg_info(context: &Context, msg_id: MsgId) -> Result { let fts = dc_timestamp_to_str(ts); ret += &format!("Read: {}", fts); - let name = Contact::load_from_db(context, contact_id.try_into()?) + let name = Contact::load_from_db(context, contact_id) .await .map(|contact| contact.get_name_n_addr()) .unwrap_or_default(); @@ -1426,7 +1425,7 @@ pub async fn set_msg_failed(context: &Context, msg_id: MsgId, error: Option Result> { @@ -1479,7 +1478,7 @@ pub async fn handle_mdn( .sql .exists( "SELECT COUNT(*) FROM msgs_mdns WHERE msg_id=? AND contact_id=?;", - paramsv![msg_id, from_id as i32,], + paramsv![msg_id, from_id], ) .await? { @@ -1487,7 +1486,7 @@ pub async fn handle_mdn( .sql .execute( "INSERT INTO msgs_mdns (msg_id, contact_id, timestamp_sent) VALUES (?, ?, ?);", - paramsv![msg_id, from_id as i32, timestamp_sent], + paramsv![msg_id, from_id, timestamp_sent], ) .await?; } diff --git a/src/mimeparser.rs b/src/mimeparser.rs index 8b23c552d..9fd126586 100644 --- a/src/mimeparser.rs +++ b/src/mimeparser.rs @@ -13,7 +13,7 @@ use once_cell::sync::Lazy; use crate::aheader::Aheader; use crate::blob::BlobObject; use crate::constants::{Viewtype, DC_DESIRED_TEXT_LEN, DC_ELLIPSIS}; -use crate::contact::addr_normalize; +use crate::contact::{addr_normalize, ContactId}; use crate::context::Context; use crate::dc_tools::{dc_get_filemeta, dc_truncate, parse_receive_headers}; use crate::dehtml::dehtml; @@ -1369,7 +1369,7 @@ impl MimeMessage { pub async fn handle_reports( &self, context: &Context, - from_id: u32, + from_id: ContactId, sent_timestamp: i64, parts: &[Part], ) { diff --git a/src/qr.rs b/src/qr.rs index a0e669b26..5edbd9588 100644 --- a/src/qr.rs +++ b/src/qr.rs @@ -9,7 +9,7 @@ use std::collections::BTreeMap; use crate::chat::{self, get_chat_id_by_grpid, ChatIdBlocked}; use crate::config::Config; use crate::constants::Blocked; -use crate::contact::{addr_normalize, may_be_valid_addr, Contact, Origin}; +use crate::contact::{addr_normalize, may_be_valid_addr, Contact, ContactId, Origin}; use crate::context::Context; use crate::dc_tools::time; use crate::key::Fingerprint; @@ -30,7 +30,7 @@ const HTTPS_SCHEME: &str = "https://"; #[derive(Debug, Clone, PartialEq)] pub enum Qr { AskVerifyContact { - contact_id: u32, + contact_id: ContactId, fingerprint: Fingerprint, invitenumber: String, authcode: String, @@ -38,16 +38,16 @@ pub enum Qr { AskVerifyGroup { grpname: String, grpid: String, - contact_id: u32, + contact_id: ContactId, fingerprint: Fingerprint, invitenumber: String, authcode: String, }, FprOk { - contact_id: u32, + contact_id: ContactId, }, FprMismatch { - contact_id: Option, + contact_id: Option, }, FprWithoutAddr { fingerprint: String, @@ -60,7 +60,7 @@ pub enum Qr { instance_pattern: String, }, Addr { - contact_id: u32, + contact_id: ContactId, }, Url { url: String, @@ -69,7 +69,7 @@ pub enum Qr { text: String, }, WithdrawVerifyContact { - contact_id: u32, + contact_id: ContactId, fingerprint: Fingerprint, invitenumber: String, authcode: String, @@ -77,13 +77,13 @@ pub enum Qr { WithdrawVerifyGroup { grpname: String, grpid: String, - contact_id: u32, + contact_id: ContactId, fingerprint: Fingerprint, invitenumber: String, authcode: String, }, ReviveVerifyContact { - contact_id: u32, + contact_id: ContactId, fingerprint: Fingerprint, invitenumber: String, authcode: String, @@ -91,7 +91,7 @@ pub enum Qr { ReviveVerifyGroup { grpname: String, grpid: String, - contact_id: u32, + contact_id: ContactId, fingerprint: Fingerprint, invitenumber: String, authcode: String, @@ -711,7 +711,7 @@ mod tests { .. } = qr { - assert_ne!(contact_id, 0); + assert_ne!(contact_id, ContactId::new(0)); assert_eq!(grpname, "test ? test !"); } else { bail!("Wrong QR code type"); @@ -729,7 +729,7 @@ mod tests { .. } = qr { - assert_ne!(contact_id, 0); + assert_ne!(contact_id, ContactId::new(0)); assert_eq!(grpname, "test ? test !"); let contact = Contact::get_by_id(&ctx.ctx, contact_id).await?; @@ -751,7 +751,7 @@ mod tests { ).await?; if let Qr::AskVerifyContact { contact_id, .. } = qr { - assert_ne!(contact_id, 0); + assert_ne!(contact_id, ContactId::new(0)); } else { bail!("Wrong QR code type"); } diff --git a/src/securejoin.rs b/src/securejoin.rs index a4d76dbeb..0c2e821a0 100644 --- a/src/securejoin.rs +++ b/src/securejoin.rs @@ -9,7 +9,7 @@ use crate::aheader::EncryptPreference; use crate::chat::{self, Chat, ChatId, ChatIdBlocked}; use crate::config::Config; use crate::constants::{Blocked, Viewtype, DC_CONTACT_ID_LAST_SPECIAL}; -use crate::contact::{Contact, Origin, VerifiedStatus}; +use crate::contact::{Contact, ContactId, Origin, VerifiedStatus}; use crate::context::Context; use crate::dc_tools::time; use crate::e2ee::ensure_secret_key_exists; @@ -205,7 +205,7 @@ pub struct SendMsgError(#[from] anyhow::Error); /// Bob's handshake messages are sent in `BobState::send_handshake_message()`. async fn send_alice_handshake_msg( context: &Context, - contact_id: u32, + contact_id: ContactId, step: &str, fingerprint: Option, ) -> Result<(), SendMsgError> { @@ -233,7 +233,7 @@ async fn send_alice_handshake_msg( } /// Get an unblocked chat that can be used for info messages. -async fn info_chat_id(context: &Context, contact_id: u32) -> Result { +async fn info_chat_id(context: &Context, contact_id: ContactId) -> Result { let chat_id_blocked = ChatIdBlocked::get_for_contact(context, contact_id, Blocked::Not).await?; Ok(chat_id_blocked.id) } @@ -241,7 +241,7 @@ async fn info_chat_id(context: &Context, contact_id: u32) -> Result { async fn fingerprint_equals_sender( context: &Context, fingerprint: &Fingerprint, - contact_id: u32, + contact_id: ContactId, ) -> Result { let contact = Contact::load_from_db(context, contact_id).await?; let peerstate = match Peerstate::from_addr(context, contact.get_addr()).await { @@ -308,7 +308,7 @@ pub(crate) enum HandshakeMessage { pub(crate) async fn handle_securejoin_handshake( context: &Context, mime_message: &MimeMessage, - contact_id: u32, + contact_id: ContactId, ) -> Result { if contact_id <= DC_CONTACT_ID_LAST_SPECIAL { return Err(Error::msg("Can not be called with special contact ID")); @@ -571,7 +571,7 @@ pub(crate) async fn handle_securejoin_handshake( pub(crate) async fn observe_securejoin_on_other_device( context: &Context, mime_message: &MimeMessage, - contact_id: u32, + contact_id: ContactId, ) -> Result { if contact_id <= DC_CONTACT_ID_LAST_SPECIAL { return Err(Error::msg("Can not be called with special contact ID")); @@ -636,7 +636,7 @@ pub(crate) async fn observe_securejoin_on_other_device( async fn secure_connection_established( context: &Context, - contact_id: u32, + contact_id: ContactId, chat_id: ChatId, ) -> Result<(), Error> { let contact = Contact::get_by_id(context, contact_id).await?; @@ -648,7 +648,7 @@ async fn secure_connection_established( async fn could_not_establish_secure_connection( context: &Context, - contact_id: u32, + contact_id: ContactId, chat_id: ChatId, details: &str, ) -> Result<(), Error> { diff --git a/src/securejoin/qrinvite.rs b/src/securejoin/qrinvite.rs index 9e25a6159..4f961e78e 100644 --- a/src/securejoin/qrinvite.rs +++ b/src/securejoin/qrinvite.rs @@ -8,6 +8,7 @@ use std::convert::TryFrom; use anyhow::{bail, Error, Result}; +use crate::contact::ContactId; use crate::key::Fingerprint; use crate::qr::Qr; @@ -17,13 +18,13 @@ use crate::qr::Qr; #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub enum QrInvite { Contact { - contact_id: u32, + contact_id: ContactId, fingerprint: Fingerprint, invitenumber: String, authcode: String, }, Group { - contact_id: u32, + contact_id: ContactId, fingerprint: Fingerprint, name: String, grpid: String, @@ -37,7 +38,7 @@ impl QrInvite { /// /// The actual QR-code contains a URL-encoded email address, but upon scanning this is /// translated to a contact ID. - pub fn contact_id(&self) -> u32 { + pub fn contact_id(&self) -> ContactId { match self { Self::Contact { contact_id, .. } | Self::Group { contact_id, .. } => *contact_id, } diff --git a/src/stock_str.rs b/src/stock_str.rs index eabdc0260..c6299b377 100644 --- a/src/stock_str.rs +++ b/src/stock_str.rs @@ -11,7 +11,7 @@ use crate::blob::BlobObject; use crate::chat::{self, Chat, ChatId, ProtectionStatus}; use crate::config::Config; use crate::constants::{Viewtype, DC_CONTACT_ID_SELF}; -use crate::contact::{Contact, Origin}; +use crate::contact::{Contact, ContactId, Origin}; use crate::context::Context; use crate::dc_tools::dc_timestamp_to_str; use crate::message::Message; @@ -389,7 +389,7 @@ trait StockStringMods: AsRef + Sized { fn action_by_contact<'a>( self, context: &'a Context, - contact_id: u32, + contact_id: ContactId, ) -> Pin + Send + 'a>> where Self: Send + 'a, @@ -457,7 +457,7 @@ pub(crate) async fn msg_grp_name( context: &Context, from_group: impl AsRef, to_group: impl AsRef, - by_contact: u32, + by_contact: ContactId, ) -> String { translated(context, StockMessage::MsgGrpName) .await @@ -468,7 +468,7 @@ pub(crate) async fn msg_grp_name( } /// Stock string: `Group image changed.`. -pub(crate) async fn msg_grp_img_changed(context: &Context, by_contact: u32) -> String { +pub(crate) async fn msg_grp_img_changed(context: &Context, by_contact: ContactId) -> String { translated(context, StockMessage::MsgGrpImgChanged) .await .action_by_contact(context, by_contact) @@ -482,7 +482,7 @@ pub(crate) async fn msg_grp_img_changed(context: &Context, by_contact: u32) -> S pub(crate) async fn msg_add_member( context: &Context, added_member_addr: impl AsRef, - by_contact: u32, + by_contact: ContactId, ) -> String { let addr = added_member_addr.as_ref(); let who = match Contact::lookup_id_by_addr(context, addr, Origin::Unknown).await { @@ -506,7 +506,7 @@ pub(crate) async fn msg_add_member( pub(crate) async fn msg_del_member( context: &Context, removed_member_addr: impl AsRef, - by_contact: u32, + by_contact: ContactId, ) -> String { let addr = removed_member_addr.as_ref(); let who = match Contact::lookup_id_by_addr(context, addr, Origin::Unknown).await { @@ -524,7 +524,7 @@ pub(crate) async fn msg_del_member( } /// Stock string: `Group left.`. -pub(crate) async fn msg_group_left(context: &Context, by_contact: u32) -> String { +pub(crate) async fn msg_group_left(context: &Context, by_contact: ContactId) -> String { translated(context, StockMessage::MsgGroupLeft) .await .action_by_contact(context, by_contact) @@ -574,7 +574,7 @@ pub(crate) async fn read_rcpt_mail_body(context: &Context, message: impl AsRef String { +pub(crate) async fn msg_grp_img_deleted(context: &Context, by_contact: ContactId) -> String { translated(context, StockMessage::MsgGrpImgDeleted) .await .action_by_contact(context, by_contact) @@ -587,7 +587,10 @@ pub(crate) async fn e2e_preferred(context: &Context) -> String { } /// Stock string: `%1$s invited you to join this group. Waiting for the device of %2$s to reply…`. -pub(crate) async fn secure_join_started(context: &Context, inviter_contact_id: u32) -> String { +pub(crate) async fn secure_join_started( + context: &Context, + inviter_contact_id: ContactId, +) -> String { if let Ok(contact) = Contact::get_by_id(context, inviter_contact_id).await { translated(context, StockMessage::SecureJoinStarted) .await @@ -602,7 +605,7 @@ pub(crate) async fn secure_join_started(context: &Context, inviter_contact_id: u } /// Stock string: `%1$s replied, waiting for being added to the group…`. -pub(crate) async fn secure_join_replies(context: &Context, contact_id: u32) -> String { +pub(crate) async fn secure_join_replies(context: &Context, contact_id: ContactId) -> String { if let Ok(contact) = Contact::get_by_id(context, contact_id).await { translated(context, StockMessage::SecureJoinReplies) .await @@ -718,7 +721,7 @@ pub(crate) async fn msg_location_enabled(context: &Context) -> String { } /// Stock string: `Location streaming enabled by ...`. -pub(crate) async fn msg_location_enabled_by(context: &Context, contact: u32) -> String { +pub(crate) async fn msg_location_enabled_by(context: &Context, contact: ContactId) -> String { translated(context, StockMessage::MsgLocationEnabled) .await .action_by_contact(context, contact) @@ -784,7 +787,10 @@ pub(crate) async fn failed_sending_to(context: &Context, name: impl AsRef) } /// Stock string: `Message deletion timer is disabled.`. -pub(crate) async fn msg_ephemeral_timer_disabled(context: &Context, by_contact: u32) -> String { +pub(crate) async fn msg_ephemeral_timer_disabled( + context: &Context, + by_contact: ContactId, +) -> String { translated(context, StockMessage::MsgEphemeralTimerDisabled) .await .action_by_contact(context, by_contact) @@ -795,7 +801,7 @@ pub(crate) async fn msg_ephemeral_timer_disabled(context: &Context, by_contact: pub(crate) async fn msg_ephemeral_timer_enabled( context: &Context, timer: impl AsRef, - by_contact: u32, + by_contact: ContactId, ) -> String { translated(context, StockMessage::MsgEphemeralTimerEnabled) .await @@ -805,7 +811,7 @@ pub(crate) async fn msg_ephemeral_timer_enabled( } /// Stock string: `Message deletion timer is set to 1 minute.`. -pub(crate) async fn msg_ephemeral_timer_minute(context: &Context, by_contact: u32) -> String { +pub(crate) async fn msg_ephemeral_timer_minute(context: &Context, by_contact: ContactId) -> String { translated(context, StockMessage::MsgEphemeralTimerMinute) .await .action_by_contact(context, by_contact) @@ -813,7 +819,7 @@ pub(crate) async fn msg_ephemeral_timer_minute(context: &Context, by_contact: u3 } /// Stock string: `Message deletion timer is set to 1 hour.`. -pub(crate) async fn msg_ephemeral_timer_hour(context: &Context, by_contact: u32) -> String { +pub(crate) async fn msg_ephemeral_timer_hour(context: &Context, by_contact: ContactId) -> String { translated(context, StockMessage::MsgEphemeralTimerHour) .await .action_by_contact(context, by_contact) @@ -821,7 +827,7 @@ pub(crate) async fn msg_ephemeral_timer_hour(context: &Context, by_contact: u32) } /// Stock string: `Message deletion timer is set to 1 day.`. -pub(crate) async fn msg_ephemeral_timer_day(context: &Context, by_contact: u32) -> String { +pub(crate) async fn msg_ephemeral_timer_day(context: &Context, by_contact: ContactId) -> String { translated(context, StockMessage::MsgEphemeralTimerDay) .await .action_by_contact(context, by_contact) @@ -829,7 +835,7 @@ pub(crate) async fn msg_ephemeral_timer_day(context: &Context, by_contact: u32) } /// Stock string: `Message deletion timer is set to 1 week.`. -pub(crate) async fn msg_ephemeral_timer_week(context: &Context, by_contact: u32) -> String { +pub(crate) async fn msg_ephemeral_timer_week(context: &Context, by_contact: ContactId) -> String { translated(context, StockMessage::MsgEphemeralTimerWeek) .await .action_by_contact(context, by_contact) @@ -874,7 +880,7 @@ pub(crate) async fn error_no_network(context: &Context) -> String { } /// Stock string: `Chat protection enabled.`. -pub(crate) async fn protection_enabled(context: &Context, by_contact: u32) -> String { +pub(crate) async fn protection_enabled(context: &Context, by_contact: ContactId) -> String { translated(context, StockMessage::ProtectionEnabled) .await .action_by_contact(context, by_contact) @@ -882,7 +888,7 @@ pub(crate) async fn protection_enabled(context: &Context, by_contact: u32) -> St } /// Stock string: `Chat protection disabled.`. -pub(crate) async fn protection_disabled(context: &Context, by_contact: u32) -> String { +pub(crate) async fn protection_disabled(context: &Context, by_contact: ContactId) -> String { translated(context, StockMessage::ProtectionDisabled) .await .action_by_contact(context, by_contact) @@ -908,7 +914,7 @@ pub(crate) async fn delete_server_turned_off(context: &Context) -> String { pub(crate) async fn msg_ephemeral_timer_minutes( context: &Context, minutes: impl AsRef, - by_contact: u32, + by_contact: ContactId, ) -> String { translated(context, StockMessage::MsgEphemeralTimerMinutes) .await @@ -921,7 +927,7 @@ pub(crate) async fn msg_ephemeral_timer_minutes( pub(crate) async fn msg_ephemeral_timer_hours( context: &Context, hours: impl AsRef, - by_contact: u32, + by_contact: ContactId, ) -> String { translated(context, StockMessage::MsgEphemeralTimerHours) .await @@ -934,7 +940,7 @@ pub(crate) async fn msg_ephemeral_timer_hours( pub(crate) async fn msg_ephemeral_timer_days( context: &Context, days: impl AsRef, - by_contact: u32, + by_contact: ContactId, ) -> String { translated(context, StockMessage::MsgEphemeralTimerDays) .await @@ -947,7 +953,7 @@ pub(crate) async fn msg_ephemeral_timer_days( pub(crate) async fn msg_ephemeral_timer_weeks( context: &Context, weeks: impl AsRef, - by_contact: u32, + by_contact: ContactId, ) -> String { translated(context, StockMessage::MsgEphemeralTimerWeeks) .await @@ -1104,7 +1110,7 @@ impl Context { pub(crate) async fn stock_protection_msg( &self, protect: ProtectionStatus, - from_id: u32, + from_id: ContactId, ) -> String { match protect { ProtectionStatus::Unprotected => protection_enabled(self, from_id).await, diff --git a/src/test_utils.rs b/src/test_utils.rs index 110a211da..feeaf6be0 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -851,7 +851,7 @@ async fn log_msg(context: &Context, prefix: impl AsRef, msg: &Message) { &contact_name, contact_id, msgtext.unwrap_or_default(), - if msg.get_from_id() == 1u32 { + if msg.get_from_id() == DC_CONTACT_ID_SELF { "" } else if msg.get_state() == MessageState::InSeen { "[SEEN]" diff --git a/src/update_helper.rs b/src/update_helper.rs index 2e200e5dc..3dc1629ef 100644 --- a/src/update_helper.rs +++ b/src/update_helper.rs @@ -1,7 +1,7 @@ //! # Functions to update timestamps. use crate::chat::{Chat, ChatId}; -use crate::contact::Contact; +use crate::contact::{Contact, ContactId}; use crate::context::Context; use crate::param::{Param, Params}; use anyhow::Result; @@ -12,7 +12,7 @@ impl Context { /// (if we have a ContactId type at some point, the function should go there) pub(crate) async fn update_contacts_timestamp( &self, - contact_id: u32, + contact_id: ContactId, scope: Param, new_timestamp: i64, ) -> Result {