diff --git a/src/contact.rs b/src/contact.rs index a08e7b0e3..e094972c9 100644 --- a/src/contact.rs +++ b/src/contact.rs @@ -15,8 +15,9 @@ use crate::chat::ChatId; use crate::color::str_to_color; use crate::config::Config; use crate::constants::{ - Blocked, Chattype, DC_CONTACT_ID_DEVICE, DC_CONTACT_ID_DEVICE_ADDR, DC_CONTACT_ID_LAST_SPECIAL, - DC_CONTACT_ID_SELF, DC_GCL_ADD_SELF, DC_GCL_VERIFIED_ONLY, + Blocked, Chattype, DC_CONTACT_ID_DEVICE, DC_CONTACT_ID_DEVICE_ADDR, DC_CONTACT_ID_INFO, + DC_CONTACT_ID_LAST_SPECIAL, DC_CONTACT_ID_SELF, DC_CONTACT_ID_UNDEFINED, DC_GCL_ADD_SELF, + DC_GCL_VERIFIED_ONLY, }; use crate::context::Context; use crate::dc_tools::{dc_get_abs_path, improve_single_line_input, EmailAddress}; @@ -52,21 +53,19 @@ impl ContactId { 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) - // } + 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) + } } } diff --git a/src/dc_receive_imf.rs b/src/dc_receive_imf.rs index c1ac86893..290bbed22 100644 --- a/src/dc_receive_imf.rs +++ b/src/dc_receive_imf.rs @@ -16,6 +16,7 @@ use crate::config::Config; use crate::constants::{ Blocked, Chattype, ShowEmails, DC_CHAT_ID_TRASH, DC_CONTACT_ID_LAST_SPECIAL, DC_CONTACT_ID_SELF, }; +use crate::contact; use crate::contact::{ addr_cmp, may_be_valid_addr, normalize_name, Contact, ContactId, Origin, VerifiedStatus, }; @@ -26,6 +27,7 @@ use crate::ephemeral::{stock_ephemeral_timer_changed, Timer as EphemeralTimer}; use crate::events::EventType; use crate::headerdef::{HeaderDef, HeaderDefMap}; use crate::job::{self, Action}; +use crate::location; use crate::log::LogExt; use crate::message::{ self, rfc724_mid_exists, Message, MessageState, MessengerMessage, MsgId, Viewtype, @@ -36,8 +38,8 @@ use crate::mimeparser::{ use crate::param::{Param, Params}; use crate::peerstate::{Peerstate, PeerstateKeyType, PeerstateVerifiedStatus}; use crate::securejoin::{self, handle_securejoin_handshake, observe_securejoin_on_other_device}; +use crate::sql; use crate::stock_str; -use crate::{contact, location}; #[derive(Debug, PartialEq, Eq)] enum CreateEvent { @@ -2017,25 +2019,25 @@ async fn create_adhoc_group( /// 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: &[ContactId]) -> Result { - let member_ids_str = member_ids - .iter() - .map(|x| x.to_string()) - .collect::>() - .join(","); let member_cs = context .get_config(Config::ConfiguredAddr) .await? .unwrap_or_else(|| "no-self".to_string()) .to_lowercase(); + let query = format!( + "SELECT addr FROM contacts WHERE id IN({}) AND id!=?", + sql::repeat_vars(member_ids.len())? + ); + let mut params = Vec::new(); + params.extend_from_slice(member_ids); + params.push(DC_CONTACT_ID_SELF); + let members = context .sql .query_map( - format!( - "SELECT addr FROM contacts WHERE id IN({}) AND id!=1", // 1=DC_CONTACT_ID_SELF - member_ids_str - ), - paramsv![], + query, + rusqlite::params_from_iter(params), |row| row.get::<_, String>(0), |rows| { let mut addrs = rows.collect::, _>>()?; diff --git a/src/sql.rs b/src/sql.rs index 89375b452..d44b9db5d 100644 --- a/src/sql.rs +++ b/src/sql.rs @@ -797,6 +797,19 @@ async fn prune_tombstones(sql: &Sql) -> Result<()> { Ok(()) } +/// Helper function to return comma-separated sequence of `?` chars. +/// +/// Use this together with [`rusqlite::ParamsFromIter`] to use dynamically generated +/// parameter lists. +pub fn repeat_vars(count: usize) -> Result { + if count == 0 { + bail!("Must have at least one repeat variable"); + } + let mut s = "?,".repeat(count); + s.pop(); // Remove trailing comma + Ok(s) +} + #[cfg(test)] mod tests { use async_std::channel;