diff --git a/Cargo.lock b/Cargo.lock index b806cfa6c..3c11402ac 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1084,7 +1084,6 @@ dependencies = [ "hex", "humansize", "image", - "indexmap", "kamadak-exif", "lettre_email", "libc", @@ -1935,16 +1934,6 @@ dependencies = [ "nom 6.1.2", ] -[[package]] -name = "indexmap" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" -dependencies = [ - "autocfg 1.0.1", - "hashbrown", -] - [[package]] name = "infer" version = "0.2.3" diff --git a/Cargo.toml b/Cargo.toml index 40e7a6f3b..d81f87952 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,7 +36,6 @@ escaper = "0.1" futures = "0.3" hex = "0.4.0" image = { version = "0.23.5", default-features=false, features = ["gif", "jpeg", "ico", "png", "pnm", "webp", "bmp"] } -indexmap = "1.7" kamadak-exif = "0.5" lettre_email = { git = "https://github.com/deltachat/lettre", branch = "master" } libc = "0.2" diff --git a/src/dc_receive_imf.rs b/src/dc_receive_imf.rs index d3692a742..7b06d75a8 100644 --- a/src/dc_receive_imf.rs +++ b/src/dc_receive_imf.rs @@ -1,6 +1,7 @@ //! Internet Message Format reception pipeline. use std::cmp::min; +use std::collections::BTreeSet; use std::convert::TryFrom; use anyhow::{bail, ensure, Context as _, Result}; @@ -35,9 +36,6 @@ use crate::securejoin::{self, handle_securejoin_handshake, observe_securejoin_on use crate::stock_str; use crate::{contact, location}; -// IndexSet is like HashSet but maintains order of insertion. -type ContactIds = indexmap::IndexSet; - #[derive(Debug, PartialEq, Eq)] enum CreateEvent { MsgsChanged, @@ -162,23 +160,19 @@ pub(crate) async fn dc_receive_imf_inner( let incoming = from_id != DC_CONTACT_ID_SELF; - let mut to_ids = ContactIds::new(); - - to_ids.extend( - &dc_add_or_lookup_contacts_by_address_list( - context, - &mime_parser.recipients, - if !incoming { - Origin::OutgoingTo - } else if incoming_origin.is_known() { - Origin::IncomingTo - } else { - Origin::IncomingUnknownTo - }, - prevent_rename, - ) - .await?, - ); + let to_ids = dc_add_or_lookup_contacts_by_address_list( + context, + &mime_parser.recipients, + if !incoming { + Origin::OutgoingTo + } else if incoming_origin.is_known() { + Origin::IncomingTo + } else { + Origin::IncomingUnknownTo + }, + prevent_rename, + ) + .await?; let rcvd_timestamp = dc_smeared_time(context).await; let sent_timestamp = mime_parser @@ -402,7 +396,7 @@ pub async fn from_field_to_contact_id( "mail has more than one From address, only using first: {:?}", from_address_list ); } - let from_id = from_ids.get_index(0).cloned().unwrap_or_default(); + let from_id = from_ids.get(0).cloned().unwrap_or_default(); let mut from_id_blocked = false; let mut incoming_origin = Origin::Unknown; @@ -430,7 +424,7 @@ async fn add_parts( incoming_origin: Origin, server_folder: &str, server_uid: u32, - to_ids: &ContactIds, + to_ids: &[u32], rfc724_mid: String, sent_timestamp: i64, rcvd_timestamp: i64, @@ -724,7 +718,7 @@ async fn add_parts( // the mail is on the IMAP server, probably it is also delivered. // We cannot recreate other states (read, error). state = MessageState::OutDelivered; - to_id = to_ids.get_index(0).cloned().unwrap_or_default(); + to_id = to_ids.get(0).cloned().unwrap_or_default(); let self_sent = from_id == DC_CONTACT_ID_SELF && to_ids.len() == 1 @@ -1316,7 +1310,7 @@ async fn lookup_chat_by_reply( mime_parser: &mut MimeMessage, parent: &Option, from_id: u32, - to_ids: &ContactIds, + to_ids: &[u32], ) -> Result> { // Try to assign message to the same chat as the parent message. @@ -1356,7 +1350,7 @@ 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: &indexmap::IndexSet, + to_ids: &[u32], mime_parser: &MimeMessage, parent_chat_id: ChatId, from_id: u32, @@ -1368,7 +1362,7 @@ async fn is_probably_private_reply( // should be assigned to the group chat. We restrict this exception to classical emails, as chat-group-messages // contain a Chat-Group-Id header and can be sorted into the correct chat this way. - let private_message = to_ids == &[DC_CONTACT_ID_SELF].iter().copied().collect::(); + let private_message = to_ids == [DC_CONTACT_ID_SELF].iter().copied().collect::>(); if !private_message { return Ok(false); } @@ -1397,7 +1391,7 @@ async fn create_or_lookup_group( allow_creation: bool, create_blocked: Blocked, from_id: u32, - to_ids: &ContactIds, + to_ids: &[u32], ) -> Result> { let grpid = if let Some(grpid) = try_getting_grpid(mime_parser) { grpid @@ -1541,7 +1535,7 @@ async fn apply_group_changes( sent_timestamp: i64, chat_id: ChatId, from_id: u32, - to_ids: &ContactIds, + to_ids: &[u32], ) -> Result<()> { let mut chat = Chat::load_from_db(context, chat_id).await?; if chat.typ != Chattype::Group { @@ -1981,7 +1975,7 @@ async fn check_verified_properties( context: &Context, mimeparser: &MimeMessage, from_id: u32, - to_ids: &ContactIds, + to_ids: &[u32], ) -> Result<()> { let contact = Contact::load_from_db(context, from_id).await?; @@ -2024,8 +2018,11 @@ async fn check_verified_properties( } // we do not need to check if we are verified with ourself - let mut to_ids = to_ids.clone(); - to_ids.remove(&DC_CONTACT_ID_SELF); + let to_ids = to_ids + .iter() + .copied() + .filter(|id| *id != DC_CONTACT_ID_SELF) + .collect::>(); if to_ids.is_empty() { return Ok(()); @@ -2188,6 +2185,10 @@ pub(crate) async fn get_prefetch_parent_message( Ok(None) } +/// Looks up contact IDs from the database given the list of recipients. +/// +/// Returns vector of IDs guaranteed to be unique. +/// /// * param `prevent_rename`: if true, the display_name of this contact will not be changed. Useful for /// mailing lists: In some mailing lists, many users write from the same address but with different /// display names. We don't want the display name to change everytime the user gets a new email from @@ -2197,8 +2198,8 @@ async fn dc_add_or_lookup_contacts_by_address_list( address_list: &[SingleInfo], origin: Origin, prevent_rename: bool, -) -> Result { - let mut contact_ids = ContactIds::new(); +) -> Result> { + let mut contact_ids = BTreeSet::new(); for info in address_list.iter() { let display_name = if prevent_rename { Some("") @@ -2210,7 +2211,7 @@ async fn dc_add_or_lookup_contacts_by_address_list( ); } - Ok(contact_ids) + Ok(contact_ids.into_iter().collect::>()) } /// Add contacts to database on receiving messages. diff --git a/src/quota.rs b/src/quota.rs index 896c2348b..3b6dc1eb7 100644 --- a/src/quota.rs +++ b/src/quota.rs @@ -2,7 +2,7 @@ use anyhow::{anyhow, Result}; use async_imap::types::{Quota, QuotaResource}; -use indexmap::IndexMap; +use std::collections::BTreeMap; use crate::chat::add_device_msg_with_importance; use crate::config::Config; @@ -43,7 +43,7 @@ pub struct QuotaInfo { /// set to `Err()` if the provider does not support quota or on other errors, /// set to `Ok()` for valid quota information. /// Updated by `Action::UpdateRecentQuota` - pub(crate) recent: Result>>, + pub(crate) recent: Result>>, /// Timestamp when structure was modified. pub(crate) modified: i64, @@ -52,8 +52,8 @@ pub struct QuotaInfo { async fn get_unique_quota_roots_and_usage( folders: Vec, imap: &mut Imap, -) -> Result>> { - let mut unique_quota_roots: IndexMap> = IndexMap::new(); +) -> Result>> { + let mut unique_quota_roots: BTreeMap> = BTreeMap::new(); for folder in folders { let (quota_roots, quotas) = &imap.get_quota_roots(&folder).await?; // if there are new quota roots found in this imap folder, add them to the list @@ -69,7 +69,7 @@ async fn get_unique_quota_roots_and_usage( // messages could be recieved and so the usage could have been changed *unique_quota_roots .entry(quota_root_name.clone()) - .or_insert(vec![]) = quota.resources; + .or_insert_with(Vec::new) = quota.resources; } } } @@ -77,7 +77,7 @@ async fn get_unique_quota_roots_and_usage( } fn get_highest_usage<'t>( - unique_quota_roots: &'t IndexMap>, + unique_quota_roots: &'t BTreeMap>, ) -> Result<(u64, &'t String, &QuotaResource)> { let mut highest: Option<(u64, &'t String, &QuotaResource)> = None; for (name, resources) in unique_quota_roots {