mirror of
https://github.com/chatmail/core.git
synced 2026-05-07 08:56:30 +03:00
Remove indexmap dependency
`indexmap` is a large dependency (4K SLoC) containing `unsafe` code. Contact IDs are now passed around as a Vec<u32> or &[u32]. QUOTA roots are now sorted by name instead of perserving original order.
This commit is contained in:
11
Cargo.lock
generated
11
Cargo.lock
generated
@@ -1084,7 +1084,6 @@ dependencies = [
|
|||||||
"hex",
|
"hex",
|
||||||
"humansize",
|
"humansize",
|
||||||
"image",
|
"image",
|
||||||
"indexmap",
|
|
||||||
"kamadak-exif",
|
"kamadak-exif",
|
||||||
"lettre_email",
|
"lettre_email",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -1935,16 +1934,6 @@ dependencies = [
|
|||||||
"nom 6.1.2",
|
"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]]
|
[[package]]
|
||||||
name = "infer"
|
name = "infer"
|
||||||
version = "0.2.3"
|
version = "0.2.3"
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ escaper = "0.1"
|
|||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
hex = "0.4.0"
|
hex = "0.4.0"
|
||||||
image = { version = "0.23.5", default-features=false, features = ["gif", "jpeg", "ico", "png", "pnm", "webp", "bmp"] }
|
image = { version = "0.23.5", default-features=false, features = ["gif", "jpeg", "ico", "png", "pnm", "webp", "bmp"] }
|
||||||
indexmap = "1.7"
|
|
||||||
kamadak-exif = "0.5"
|
kamadak-exif = "0.5"
|
||||||
lettre_email = { git = "https://github.com/deltachat/lettre", branch = "master" }
|
lettre_email = { git = "https://github.com/deltachat/lettre", branch = "master" }
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
//! Internet Message Format reception pipeline.
|
//! Internet Message Format reception pipeline.
|
||||||
|
|
||||||
use std::cmp::min;
|
use std::cmp::min;
|
||||||
|
use std::collections::BTreeSet;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
use anyhow::{bail, ensure, Context as _, Result};
|
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::stock_str;
|
||||||
use crate::{contact, location};
|
use crate::{contact, location};
|
||||||
|
|
||||||
// IndexSet is like HashSet but maintains order of insertion.
|
|
||||||
type ContactIds = indexmap::IndexSet<u32>;
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
enum CreateEvent {
|
enum CreateEvent {
|
||||||
MsgsChanged,
|
MsgsChanged,
|
||||||
@@ -162,23 +160,19 @@ pub(crate) async fn dc_receive_imf_inner(
|
|||||||
|
|
||||||
let incoming = from_id != DC_CONTACT_ID_SELF;
|
let incoming = from_id != DC_CONTACT_ID_SELF;
|
||||||
|
|
||||||
let mut to_ids = ContactIds::new();
|
let to_ids = dc_add_or_lookup_contacts_by_address_list(
|
||||||
|
context,
|
||||||
to_ids.extend(
|
&mime_parser.recipients,
|
||||||
&dc_add_or_lookup_contacts_by_address_list(
|
if !incoming {
|
||||||
context,
|
Origin::OutgoingTo
|
||||||
&mime_parser.recipients,
|
} else if incoming_origin.is_known() {
|
||||||
if !incoming {
|
Origin::IncomingTo
|
||||||
Origin::OutgoingTo
|
} else {
|
||||||
} else if incoming_origin.is_known() {
|
Origin::IncomingUnknownTo
|
||||||
Origin::IncomingTo
|
},
|
||||||
} else {
|
prevent_rename,
|
||||||
Origin::IncomingUnknownTo
|
)
|
||||||
},
|
.await?;
|
||||||
prevent_rename,
|
|
||||||
)
|
|
||||||
.await?,
|
|
||||||
);
|
|
||||||
|
|
||||||
let rcvd_timestamp = dc_smeared_time(context).await;
|
let rcvd_timestamp = dc_smeared_time(context).await;
|
||||||
let sent_timestamp = mime_parser
|
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
|
"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 from_id_blocked = false;
|
||||||
let mut incoming_origin = Origin::Unknown;
|
let mut incoming_origin = Origin::Unknown;
|
||||||
@@ -430,7 +424,7 @@ async fn add_parts(
|
|||||||
incoming_origin: Origin,
|
incoming_origin: Origin,
|
||||||
server_folder: &str,
|
server_folder: &str,
|
||||||
server_uid: u32,
|
server_uid: u32,
|
||||||
to_ids: &ContactIds,
|
to_ids: &[u32],
|
||||||
rfc724_mid: String,
|
rfc724_mid: String,
|
||||||
sent_timestamp: i64,
|
sent_timestamp: i64,
|
||||||
rcvd_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.
|
// the mail is on the IMAP server, probably it is also delivered.
|
||||||
// We cannot recreate other states (read, error).
|
// We cannot recreate other states (read, error).
|
||||||
state = MessageState::OutDelivered;
|
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
|
let self_sent = from_id == DC_CONTACT_ID_SELF
|
||||||
&& to_ids.len() == 1
|
&& to_ids.len() == 1
|
||||||
@@ -1316,7 +1310,7 @@ async fn lookup_chat_by_reply(
|
|||||||
mime_parser: &mut MimeMessage,
|
mime_parser: &mut MimeMessage,
|
||||||
parent: &Option<Message>,
|
parent: &Option<Message>,
|
||||||
from_id: u32,
|
from_id: u32,
|
||||||
to_ids: &ContactIds,
|
to_ids: &[u32],
|
||||||
) -> Result<Option<(ChatId, Blocked)>> {
|
) -> Result<Option<(ChatId, Blocked)>> {
|
||||||
// Try to assign message to the same chat as the parent message.
|
// 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.
|
/// If it returns false, it shall be assigned to the parent chat.
|
||||||
async fn is_probably_private_reply(
|
async fn is_probably_private_reply(
|
||||||
context: &Context,
|
context: &Context,
|
||||||
to_ids: &indexmap::IndexSet<u32>,
|
to_ids: &[u32],
|
||||||
mime_parser: &MimeMessage,
|
mime_parser: &MimeMessage,
|
||||||
parent_chat_id: ChatId,
|
parent_chat_id: ChatId,
|
||||||
from_id: u32,
|
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
|
// 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.
|
// 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::<ContactIds>();
|
let private_message = to_ids == [DC_CONTACT_ID_SELF].iter().copied().collect::<Vec<u32>>();
|
||||||
if !private_message {
|
if !private_message {
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
@@ -1397,7 +1391,7 @@ async fn create_or_lookup_group(
|
|||||||
allow_creation: bool,
|
allow_creation: bool,
|
||||||
create_blocked: Blocked,
|
create_blocked: Blocked,
|
||||||
from_id: u32,
|
from_id: u32,
|
||||||
to_ids: &ContactIds,
|
to_ids: &[u32],
|
||||||
) -> Result<Option<(ChatId, Blocked)>> {
|
) -> Result<Option<(ChatId, Blocked)>> {
|
||||||
let grpid = if let Some(grpid) = try_getting_grpid(mime_parser) {
|
let grpid = if let Some(grpid) = try_getting_grpid(mime_parser) {
|
||||||
grpid
|
grpid
|
||||||
@@ -1541,7 +1535,7 @@ async fn apply_group_changes(
|
|||||||
sent_timestamp: i64,
|
sent_timestamp: i64,
|
||||||
chat_id: ChatId,
|
chat_id: ChatId,
|
||||||
from_id: u32,
|
from_id: u32,
|
||||||
to_ids: &ContactIds,
|
to_ids: &[u32],
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let mut chat = Chat::load_from_db(context, chat_id).await?;
|
let mut chat = Chat::load_from_db(context, chat_id).await?;
|
||||||
if chat.typ != Chattype::Group {
|
if chat.typ != Chattype::Group {
|
||||||
@@ -1981,7 +1975,7 @@ async fn check_verified_properties(
|
|||||||
context: &Context,
|
context: &Context,
|
||||||
mimeparser: &MimeMessage,
|
mimeparser: &MimeMessage,
|
||||||
from_id: u32,
|
from_id: u32,
|
||||||
to_ids: &ContactIds,
|
to_ids: &[u32],
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let contact = Contact::load_from_db(context, from_id).await?;
|
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
|
// we do not need to check if we are verified with ourself
|
||||||
let mut to_ids = to_ids.clone();
|
let to_ids = to_ids
|
||||||
to_ids.remove(&DC_CONTACT_ID_SELF);
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.filter(|id| *id != DC_CONTACT_ID_SELF)
|
||||||
|
.collect::<Vec<u32>>();
|
||||||
|
|
||||||
if to_ids.is_empty() {
|
if to_ids.is_empty() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@@ -2188,6 +2185,10 @@ pub(crate) async fn get_prefetch_parent_message(
|
|||||||
Ok(None)
|
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
|
/// * 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
|
/// 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
|
/// 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],
|
address_list: &[SingleInfo],
|
||||||
origin: Origin,
|
origin: Origin,
|
||||||
prevent_rename: bool,
|
prevent_rename: bool,
|
||||||
) -> Result<ContactIds> {
|
) -> Result<Vec<u32>> {
|
||||||
let mut contact_ids = ContactIds::new();
|
let mut contact_ids = BTreeSet::new();
|
||||||
for info in address_list.iter() {
|
for info in address_list.iter() {
|
||||||
let display_name = if prevent_rename {
|
let display_name = if prevent_rename {
|
||||||
Some("")
|
Some("")
|
||||||
@@ -2210,7 +2211,7 @@ async fn dc_add_or_lookup_contacts_by_address_list(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(contact_ids)
|
Ok(contact_ids.into_iter().collect::<Vec<u32>>())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add contacts to database on receiving messages.
|
/// Add contacts to database on receiving messages.
|
||||||
|
|||||||
12
src/quota.rs
12
src/quota.rs
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use async_imap::types::{Quota, QuotaResource};
|
use async_imap::types::{Quota, QuotaResource};
|
||||||
use indexmap::IndexMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use crate::chat::add_device_msg_with_importance;
|
use crate::chat::add_device_msg_with_importance;
|
||||||
use crate::config::Config;
|
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 `Err()` if the provider does not support quota or on other errors,
|
||||||
/// set to `Ok()` for valid quota information.
|
/// set to `Ok()` for valid quota information.
|
||||||
/// Updated by `Action::UpdateRecentQuota`
|
/// Updated by `Action::UpdateRecentQuota`
|
||||||
pub(crate) recent: Result<IndexMap<String, Vec<QuotaResource>>>,
|
pub(crate) recent: Result<BTreeMap<String, Vec<QuotaResource>>>,
|
||||||
|
|
||||||
/// Timestamp when structure was modified.
|
/// Timestamp when structure was modified.
|
||||||
pub(crate) modified: i64,
|
pub(crate) modified: i64,
|
||||||
@@ -52,8 +52,8 @@ pub struct QuotaInfo {
|
|||||||
async fn get_unique_quota_roots_and_usage(
|
async fn get_unique_quota_roots_and_usage(
|
||||||
folders: Vec<String>,
|
folders: Vec<String>,
|
||||||
imap: &mut Imap,
|
imap: &mut Imap,
|
||||||
) -> Result<IndexMap<String, Vec<QuotaResource>>> {
|
) -> Result<BTreeMap<String, Vec<QuotaResource>>> {
|
||||||
let mut unique_quota_roots: IndexMap<String, Vec<QuotaResource>> = IndexMap::new();
|
let mut unique_quota_roots: BTreeMap<String, Vec<QuotaResource>> = BTreeMap::new();
|
||||||
for folder in folders {
|
for folder in folders {
|
||||||
let (quota_roots, quotas) = &imap.get_quota_roots(&folder).await?;
|
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
|
// 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
|
// messages could be recieved and so the usage could have been changed
|
||||||
*unique_quota_roots
|
*unique_quota_roots
|
||||||
.entry(quota_root_name.clone())
|
.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>(
|
fn get_highest_usage<'t>(
|
||||||
unique_quota_roots: &'t IndexMap<String, Vec<QuotaResource>>,
|
unique_quota_roots: &'t BTreeMap<String, Vec<QuotaResource>>,
|
||||||
) -> Result<(u64, &'t String, &QuotaResource)> {
|
) -> Result<(u64, &'t String, &QuotaResource)> {
|
||||||
let mut highest: Option<(u64, &'t String, &QuotaResource)> = None;
|
let mut highest: Option<(u64, &'t String, &QuotaResource)> = None;
|
||||||
for (name, resources) in unique_quota_roots {
|
for (name, resources) in unique_quota_roots {
|
||||||
|
|||||||
Reference in New Issue
Block a user