mirror of
https://github.com/chatmail/core.git
synced 2026-10-01 18:50:39 +03:00
refactor: upgrade to Rust 2024
This commit is contained in:
+21
-12
@@ -4,7 +4,7 @@ use std::collections::BTreeMap;
|
||||
use std::future::Future;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use anyhow::{bail, ensure, Context as _, Result};
|
||||
use anyhow::{Context as _, Result, bail, ensure};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::fs;
|
||||
use tokio::io::AsyncWriteExt;
|
||||
@@ -14,7 +14,7 @@ use uuid::Uuid;
|
||||
#[cfg(not(target_os = "ios"))]
|
||||
use tokio::sync::oneshot;
|
||||
#[cfg(not(target_os = "ios"))]
|
||||
use tokio::time::{sleep, Duration};
|
||||
use tokio::time::{Duration, sleep};
|
||||
|
||||
use crate::context::{Context, ContextBuilder};
|
||||
use crate::events::{Event, EventEmitter, EventType, Events};
|
||||
@@ -352,7 +352,10 @@ impl Accounts {
|
||||
///
|
||||
/// Returns a future that resolves when background fetch is done,
|
||||
/// but does not capture `&self`.
|
||||
pub fn background_fetch(&self, timeout: std::time::Duration) -> impl Future<Output = ()> {
|
||||
pub fn background_fetch(
|
||||
&self,
|
||||
timeout: std::time::Duration,
|
||||
) -> impl Future<Output = ()> + use<> {
|
||||
let accounts: Vec<Context> = self.accounts.values().cloned().collect();
|
||||
let events = self.events.clone();
|
||||
Self::background_fetch_with_timeout(accounts, events, timeout)
|
||||
@@ -456,7 +459,9 @@ impl Config {
|
||||
Ok(())
|
||||
});
|
||||
if locked_rx.await.is_err() {
|
||||
bail!("Delta Chat is already running. To use Delta Chat, you must first close the existing Delta Chat process, or restart your device. (accounts.lock file is already locked)");
|
||||
bail!(
|
||||
"Delta Chat is already running. To use Delta Chat, you must first close the existing Delta Chat process, or restart your device. (accounts.lock file is already locked)"
|
||||
);
|
||||
};
|
||||
Ok(Some(lock_task))
|
||||
}
|
||||
@@ -500,11 +505,13 @@ impl Config {
|
||||
/// protects from parallel calls resulting to a wrong file contents.
|
||||
async fn sync(&mut self) -> Result<()> {
|
||||
#[cfg(not(target_os = "ios"))]
|
||||
ensure!(!self
|
||||
.lock_task
|
||||
.as_ref()
|
||||
.context("Config is read-only")?
|
||||
.is_finished());
|
||||
ensure!(
|
||||
!self
|
||||
.lock_task
|
||||
.as_ref()
|
||||
.context("Config is read-only")?
|
||||
.is_finished()
|
||||
);
|
||||
|
||||
let tmp_path = self.file.with_extension("toml.tmp");
|
||||
let mut file = fs::File::create(&tmp_path)
|
||||
@@ -962,9 +969,11 @@ mod tests {
|
||||
|
||||
// Test that event emitter does not return `None` immediately.
|
||||
let duration = std::time::Duration::from_millis(1);
|
||||
assert!(tokio::time::timeout(duration, event_emitter.recv())
|
||||
.await
|
||||
.is_err());
|
||||
assert!(
|
||||
tokio::time::timeout(duration, event_emitter.recv())
|
||||
.await
|
||||
.is_err()
|
||||
);
|
||||
|
||||
// When account manager is dropped, event emitter is exhausted.
|
||||
drop(accounts);
|
||||
|
||||
+34
-26
@@ -6,7 +6,7 @@ use std::collections::BTreeMap;
|
||||
use std::fmt;
|
||||
use std::str::FromStr;
|
||||
|
||||
use anyhow::{bail, Context as _, Error, Result};
|
||||
use anyhow::{Context as _, Error, Result, bail};
|
||||
|
||||
use crate::key::{DcKey, SignedPublicKey};
|
||||
|
||||
@@ -217,7 +217,9 @@ mod tests {
|
||||
let rendered = ah.to_string();
|
||||
assert_eq!(rendered, fixed_header);
|
||||
|
||||
let ah = Aheader::from_str(&format!(" _foo; __FOO=BAR ;;; addr = a@b.example.org ;\r\n prefer-encrypt = mutual ; keydata = {RAWKEY}"))?;
|
||||
let ah = Aheader::from_str(&format!(
|
||||
" _foo; __FOO=BAR ;;; addr = a@b.example.org ;\r\n prefer-encrypt = mutual ; keydata = {RAWKEY}"
|
||||
))?;
|
||||
assert_eq!(ah.addr, "a@b.example.org");
|
||||
assert_eq!(ah.prefer_encrypt, EncryptPreference::Mutual);
|
||||
|
||||
@@ -240,38 +242,44 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_display_aheader() {
|
||||
assert!(format!(
|
||||
"{}",
|
||||
Aheader::new(
|
||||
"test@example.com".to_string(),
|
||||
SignedPublicKey::from_base64(RAWKEY).unwrap(),
|
||||
EncryptPreference::Mutual
|
||||
assert!(
|
||||
format!(
|
||||
"{}",
|
||||
Aheader::new(
|
||||
"test@example.com".to_string(),
|
||||
SignedPublicKey::from_base64(RAWKEY).unwrap(),
|
||||
EncryptPreference::Mutual
|
||||
)
|
||||
)
|
||||
)
|
||||
.contains("prefer-encrypt=mutual;"));
|
||||
.contains("prefer-encrypt=mutual;")
|
||||
);
|
||||
|
||||
// According to Autocrypt Level 1 specification,
|
||||
// only "prefer-encrypt=mutual;" can be used.
|
||||
// If the setting is nopreference, the whole attribute is omitted.
|
||||
assert!(!format!(
|
||||
"{}",
|
||||
Aheader::new(
|
||||
"test@example.com".to_string(),
|
||||
SignedPublicKey::from_base64(RAWKEY).unwrap(),
|
||||
EncryptPreference::NoPreference
|
||||
assert!(
|
||||
!format!(
|
||||
"{}",
|
||||
Aheader::new(
|
||||
"test@example.com".to_string(),
|
||||
SignedPublicKey::from_base64(RAWKEY).unwrap(),
|
||||
EncryptPreference::NoPreference
|
||||
)
|
||||
)
|
||||
)
|
||||
.contains("prefer-encrypt"));
|
||||
.contains("prefer-encrypt")
|
||||
);
|
||||
|
||||
// Always lowercase the address in the header.
|
||||
assert!(format!(
|
||||
"{}",
|
||||
Aheader::new(
|
||||
"TeSt@eXaMpLe.cOm".to_string(),
|
||||
SignedPublicKey::from_base64(RAWKEY).unwrap(),
|
||||
EncryptPreference::Mutual
|
||||
assert!(
|
||||
format!(
|
||||
"{}",
|
||||
Aheader::new(
|
||||
"TeSt@eXaMpLe.cOm".to_string(),
|
||||
SignedPublicKey::from_base64(RAWKEY).unwrap(),
|
||||
EncryptPreference::Mutual
|
||||
)
|
||||
)
|
||||
)
|
||||
.contains("test@example.com"));
|
||||
.contains("test@example.com")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+7
-6
@@ -548,12 +548,13 @@ Authentication-Results: dkim=";
|
||||
let rcvd = bob.recv_msg(&sent).await;
|
||||
|
||||
// The message info should contain a warning:
|
||||
assert!(rcvd
|
||||
.id
|
||||
.get_info(&bob)
|
||||
.await
|
||||
.unwrap()
|
||||
.contains("DKIM Results: Passed=false"));
|
||||
assert!(
|
||||
rcvd.id
|
||||
.get_info(&bob)
|
||||
.await
|
||||
.unwrap()
|
||||
.contains("DKIM Results: Passed=false")
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
+4
-8
@@ -6,11 +6,11 @@ use std::iter::FusedIterator;
|
||||
use std::mem;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use anyhow::{ensure, format_err, Context as _, Result};
|
||||
use anyhow::{Context as _, Result, ensure, format_err};
|
||||
use base64::Engine as _;
|
||||
use futures::StreamExt;
|
||||
use image::codecs::jpeg::JpegEncoder;
|
||||
use image::ImageReader;
|
||||
use image::codecs::jpeg::JpegEncoder;
|
||||
use image::{DynamicImage, GenericImage, GenericImageView, ImageFormat, Pixel, Rgba};
|
||||
use num_traits::FromPrimitive;
|
||||
use tokio::{fs, task};
|
||||
@@ -20,7 +20,7 @@ use crate::config::Config;
|
||||
use crate::constants::{self, MediaQuality};
|
||||
use crate::context::Context;
|
||||
use crate::events::EventType;
|
||||
use crate::log::{error, info, warn, LogExt};
|
||||
use crate::log::{LogExt, error, info, warn};
|
||||
use crate::tools::sanitize_filename;
|
||||
|
||||
/// Represents a file in the blob directory.
|
||||
@@ -205,11 +205,7 @@ impl<'a> BlobObject<'a> {
|
||||
/// to be lowercase.
|
||||
pub fn suffix(&self) -> Option<&str> {
|
||||
let ext = self.name.rsplit('.').next();
|
||||
if ext == Some(&self.name) {
|
||||
None
|
||||
} else {
|
||||
ext
|
||||
}
|
||||
if ext == Some(&self.name) { None } else { ext }
|
||||
}
|
||||
|
||||
/// Checks whether a name is a valid blob name.
|
||||
|
||||
+17
-14
@@ -580,20 +580,23 @@ impl SendImageCheckMediaquality<'_> {
|
||||
}
|
||||
|
||||
fn assert_extension(context: &TestContext, msg: Message, extension: &str) {
|
||||
assert!(msg
|
||||
.param
|
||||
.get(Param::File)
|
||||
.unwrap()
|
||||
.ends_with(&format!(".{extension}")));
|
||||
assert!(msg
|
||||
.param
|
||||
.get(Param::Filename)
|
||||
.unwrap()
|
||||
.ends_with(&format!(".{extension}")));
|
||||
assert!(msg
|
||||
.get_filename()
|
||||
.unwrap()
|
||||
.ends_with(&format!(".{extension}")));
|
||||
assert!(
|
||||
msg.param
|
||||
.get(Param::File)
|
||||
.unwrap()
|
||||
.ends_with(&format!(".{extension}"))
|
||||
);
|
||||
assert!(
|
||||
msg.param
|
||||
.get(Param::Filename)
|
||||
.unwrap()
|
||||
.ends_with(&format!(".{extension}"))
|
||||
);
|
||||
assert!(
|
||||
msg.get_filename()
|
||||
.unwrap()
|
||||
.ends_with(&format!(".{extension}"))
|
||||
);
|
||||
assert_eq!(
|
||||
msg.get_file(context)
|
||||
.unwrap()
|
||||
|
||||
+15
-12
@@ -9,8 +9,8 @@ use std::path::{Path, PathBuf};
|
||||
use std::str::FromStr;
|
||||
use std::time::Duration;
|
||||
|
||||
use anyhow::{anyhow, bail, ensure, Context as _, Result};
|
||||
use deltachat_contact_tools::{sanitize_bidi_characters, sanitize_single_line, ContactAddress};
|
||||
use anyhow::{Context as _, Result, anyhow, bail, ensure};
|
||||
use deltachat_contact_tools::{ContactAddress, sanitize_bidi_characters, sanitize_single_line};
|
||||
use deltachat_derive::{FromSql, ToSql};
|
||||
use mail_builder::mime::MimePart;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -28,10 +28,10 @@ use crate::contact::{self, Contact, ContactId, Origin};
|
||||
use crate::context::Context;
|
||||
use crate::debug_logging::maybe_set_logging_xdc;
|
||||
use crate::download::DownloadState;
|
||||
use crate::ephemeral::{start_chat_ephemeral_timers, Timer as EphemeralTimer};
|
||||
use crate::ephemeral::{Timer as EphemeralTimer, start_chat_ephemeral_timers};
|
||||
use crate::events::EventType;
|
||||
use crate::location;
|
||||
use crate::log::{error, info, warn, LogExt};
|
||||
use crate::log::{LogExt, error, info, warn};
|
||||
use crate::message::{self, Message, MessageState, MsgId, Viewtype};
|
||||
use crate::mimefactory::MimeFactory;
|
||||
use crate::mimeparser::SystemMessage;
|
||||
@@ -41,9 +41,9 @@ use crate::smtp::send_msg_to_smtp;
|
||||
use crate::stock_str;
|
||||
use crate::sync::{self, Sync::*, SyncData};
|
||||
use crate::tools::{
|
||||
buf_compress, create_id, create_outgoing_rfc724_mid, create_smeared_timestamp,
|
||||
create_smeared_timestamps, get_abs_path, gm2local_offset, smeared_time, time,
|
||||
truncate_msg_text, IsNoneOrEmpty, SystemTime,
|
||||
IsNoneOrEmpty, SystemTime, buf_compress, create_id, create_outgoing_rfc724_mid,
|
||||
create_smeared_timestamp, create_smeared_timestamps, get_abs_path, gm2local_offset,
|
||||
smeared_time, time, truncate_msg_text,
|
||||
};
|
||||
use crate::webxdc::StatusUpdateSerial;
|
||||
use crate::{chatlist_events, imap};
|
||||
@@ -4085,7 +4085,10 @@ pub async fn remove_contact_from_chat(
|
||||
res?;
|
||||
set_group_explicitly_left(context, &chat.grpid).await?;
|
||||
} else if let Err(e) = res {
|
||||
warn!(context, "remove_contact_from_chat({chat_id}, {contact_id}): send_msg() failed: {e:#}.");
|
||||
warn!(
|
||||
context,
|
||||
"remove_contact_from_chat({chat_id}, {contact_id}): send_msg() failed: {e:#}."
|
||||
);
|
||||
}
|
||||
} else {
|
||||
sync = Sync;
|
||||
@@ -4918,10 +4921,10 @@ impl Context {
|
||||
Contact::add_or_lookup(self, "", &addr, Origin::Hidden).await?;
|
||||
match action {
|
||||
SyncAction::Block => {
|
||||
return contact::set_blocked(self, Nosync, contact_id, true).await
|
||||
return contact::set_blocked(self, Nosync, contact_id, true).await;
|
||||
}
|
||||
SyncAction::Unblock => {
|
||||
return contact::set_blocked(self, Nosync, contact_id, false).await
|
||||
return contact::set_blocked(self, Nosync, contact_id, false).await;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
@@ -4944,10 +4947,10 @@ impl Context {
|
||||
return Ok(());
|
||||
}
|
||||
SyncAction::Block => {
|
||||
return contact::set_blocked(self, Nosync, contact_id, true).await
|
||||
return contact::set_blocked(self, Nosync, contact_id, true).await;
|
||||
}
|
||||
SyncAction::Unblock => {
|
||||
return contact::set_blocked(self, Nosync, contact_id, false).await
|
||||
return contact::set_blocked(self, Nosync, contact_id, false).await;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
+97
-63
@@ -3,10 +3,10 @@ use crate::chatlist::get_archived_cnt;
|
||||
use crate::constants::{DC_GCL_ARCHIVED_ONLY, DC_GCL_NO_SPECIALS};
|
||||
use crate::ephemeral::Timer;
|
||||
use crate::headerdef::HeaderDef;
|
||||
use crate::imex::{has_backup, imex, ImexMode};
|
||||
use crate::message::{delete_msgs, MessengerMessage};
|
||||
use crate::imex::{ImexMode, has_backup, imex};
|
||||
use crate::message::{MessengerMessage, delete_msgs};
|
||||
use crate::receive_imf::receive_imf;
|
||||
use crate::test_utils::{sync, TestContext, TestContextManager, TimeShiftFalsePositiveNote};
|
||||
use crate::test_utils::{TestContext, TestContextManager, TimeShiftFalsePositiveNote, sync};
|
||||
use pretty_assertions::assert_eq;
|
||||
use strum::IntoEnumIterator;
|
||||
use tokio::fs;
|
||||
@@ -961,9 +961,11 @@ async fn test_was_device_msg_ever_added() {
|
||||
add_device_msg(&t, Some("another-label"), Some(&mut msg))
|
||||
.await
|
||||
.ok();
|
||||
assert!(was_device_msg_ever_added(&t, "another-label")
|
||||
.await
|
||||
.unwrap());
|
||||
assert!(
|
||||
was_device_msg_ever_added(&t, "another-label")
|
||||
.await
|
||||
.unwrap()
|
||||
);
|
||||
|
||||
assert!(!was_device_msg_ever_added(&t, "unused-label").await.unwrap());
|
||||
|
||||
@@ -1069,10 +1071,12 @@ async fn test_archive() {
|
||||
assert_eq!(DC_GCL_NO_SPECIALS, 0x02);
|
||||
|
||||
// archive first chat
|
||||
assert!(chat_id1
|
||||
.set_visibility(&t, ChatVisibility::Archived)
|
||||
.await
|
||||
.is_ok());
|
||||
assert!(
|
||||
chat_id1
|
||||
.set_visibility(&t, ChatVisibility::Archived)
|
||||
.await
|
||||
.is_ok()
|
||||
);
|
||||
assert!(
|
||||
Chat::load_from_db(&t, chat_id1)
|
||||
.await
|
||||
@@ -1093,10 +1097,12 @@ async fn test_archive() {
|
||||
assert_eq!(chatlist_len(&t, DC_GCL_ARCHIVED_ONLY).await, 1);
|
||||
|
||||
// archive second chat
|
||||
assert!(chat_id2
|
||||
.set_visibility(&t, ChatVisibility::Archived)
|
||||
.await
|
||||
.is_ok());
|
||||
assert!(
|
||||
chat_id2
|
||||
.set_visibility(&t, ChatVisibility::Archived)
|
||||
.await
|
||||
.is_ok()
|
||||
);
|
||||
assert!(
|
||||
Chat::load_from_db(&t, chat_id1)
|
||||
.await
|
||||
@@ -1117,18 +1123,24 @@ async fn test_archive() {
|
||||
assert_eq!(chatlist_len(&t, DC_GCL_ARCHIVED_ONLY).await, 2);
|
||||
|
||||
// archive already archived first chat, unarchive second chat two times
|
||||
assert!(chat_id1
|
||||
.set_visibility(&t, ChatVisibility::Archived)
|
||||
.await
|
||||
.is_ok());
|
||||
assert!(chat_id2
|
||||
.set_visibility(&t, ChatVisibility::Normal)
|
||||
.await
|
||||
.is_ok());
|
||||
assert!(chat_id2
|
||||
.set_visibility(&t, ChatVisibility::Normal)
|
||||
.await
|
||||
.is_ok());
|
||||
assert!(
|
||||
chat_id1
|
||||
.set_visibility(&t, ChatVisibility::Archived)
|
||||
.await
|
||||
.is_ok()
|
||||
);
|
||||
assert!(
|
||||
chat_id2
|
||||
.set_visibility(&t, ChatVisibility::Normal)
|
||||
.await
|
||||
.is_ok()
|
||||
);
|
||||
assert!(
|
||||
chat_id2
|
||||
.set_visibility(&t, ChatVisibility::Normal)
|
||||
.await
|
||||
.is_ok()
|
||||
);
|
||||
assert!(
|
||||
Chat::load_from_db(&t, chat_id1)
|
||||
.await
|
||||
@@ -1368,10 +1380,12 @@ async fn test_pinned() {
|
||||
assert_eq!(chatlist, vec![chat_id3, chat_id2, chat_id1]);
|
||||
|
||||
// pin
|
||||
assert!(chat_id1
|
||||
.set_visibility(&t, ChatVisibility::Pinned)
|
||||
.await
|
||||
.is_ok());
|
||||
assert!(
|
||||
chat_id1
|
||||
.set_visibility(&t, ChatVisibility::Pinned)
|
||||
.await
|
||||
.is_ok()
|
||||
);
|
||||
assert_eq!(
|
||||
Chat::load_from_db(&t, chat_id1)
|
||||
.await
|
||||
@@ -1385,10 +1399,12 @@ async fn test_pinned() {
|
||||
assert_eq!(chatlist, vec![chat_id1, chat_id3, chat_id2]);
|
||||
|
||||
// unpin
|
||||
assert!(chat_id1
|
||||
.set_visibility(&t, ChatVisibility::Normal)
|
||||
.await
|
||||
.is_ok());
|
||||
assert!(
|
||||
chat_id1
|
||||
.set_visibility(&t, ChatVisibility::Normal)
|
||||
.await
|
||||
.is_ok()
|
||||
);
|
||||
assert_eq!(
|
||||
Chat::load_from_db(&t, chat_id1)
|
||||
.await
|
||||
@@ -1409,10 +1425,12 @@ async fn test_pinned_after_new_msgs() -> Result<()> {
|
||||
let alice_chat_id = alice.create_chat(&bob).await.id;
|
||||
let bob_chat_id = bob.create_chat(&alice).await.id;
|
||||
|
||||
assert!(alice_chat_id
|
||||
.set_visibility(&alice, ChatVisibility::Pinned)
|
||||
.await
|
||||
.is_ok());
|
||||
assert!(
|
||||
alice_chat_id
|
||||
.set_visibility(&alice, ChatVisibility::Pinned)
|
||||
.await
|
||||
.is_ok()
|
||||
);
|
||||
assert_eq!(
|
||||
Chat::load_from_db(&alice, alice_chat_id)
|
||||
.await?
|
||||
@@ -1793,10 +1811,12 @@ async fn test_contact_request_fresh_messages() -> Result<()> {
|
||||
let chats = Chatlist::try_load(&t, 0, None, None).await?;
|
||||
assert_eq!(chats.len(), 1);
|
||||
let chat_id = chats.get_chat_id(0).unwrap();
|
||||
assert!(Chat::load_from_db(&t, chat_id)
|
||||
.await
|
||||
.unwrap()
|
||||
.is_contact_request());
|
||||
assert!(
|
||||
Chat::load_from_db(&t, chat_id)
|
||||
.await
|
||||
.unwrap()
|
||||
.is_contact_request()
|
||||
);
|
||||
assert_eq!(chat_id.get_msg_cnt(&t).await?, 1);
|
||||
assert_eq!(chat_id.get_fresh_msg_cnt(&t).await?, 1);
|
||||
let msgs = get_chat_msgs(&t, chat_id).await?;
|
||||
@@ -2674,9 +2694,11 @@ async fn test_broadcast_multidev() -> Result<()> {
|
||||
let a1_broadcast_chat = Chat::load_from_db(&alices[1], a1_broadcast_id).await?;
|
||||
assert_eq!(a1_broadcast_chat.get_type(), Chattype::Broadcast);
|
||||
assert_eq!(a1_broadcast_chat.get_name(), "Broadcast list 42");
|
||||
assert!(get_chat_contacts(&alices[1], a1_broadcast_id)
|
||||
.await?
|
||||
.is_empty());
|
||||
assert!(
|
||||
get_chat_contacts(&alices[1], a1_broadcast_id)
|
||||
.await?
|
||||
.is_empty()
|
||||
);
|
||||
|
||||
add_contact_to_chat(&alices[1], a1_broadcast_id, a1b_contact_id).await?;
|
||||
set_chat_name(&alices[1], a1_broadcast_id, "Broadcast list 43").await?;
|
||||
@@ -2686,9 +2708,11 @@ async fn test_broadcast_multidev() -> Result<()> {
|
||||
let a0_broadcast_chat = Chat::load_from_db(&alices[0], a0_broadcast_id).await?;
|
||||
assert_eq!(a0_broadcast_chat.get_type(), Chattype::Broadcast);
|
||||
assert_eq!(a0_broadcast_chat.get_name(), "Broadcast list 42");
|
||||
assert!(get_chat_contacts(&alices[0], a0_broadcast_id)
|
||||
.await?
|
||||
.is_empty());
|
||||
assert!(
|
||||
get_chat_contacts(&alices[0], a0_broadcast_id)
|
||||
.await?
|
||||
.is_empty()
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -3422,9 +3446,11 @@ async fn test_sync_broadcast() -> Result<()> {
|
||||
remove_contact_from_chat(alice0, a0_broadcast_id, a0b_contact_id).await?;
|
||||
sync(alice0, alice1).await;
|
||||
assert!(get_chat_contacts(alice1, a1_broadcast_id).await?.is_empty());
|
||||
assert!(get_past_chat_contacts(alice1, a1_broadcast_id)
|
||||
.await?
|
||||
.is_empty());
|
||||
assert!(
|
||||
get_past_chat_contacts(alice1, a1_broadcast_id)
|
||||
.await?
|
||||
.is_empty()
|
||||
);
|
||||
|
||||
a0_broadcast_id.delete(alice0).await?;
|
||||
sync(alice0, alice1).await;
|
||||
@@ -4102,9 +4128,11 @@ async fn test_cannot_send_edit_request() -> Result<()> {
|
||||
|
||||
// Bob cannot edit Alice's message
|
||||
let msg = bob.recv_msg(&sent1).await;
|
||||
assert!(send_edit_request(bob, msg.id, "bar".to_string())
|
||||
.await
|
||||
.is_err());
|
||||
assert!(
|
||||
send_edit_request(bob, msg.id, "bar".to_string())
|
||||
.await
|
||||
.is_err()
|
||||
);
|
||||
|
||||
// HTML messages cannot be edited
|
||||
let mut msg = Message::new_text("plain text".to_string());
|
||||
@@ -4122,18 +4150,22 @@ async fn test_cannot_send_edit_request() -> Result<()> {
|
||||
let msg = alice.get_last_msg().await;
|
||||
assert!(msg.is_info());
|
||||
assert_eq!(msg.from_id, ContactId::SELF);
|
||||
assert!(send_edit_request(alice, msg.id, "bar".to_string())
|
||||
.await
|
||||
.is_err());
|
||||
assert!(
|
||||
send_edit_request(alice, msg.id, "bar".to_string())
|
||||
.await
|
||||
.is_err()
|
||||
);
|
||||
|
||||
// Videochat invitations cannot be edited
|
||||
alice
|
||||
.set_config(Config::WebrtcInstance, Some("https://foo.bar"))
|
||||
.await?;
|
||||
let msg_id = send_videochat_invitation(alice, chat_id).await?;
|
||||
assert!(send_edit_request(alice, msg_id, "bar".to_string())
|
||||
.await
|
||||
.is_err());
|
||||
assert!(
|
||||
send_edit_request(alice, msg_id, "bar".to_string())
|
||||
.await
|
||||
.is_err()
|
||||
);
|
||||
|
||||
// If not text was given initally, there is nothing to edit
|
||||
// (this also avoids complexity in UI element changes; focus is typos and rewordings)
|
||||
@@ -4200,9 +4232,11 @@ async fn test_send_delete_request_no_encryption() -> Result<()> {
|
||||
|
||||
// Alice sends a message, then tries to send a deletion request which fails.
|
||||
let sent1 = alice.send_text(alice_chat.id, "wtf").await;
|
||||
assert!(message::delete_msgs_ex(alice, &[sent1.sender_msg_id], true)
|
||||
.await
|
||||
.is_err());
|
||||
assert!(
|
||||
message::delete_msgs_ex(alice, &[sent1.sender_msg_id], true)
|
||||
.await
|
||||
.is_err()
|
||||
);
|
||||
sent1.load_from_db().await;
|
||||
assert_eq!(alice_chat.id.get_msg_cnt(alice).await?, 1);
|
||||
Ok(())
|
||||
|
||||
+16
-12
@@ -1,9 +1,9 @@
|
||||
//! # Chat list module.
|
||||
|
||||
use anyhow::{ensure, Context as _, Result};
|
||||
use anyhow::{Context as _, Result, ensure};
|
||||
use std::sync::LazyLock;
|
||||
|
||||
use crate::chat::{update_special_chat_names, Chat, ChatId, ChatVisibility};
|
||||
use crate::chat::{Chat, ChatId, ChatVisibility, update_special_chat_names};
|
||||
use crate::constants::{
|
||||
Blocked, Chattype, DC_CHAT_ID_ALLDONE_HINT, DC_CHAT_ID_ARCHIVED_LINK, DC_GCL_ADD_ALLDONE_HINT,
|
||||
DC_GCL_ARCHIVED_ONLY, DC_GCL_FOR_FORWARDING, DC_GCL_NO_SPECIALS,
|
||||
@@ -483,8 +483,8 @@ mod tests {
|
||||
use super::*;
|
||||
use crate::chat::save_msgs;
|
||||
use crate::chat::{
|
||||
add_contact_to_chat, create_group_chat, get_chat_contacts, remove_contact_from_chat,
|
||||
send_text_msg, ProtectionStatus,
|
||||
ProtectionStatus, add_contact_to_chat, create_group_chat, get_chat_contacts,
|
||||
remove_contact_from_chat, send_text_msg,
|
||||
};
|
||||
use crate::receive_imf::receive_imf;
|
||||
use crate::stock_str::StockMessage;
|
||||
@@ -580,19 +580,23 @@ mod tests {
|
||||
|
||||
let chats = Chatlist::try_load(&t, 0, None, None).await.unwrap();
|
||||
assert_eq!(chats.len(), 3);
|
||||
assert!(!Chat::load_from_db(&t, chats.get_chat_id(0).unwrap())
|
||||
.await
|
||||
.unwrap()
|
||||
.is_self_talk());
|
||||
assert!(
|
||||
!Chat::load_from_db(&t, chats.get_chat_id(0).unwrap())
|
||||
.await
|
||||
.unwrap()
|
||||
.is_self_talk()
|
||||
);
|
||||
|
||||
let chats = Chatlist::try_load(&t, DC_GCL_FOR_FORWARDING, None, None)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(chats.len(), 2); // device chat cannot be written and is skipped on forwarding
|
||||
assert!(Chat::load_from_db(&t, chats.get_chat_id(0).unwrap())
|
||||
.await
|
||||
.unwrap()
|
||||
.is_self_talk());
|
||||
assert!(
|
||||
Chat::load_from_db(&t, chats.get_chat_id(0).unwrap())
|
||||
.await
|
||||
.unwrap()
|
||||
.is_self_talk()
|
||||
);
|
||||
|
||||
remove_contact_from_chat(&t, chats.get_chat_id(1).unwrap(), ContactId::SELF)
|
||||
.await
|
||||
|
||||
+7
-4
@@ -4,7 +4,7 @@ use std::env;
|
||||
use std::path::Path;
|
||||
use std::str::FromStr;
|
||||
|
||||
use anyhow::{bail, ensure, Context as _, Result};
|
||||
use anyhow::{Context as _, Result, bail, ensure};
|
||||
use base64::Engine as _;
|
||||
use deltachat_contact_tools::{addr_cmp, sanitize_single_line};
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -17,10 +17,10 @@ use crate::configure::EnteredLoginParam;
|
||||
use crate::constants;
|
||||
use crate::context::Context;
|
||||
use crate::events::EventType;
|
||||
use crate::log::{info, LogExt};
|
||||
use crate::log::{LogExt, info};
|
||||
use crate::login_param::ConfiguredLoginParam;
|
||||
use crate::mimefactory::RECOMMENDED_FILE_SIZE;
|
||||
use crate::provider::{get_provider_by_id, Provider};
|
||||
use crate::provider::{Provider, get_provider_by_id};
|
||||
use crate::sync::{self, Sync::*, SyncData};
|
||||
use crate::tools::get_abs_path;
|
||||
|
||||
@@ -813,7 +813,10 @@ impl Context {
|
||||
bail!("Cannot change ConfiguredAddr");
|
||||
}
|
||||
if let Some(addr) = value {
|
||||
info!(self, "Creating a pseudo configured account which will not be able to send or receive messages. Only meant for tests!");
|
||||
info!(
|
||||
self,
|
||||
"Creating a pseudo configured account which will not be able to send or receive messages. Only meant for tests!"
|
||||
);
|
||||
ConfiguredLoginParam::from_json(&format!(
|
||||
r#"{{"addr":"{addr}","imap":[],"imap_user":"","imap_password":"","smtp":[],"smtp_user":"","smtp_password":"","certificate_checks":"Automatic","oauth2":false}}"#
|
||||
))?
|
||||
|
||||
+27
-20
@@ -1,7 +1,7 @@
|
||||
use num_traits::FromPrimitive;
|
||||
|
||||
use super::*;
|
||||
use crate::test_utils::{sync, TestContext, TestContextManager};
|
||||
use crate::test_utils::{TestContext, TestContextManager, sync};
|
||||
|
||||
#[test]
|
||||
fn test_to_string() {
|
||||
@@ -20,10 +20,11 @@ async fn test_set_config_addr() {
|
||||
let t = TestContext::new().await;
|
||||
|
||||
// Test that uppercase address get lowercased.
|
||||
assert!(t
|
||||
.set_config(Config::Addr, Some("Foobar@eXample.oRg"))
|
||||
.await
|
||||
.is_ok());
|
||||
assert!(
|
||||
t.set_config(Config::Addr, Some("Foobar@eXample.oRg"))
|
||||
.await
|
||||
.is_ok()
|
||||
);
|
||||
assert_eq!(
|
||||
t.get_config(Config::Addr).await.unwrap().unwrap(),
|
||||
"foobar@example.org"
|
||||
@@ -263,11 +264,13 @@ async fn test_sync() -> Result<()> {
|
||||
self_chat_avatar_path,
|
||||
alice0.get_blobdir().join(SAVED_MESSAGES_DEDUPLICATED_FILE)
|
||||
);
|
||||
assert!(alice1
|
||||
.get_config(Config::Selfavatar)
|
||||
.await?
|
||||
.filter(|path| path.ends_with(".png"))
|
||||
.is_some());
|
||||
assert!(
|
||||
alice1
|
||||
.get_config(Config::Selfavatar)
|
||||
.await?
|
||||
.filter(|path| path.ends_with(".png"))
|
||||
.is_some()
|
||||
);
|
||||
alice0.set_config(Config::Selfavatar, None).await?;
|
||||
sync(&alice0, &alice1).await;
|
||||
assert!(alice1.get_config(Config::Selfavatar).await?.is_none());
|
||||
@@ -321,17 +324,21 @@ async fn test_no_sync_on_self_sent_msg() -> Result<()> {
|
||||
.await?;
|
||||
let sent_msg = alice0.send_text(a0b_chat_id, "hi").await;
|
||||
alice1.recv_msg(&sent_msg).await;
|
||||
assert!(alice1
|
||||
.get_config(Config::Selfavatar)
|
||||
.await?
|
||||
.filter(|path| path.ends_with(".png"))
|
||||
.is_some());
|
||||
assert!(
|
||||
alice1
|
||||
.get_config(Config::Selfavatar)
|
||||
.await?
|
||||
.filter(|path| path.ends_with(".png"))
|
||||
.is_some()
|
||||
);
|
||||
sync(alice1, alice0).await;
|
||||
assert!(alice0
|
||||
.get_config(Config::Selfavatar)
|
||||
.await?
|
||||
.filter(|path| path.ends_with(".jpg"))
|
||||
.is_some());
|
||||
assert!(
|
||||
alice0
|
||||
.get_config(Config::Selfavatar)
|
||||
.await?
|
||||
.filter(|path| path.ends_with(".jpg"))
|
||||
.is_some()
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
+8
-6
@@ -13,21 +13,21 @@ mod auto_mozilla;
|
||||
mod auto_outlook;
|
||||
pub(crate) mod server_params;
|
||||
|
||||
use anyhow::{bail, ensure, format_err, Context as _, Result};
|
||||
use anyhow::{Context as _, Result, bail, ensure, format_err};
|
||||
use auto_mozilla::moz_autoconfigure;
|
||||
use auto_outlook::outlk_autodiscover;
|
||||
use deltachat_contact_tools::{addr_normalize, EmailAddress};
|
||||
use deltachat_contact_tools::{EmailAddress, addr_normalize};
|
||||
use futures::FutureExt;
|
||||
use futures_lite::FutureExt as _;
|
||||
use percent_encoding::utf8_percent_encode;
|
||||
use server_params::{expand_param_vector, ServerParams};
|
||||
use server_params::{ServerParams, expand_param_vector};
|
||||
use tokio::task;
|
||||
|
||||
use crate::config::{self, Config};
|
||||
use crate::constants::NON_ALPHANUMERIC_WITHOUT_DOT;
|
||||
use crate::context::Context;
|
||||
use crate::imap::Imap;
|
||||
use crate::log::{info, warn, LogExt};
|
||||
use crate::log::{LogExt, info, warn};
|
||||
pub use crate::login_param::EnteredLoginParam;
|
||||
use crate::login_param::{
|
||||
ConfiguredCertificateChecks, ConfiguredLoginParam, ConfiguredServerLoginParam,
|
||||
@@ -39,8 +39,8 @@ use crate::provider::{Protocol, Provider, Socket, UsernamePattern};
|
||||
use crate::smtp::Smtp;
|
||||
use crate::sync::Sync::*;
|
||||
use crate::tools::time;
|
||||
use crate::{EventType, stock_str};
|
||||
use crate::{chat, provider};
|
||||
use crate::{stock_str, EventType};
|
||||
use deltachat_contact_tools::addr_cmp;
|
||||
|
||||
macro_rules! progress {
|
||||
@@ -215,7 +215,9 @@ impl Context {
|
||||
/// (i.e. [EnteredLoginParam::addr]).
|
||||
#[expect(clippy::unused_async)]
|
||||
pub async fn delete_transport(&self, _addr: &str) -> Result<()> {
|
||||
bail!("Adding and removing additional transports is not supported yet. Check back in a few months!")
|
||||
bail!(
|
||||
"Adding and removing additional transports is not supported yet. Check back in a few months!"
|
||||
)
|
||||
}
|
||||
|
||||
async fn inner_configure(&self, param: &EnteredLoginParam) -> Result<()> {
|
||||
|
||||
+8
-8
@@ -6,19 +6,19 @@ use std::fmt;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::time::UNIX_EPOCH;
|
||||
|
||||
use anyhow::{bail, ensure, Context as _, Result};
|
||||
use anyhow::{Context as _, Result, bail, ensure};
|
||||
use async_channel::{self as channel, Receiver, Sender};
|
||||
use base64::Engine as _;
|
||||
pub use deltachat_contact_tools::may_be_valid_addr;
|
||||
use deltachat_contact_tools::{
|
||||
self as contact_tools, addr_normalize, sanitize_name, sanitize_name_and_addr, ContactAddress,
|
||||
VcardContact,
|
||||
self as contact_tools, ContactAddress, VcardContact, addr_normalize, sanitize_name,
|
||||
sanitize_name_and_addr,
|
||||
};
|
||||
use deltachat_derive::{FromSql, ToSql};
|
||||
use rusqlite::OptionalExtension;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::task;
|
||||
use tokio::time::{timeout, Duration};
|
||||
use tokio::time::{Duration, timeout};
|
||||
|
||||
use crate::blob::BlobObject;
|
||||
use crate::chat::{ChatId, ChatIdBlocked, ProtectionStatus};
|
||||
@@ -28,15 +28,15 @@ use crate::constants::{Blocked, Chattype, DC_GCL_ADD_SELF};
|
||||
use crate::context::Context;
|
||||
use crate::events::EventType;
|
||||
use crate::key::{
|
||||
load_self_public_key, self_fingerprint, self_fingerprint_opt, DcKey, Fingerprint,
|
||||
SignedPublicKey,
|
||||
DcKey, Fingerprint, SignedPublicKey, load_self_public_key, self_fingerprint,
|
||||
self_fingerprint_opt,
|
||||
};
|
||||
use crate::log::{info, warn, LogExt};
|
||||
use crate::log::{LogExt, info, warn};
|
||||
use crate::message::MessageState;
|
||||
use crate::mimeparser::AvatarAction;
|
||||
use crate::param::{Param, Params};
|
||||
use crate::sync::{self, Sync::*};
|
||||
use crate::tools::{duration_to_str, get_abs_path, time, SystemTime};
|
||||
use crate::tools::{SystemTime, duration_to_str, get_abs_path, time};
|
||||
use crate::{chat, chatlist_events, stock_str};
|
||||
|
||||
/// Time during which a contact is considered as seen recently.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use deltachat_contact_tools::{addr_cmp, may_be_valid_addr};
|
||||
|
||||
use super::*;
|
||||
use crate::chat::{get_chat_contacts, send_text_msg, Chat};
|
||||
use crate::chat::{Chat, get_chat_contacts, send_text_msg};
|
||||
use crate::chatlist::Chatlist;
|
||||
use crate::receive_imf::receive_imf;
|
||||
use crate::test_utils::{self, TestContext, TestContextManager, TimeShiftFalsePositiveNote};
|
||||
@@ -677,20 +677,28 @@ async fn test_name_in_address() {
|
||||
assert_eq!(contact.get_name(), "name1");
|
||||
assert_eq!(contact.get_addr(), "dave@example.org");
|
||||
|
||||
assert!(Contact::create(&t, "", "<dskjfdslk@sadklj.dk")
|
||||
.await
|
||||
.is_err());
|
||||
assert!(Contact::create(&t, "", "<dskjf>dslk@sadklj.dk>")
|
||||
.await
|
||||
.is_err());
|
||||
assert!(
|
||||
Contact::create(&t, "", "<dskjfdslk@sadklj.dk")
|
||||
.await
|
||||
.is_err()
|
||||
);
|
||||
assert!(
|
||||
Contact::create(&t, "", "<dskjf>dslk@sadklj.dk>")
|
||||
.await
|
||||
.is_err()
|
||||
);
|
||||
assert!(Contact::create(&t, "", "dskjfdslksadklj.dk").await.is_err());
|
||||
assert!(Contact::create(&t, "", "dskjfdslk@sadklj.dk>")
|
||||
.await
|
||||
.is_err());
|
||||
assert!(
|
||||
Contact::create(&t, "", "dskjfdslk@sadklj.dk>")
|
||||
.await
|
||||
.is_err()
|
||||
);
|
||||
assert!(Contact::create(&t, "", "dskjf dslk@d.e").await.is_err());
|
||||
assert!(Contact::create(&t, "", "<dskjf dslk@sadklj.dk")
|
||||
.await
|
||||
.is_err());
|
||||
assert!(
|
||||
Contact::create(&t, "", "<dskjf dslk@sadklj.dk")
|
||||
.await
|
||||
.is_err()
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
|
||||
+4
-4
@@ -8,19 +8,19 @@ use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::{Arc, OnceLock};
|
||||
use std::time::Duration;
|
||||
|
||||
use anyhow::{bail, ensure, Context as _, Result};
|
||||
use anyhow::{Context as _, Result, bail, ensure};
|
||||
use async_channel::{self as channel, Receiver, Sender};
|
||||
use pgp::types::PublicKeyTrait;
|
||||
use ratelimit::Ratelimit;
|
||||
use tokio::sync::{Mutex, Notify, RwLock};
|
||||
|
||||
use crate::chat::{get_chat_cnt, ChatId, ProtectionStatus};
|
||||
use crate::chat::{ChatId, ProtectionStatus, get_chat_cnt};
|
||||
use crate::chatlist_events;
|
||||
use crate::config::Config;
|
||||
use crate::constants::{
|
||||
self, DC_BACKGROUND_FETCH_QUOTA_CHECK_RATELIMIT, DC_CHAT_ID_TRASH, DC_VERSION_STR,
|
||||
};
|
||||
use crate::contact::{import_vcard, mark_contact_id_as_verified, Contact, ContactId};
|
||||
use crate::contact::{Contact, ContactId, import_vcard, mark_contact_id_as_verified};
|
||||
use crate::debug_logging::DebugLogging;
|
||||
use crate::download::DownloadState;
|
||||
use crate::events::{Event, EventEmitter, EventType, Events};
|
||||
@@ -33,7 +33,7 @@ use crate::param::{Param, Params};
|
||||
use crate::peer_channels::Iroh;
|
||||
use crate::push::PushSubscriber;
|
||||
use crate::quota::QuotaInfo;
|
||||
use crate::scheduler::{convert_folder_meaning, SchedulerState};
|
||||
use crate::scheduler::{SchedulerState, convert_folder_meaning};
|
||||
use crate::sql::Sql;
|
||||
use crate::stock_str::StockStrings;
|
||||
use crate::timesmearing::SmearedTimestamp;
|
||||
|
||||
@@ -3,13 +3,13 @@ use strum::IntoEnumIterator;
|
||||
use tempfile::tempdir;
|
||||
|
||||
use super::*;
|
||||
use crate::chat::{get_chat_contacts, get_chat_msgs, send_msg, set_muted, Chat, MuteDuration};
|
||||
use crate::chat::{Chat, MuteDuration, get_chat_contacts, get_chat_msgs, send_msg, set_muted};
|
||||
use crate::chatlist::Chatlist;
|
||||
use crate::constants::Chattype;
|
||||
use crate::mimeparser::SystemMessage;
|
||||
use crate::receive_imf::receive_imf;
|
||||
use crate::test_utils::{get_chat_msg, TestContext};
|
||||
use crate::tools::{create_outgoing_rfc724_mid, SystemTime};
|
||||
use crate::test_utils::{TestContext, get_chat_msg};
|
||||
use crate::tools::{SystemTime, create_outgoing_rfc724_mid};
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn test_wrong_db() -> Result<()> {
|
||||
|
||||
+7
-5
@@ -6,11 +6,11 @@ use std::io::BufRead;
|
||||
use std::sync::LazyLock;
|
||||
|
||||
use quick_xml::{
|
||||
events::{BytesEnd, BytesStart, BytesText},
|
||||
Reader,
|
||||
events::{BytesEnd, BytesStart, BytesText},
|
||||
};
|
||||
|
||||
use crate::simplify::{simplify_quote, SimplifiedText};
|
||||
use crate::simplify::{SimplifiedText, simplify_quote};
|
||||
|
||||
struct Dehtml {
|
||||
strbuilder: String,
|
||||
@@ -481,8 +481,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_dehtml_html_encoded() {
|
||||
let html =
|
||||
"<>"'& äÄöÖüÜß fooÆçÇ ♦‎‏‌&noent;‍";
|
||||
let html = "<>"'& äÄöÖüÜß fooÆçÇ ♦‎‏‌&noent;‍";
|
||||
|
||||
let plain = dehtml(html).unwrap().text;
|
||||
|
||||
@@ -540,6 +539,9 @@ mod tests {
|
||||
fn test_spaces() {
|
||||
let input = include_str!("../test-data/spaces.html");
|
||||
let txt = dehtml(input).unwrap();
|
||||
assert_eq!(txt.text, "Welcome back to Strolling!\n\nHey there,\n\nWelcome back! Use this link to securely sign in to your Strolling account:\n\nSign in to Strolling\n\nFor your security, the link will expire in 24 hours time.\n\nSee you soon!\n\nYou can also copy & paste this URL into your browser:\n\nhttps://strolling.rosano.ca/members/?token=XXX&action=signin&r=https%3A%2F%2Fstrolling.rosano.ca%2F\n\nIf you did not make this request, you can safely ignore this email.\n\nThis message was sent from [strolling.rosano.ca](https://strolling.rosano.ca/) to [alice@example.org](mailto:alice@example.org)");
|
||||
assert_eq!(
|
||||
txt.text,
|
||||
"Welcome back to Strolling!\n\nHey there,\n\nWelcome back! Use this link to securely sign in to your Strolling account:\n\nSign in to Strolling\n\nFor your security, the link will expire in 24 hours time.\n\nSee you soon!\n\nYou can also copy & paste this URL into your browser:\n\nhttps://strolling.rosano.ca/members/?token=XXX&action=signin&r=https%3A%2F%2Fstrolling.rosano.ca%2F\n\nIf you did not make this request, you can safely ignore this email.\n\nThis message was sent from [strolling.rosano.ca](https://strolling.rosano.ca/) to [alice@example.org](mailto:alice@example.org)"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+18
-14
@@ -3,7 +3,7 @@
|
||||
use std::cmp::max;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use anyhow::{anyhow, bail, ensure, Result};
|
||||
use anyhow::{Result, anyhow, bail, ensure};
|
||||
use deltachat_derive::{FromSql, ToSql};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
@@ -14,7 +14,7 @@ use crate::log::info;
|
||||
use crate::message::{Message, MsgId, Viewtype};
|
||||
use crate::mimeparser::{MimeMessage, Part};
|
||||
use crate::tools::time;
|
||||
use crate::{chatlist_events, stock_str, EventType};
|
||||
use crate::{EventType, chatlist_events, stock_str};
|
||||
|
||||
/// Download limits should not be used below `MIN_DOWNLOAD_LIMIT`.
|
||||
///
|
||||
@@ -83,7 +83,7 @@ impl MsgId {
|
||||
let msg = Message::load_from_db(context, self).await?;
|
||||
match msg.download_state() {
|
||||
DownloadState::Done | DownloadState::Undecipherable => {
|
||||
return Err(anyhow!("Nothing to download."))
|
||||
return Err(anyhow!("Nothing to download."));
|
||||
}
|
||||
DownloadState::InProgress => return Err(anyhow!("Download already in progress.")),
|
||||
DownloadState::Available | DownloadState::Failure => {
|
||||
@@ -353,8 +353,7 @@ mod tests {
|
||||
async fn test_partial_receive_imf() -> Result<()> {
|
||||
let t = TestContext::new_alice().await;
|
||||
|
||||
let header =
|
||||
"Received: (Postfix, from userid 1000); Mon, 4 Dec 2006 14:51:39 +0100 (CET)\n\
|
||||
let header = "Received: (Postfix, from userid 1000); Mon, 4 Dec 2006 14:51:39 +0100 (CET)\n\
|
||||
From: bob@example.com\n\
|
||||
To: alice@example.org\n\
|
||||
Subject: foo\n\
|
||||
@@ -374,9 +373,10 @@ mod tests {
|
||||
let msg = t.get_last_msg().await;
|
||||
assert_eq!(msg.download_state(), DownloadState::Available);
|
||||
assert_eq!(msg.get_subject(), "foo");
|
||||
assert!(msg
|
||||
.get_text()
|
||||
.contains(&stock_str::partial_download_msg_body(&t, 100000).await));
|
||||
assert!(
|
||||
msg.get_text()
|
||||
.contains(&stock_str::partial_download_msg_body(&t, 100000).await)
|
||||
);
|
||||
|
||||
receive_imf_from_inbox(
|
||||
&t,
|
||||
@@ -472,9 +472,11 @@ mod tests {
|
||||
)
|
||||
.await?;
|
||||
assert_eq!(get_chat_msgs(&bob, chat_id).await?.len(), 0);
|
||||
assert!(Message::load_from_db_optional(&bob, msg.id)
|
||||
.await?
|
||||
.is_none());
|
||||
assert!(
|
||||
Message::load_from_db_optional(&bob, msg.id)
|
||||
.await?
|
||||
.is_none()
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -522,9 +524,11 @@ mod tests {
|
||||
// (usually mdn are too small for not being downloaded directly)
|
||||
receive_imf_from_inbox(&bob, "bar@example.org", raw, false, None).await?;
|
||||
assert_eq!(get_chat_msgs(&bob, chat_id).await?.len(), 0);
|
||||
assert!(Message::load_from_db_optional(&bob, msg.id)
|
||||
.await?
|
||||
.is_none());
|
||||
assert!(
|
||||
Message::load_from_db_optional(&bob, msg.id)
|
||||
.await?
|
||||
.is_none()
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ use num_traits::FromPrimitive;
|
||||
use crate::aheader::{Aheader, EncryptPreference};
|
||||
use crate::config::Config;
|
||||
use crate::context::Context;
|
||||
use crate::key::{load_self_public_key, load_self_secret_key, SignedPublicKey};
|
||||
use crate::key::{SignedPublicKey, load_self_public_key, load_self_secret_key};
|
||||
use crate::pgp;
|
||||
|
||||
#[derive(Debug)]
|
||||
|
||||
+4
-4
@@ -69,23 +69,23 @@ use std::num::ParseIntError;
|
||||
use std::str::FromStr;
|
||||
use std::time::{Duration, UNIX_EPOCH};
|
||||
|
||||
use anyhow::{ensure, Context as _, Result};
|
||||
use anyhow::{Context as _, Result, ensure};
|
||||
use async_channel::Receiver;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::time::timeout;
|
||||
|
||||
use crate::chat::{send_msg, ChatId, ChatIdBlocked};
|
||||
use crate::chat::{ChatId, ChatIdBlocked, send_msg};
|
||||
use crate::constants::{DC_CHAT_ID_LAST_SPECIAL, DC_CHAT_ID_TRASH};
|
||||
use crate::contact::ContactId;
|
||||
use crate::context::Context;
|
||||
use crate::download::MIN_DELETE_SERVER_AFTER;
|
||||
use crate::events::EventType;
|
||||
use crate::location;
|
||||
use crate::log::{error, info, warn, LogExt};
|
||||
use crate::log::{LogExt, error, info, warn};
|
||||
use crate::message::{Message, MessageState, MsgId, Viewtype};
|
||||
use crate::mimeparser::SystemMessage;
|
||||
use crate::stock_str;
|
||||
use crate::tools::{duration_to_str, time, SystemTime};
|
||||
use crate::tools::{SystemTime, duration_to_str, time};
|
||||
|
||||
/// Ephemeral timer value.
|
||||
#[derive(Debug, PartialEq, Eq, Copy, Clone, Serialize, Deserialize)]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use super::*;
|
||||
use crate::chat::{
|
||||
add_contact_to_chat, marknoticed_chat, remove_contact_from_chat, set_muted, ChatVisibility,
|
||||
MuteDuration,
|
||||
ChatVisibility, MuteDuration, add_contact_to_chat, marknoticed_chat, remove_contact_from_chat,
|
||||
set_muted,
|
||||
};
|
||||
use crate::config::Config;
|
||||
use crate::constants::DC_CHAT_ID_ARCHIVED_LINK;
|
||||
@@ -12,7 +12,7 @@ use crate::receive_imf::receive_imf;
|
||||
use crate::test_utils::{TestContext, TestContextManager};
|
||||
use crate::timesmearing::MAX_SECONDS_TO_LEND_FROM_FUTURE;
|
||||
use crate::{
|
||||
chat::{self, create_group_chat, send_text_msg, Chat, ChatItem, ProtectionStatus},
|
||||
chat::{self, Chat, ChatItem, ProtectionStatus, create_group_chat, send_text_msg},
|
||||
tools::IsNoneOrEmpty,
|
||||
};
|
||||
|
||||
@@ -649,9 +649,11 @@ async fn test_ephemeral_msg_offline() -> Result<()> {
|
||||
.set_ephemeral_timer(&alice, Timer::Enabled { duration })
|
||||
.await?;
|
||||
let mut msg = Message::new_text("hi".to_string());
|
||||
assert!(chat::send_msg_sync(&alice, chat.id, &mut msg)
|
||||
.await
|
||||
.is_err());
|
||||
assert!(
|
||||
chat::send_msg_sync(&alice, chat.id, &mut msg)
|
||||
.await
|
||||
.is_err()
|
||||
);
|
||||
let stmt = "SELECT COUNT(*) FROM smtp WHERE msg_id=?";
|
||||
assert!(alice.sql.exists(stmt, (msg.id,)).await?);
|
||||
let now = time();
|
||||
@@ -729,9 +731,11 @@ async fn test_noticed_ephemeral_timer() -> Result<()> {
|
||||
|
||||
delete_expired_messages(bob, time()).await?;
|
||||
|
||||
assert!(Message::load_from_db_optional(bob, bob_received_message.id)
|
||||
.await?
|
||||
.is_none());
|
||||
assert!(
|
||||
Message::load_from_db_optional(bob, bob_received_message.id)
|
||||
.await?
|
||||
.is_none()
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -757,9 +761,11 @@ async fn test_archived_ephemeral_timer() -> Result<()> {
|
||||
|
||||
delete_expired_messages(bob, time()).await?;
|
||||
|
||||
assert!(Message::load_from_db_optional(bob, bob_received_message.id)
|
||||
.await?
|
||||
.is_none());
|
||||
assert!(
|
||||
Message::load_from_db_optional(bob, bob_received_message.id)
|
||||
.await?
|
||||
.is_none()
|
||||
);
|
||||
|
||||
// Bob mutes the chat so it is not unarchived.
|
||||
set_muted(bob, bob_received_message.chat_id, MuteDuration::Forever).await?;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::{chat::ChatId, contact::ContactId, context::Context, EventType};
|
||||
use crate::{EventType, chat::ChatId, contact::ContactId, context::Context};
|
||||
|
||||
/// order or content of chatlist changes (chat ids, not the actual chatlist item)
|
||||
pub(crate) fn emit_chatlist_changed(context: &Context) {
|
||||
@@ -64,9 +64,10 @@ mod test_chatlist_events {
|
||||
};
|
||||
|
||||
use crate::{
|
||||
EventType,
|
||||
chat::{
|
||||
self, create_broadcast_list, create_group_chat, set_muted, ChatId, ChatVisibility,
|
||||
MuteDuration, ProtectionStatus,
|
||||
self, ChatId, ChatVisibility, MuteDuration, ProtectionStatus, create_broadcast_list,
|
||||
create_group_chat, set_muted,
|
||||
},
|
||||
config::Config,
|
||||
constants::*,
|
||||
@@ -76,7 +77,6 @@ mod test_chatlist_events {
|
||||
receive_imf::receive_imf,
|
||||
securejoin::{get_securejoin_qr, join_securejoin},
|
||||
test_utils::{TestContext, TestContextManager},
|
||||
EventType,
|
||||
};
|
||||
|
||||
use crate::tools::SystemTime;
|
||||
|
||||
+15
-16
@@ -13,7 +13,7 @@ use std::{
|
||||
time::{Duration, UNIX_EPOCH},
|
||||
};
|
||||
|
||||
use anyhow::{bail, ensure, format_err, Context as _, Result};
|
||||
use anyhow::{Context as _, Result, bail, ensure, format_err};
|
||||
use async_channel::Receiver;
|
||||
use async_imap::types::{Fetch, Flag, Name, NameAttribute, UnsolicitedResponse};
|
||||
use deltachat_contact_tools::ContactAddress;
|
||||
@@ -32,9 +32,9 @@ use crate::contact::{Contact, ContactId, Modifier, Origin};
|
||||
use crate::context::Context;
|
||||
use crate::events::EventType;
|
||||
use crate::headerdef::{HeaderDef, HeaderDefMap};
|
||||
use crate::log::{error, info, warn, LogExt};
|
||||
use crate::log::{LogExt, error, info, warn};
|
||||
use crate::login_param::{
|
||||
prioritize_server_login_params, ConfiguredLoginParam, ConfiguredServerLoginParam,
|
||||
ConfiguredLoginParam, ConfiguredServerLoginParam, prioritize_server_login_params,
|
||||
};
|
||||
use crate::message::{self, Message, MessageState, MessengerMessage, MsgId};
|
||||
use crate::mimeparser;
|
||||
@@ -43,7 +43,7 @@ use crate::net::session::SessionStream;
|
||||
use crate::oauth2::get_oauth2_access_token;
|
||||
use crate::push::encrypt_device_token;
|
||||
use crate::receive_imf::{
|
||||
from_field_to_contact_id, get_prefetch_parent_message, receive_imf_inner, ReceivedMsg,
|
||||
ReceivedMsg, from_field_to_contact_id, get_prefetch_parent_message, receive_imf_inner,
|
||||
};
|
||||
use crate::scheduler::connectivity::ConnectivityStore;
|
||||
use crate::stock_str;
|
||||
@@ -56,7 +56,7 @@ pub mod scan_folders;
|
||||
pub mod select_folder;
|
||||
pub(crate) mod session;
|
||||
|
||||
use client::{determine_capabilities, Client};
|
||||
use client::{Client, determine_capabilities};
|
||||
use mailparse::SingleInfo;
|
||||
use session::Session;
|
||||
|
||||
@@ -1123,7 +1123,8 @@ impl Session {
|
||||
Err(err) => {
|
||||
warn!(
|
||||
context,
|
||||
"store_seen_flags_on_imap: Failed to select {folder}, will retry later: {err:#}.");
|
||||
"store_seen_flags_on_imap: Failed to select {folder}, will retry later: {err:#}."
|
||||
);
|
||||
continue;
|
||||
}
|
||||
Ok(folder_exists) => folder_exists,
|
||||
@@ -1133,7 +1134,8 @@ impl Session {
|
||||
} else if let Err(err) = self.add_flag_finalized_with_set(&uid_set, "\\Seen").await {
|
||||
warn!(
|
||||
context,
|
||||
"Cannot mark messages {uid_set} in {folder} as seen, will retry later: {err:#}.");
|
||||
"Cannot mark messages {uid_set} in {folder} as seen, will retry later: {err:#}."
|
||||
);
|
||||
continue;
|
||||
} else {
|
||||
info!(
|
||||
@@ -1349,13 +1351,10 @@ impl Session {
|
||||
|
||||
// Try to find a requested UID in returned FETCH responses.
|
||||
while fetch_response.is_none() {
|
||||
let next_fetch_response =
|
||||
if let Some(next_fetch_response) = fetch_responses.next().await {
|
||||
next_fetch_response
|
||||
} else {
|
||||
// No more FETCH responses received from the server.
|
||||
break;
|
||||
};
|
||||
let Some(next_fetch_response) = fetch_responses.next().await else {
|
||||
// No more FETCH responses received from the server.
|
||||
break;
|
||||
};
|
||||
|
||||
let next_fetch_response =
|
||||
next_fetch_response.context("Failed to process IMAP FETCH result")?;
|
||||
@@ -1806,9 +1805,9 @@ impl Session {
|
||||
/// In this case we may want to skip next IDLE and do a round
|
||||
/// of fetching new messages and synchronizing seen flags.
|
||||
fn drain_unsolicited_responses(&self, context: &Context) -> Result<bool> {
|
||||
use UnsolicitedResponse::*;
|
||||
use async_imap::imap_proto::Response;
|
||||
use async_imap::imap_proto::ResponseCode;
|
||||
use UnsolicitedResponse::*;
|
||||
|
||||
let folder = self.selected_folder.as_deref().unwrap_or_default();
|
||||
let mut should_refetch = false;
|
||||
@@ -2142,7 +2141,7 @@ fn get_folder_meaning_by_attrs(folder_attrs: &[NameAttribute]) -> FolderMeaning
|
||||
NameAttribute::Junk => return FolderMeaning::Spam,
|
||||
NameAttribute::Drafts => return FolderMeaning::Drafts,
|
||||
NameAttribute::All | NameAttribute::Flagged => return FolderMeaning::Virtual,
|
||||
NameAttribute::Extension(ref label) => {
|
||||
NameAttribute::Extension(label) => {
|
||||
match label.as_ref() {
|
||||
"\\Spam" => return FolderMeaning::Spam,
|
||||
"\\Important" => return FolderMeaning::Virtual,
|
||||
|
||||
+1
-1
@@ -5,8 +5,8 @@ use async_channel::Receiver;
|
||||
use async_imap::extensions::idle::IdleResponse;
|
||||
use tokio::time::timeout;
|
||||
|
||||
use super::session::Session;
|
||||
use super::Imap;
|
||||
use super::session::Session;
|
||||
use crate::context::Context;
|
||||
use crate::log::{info, warn};
|
||||
use crate::net::TIMEOUT;
|
||||
|
||||
@@ -111,7 +111,9 @@ async fn check_target_folder_combination(
|
||||
outgoing: bool,
|
||||
setupmessage: bool,
|
||||
) -> Result<()> {
|
||||
println!("Testing: For folder {folder}, mvbox_move {mvbox_move}, chat_msg {chat_msg}, accepted {accepted_chat}, outgoing {outgoing}, setupmessage {setupmessage}");
|
||||
println!(
|
||||
"Testing: For folder {folder}, mvbox_move {mvbox_move}, chat_msg {chat_msg}, accepted {accepted_chat}, outgoing {outgoing}, setupmessage {setupmessage}"
|
||||
);
|
||||
|
||||
let t = TestContext::new_alice().await;
|
||||
t.ctx
|
||||
@@ -166,7 +168,11 @@ async fn check_target_folder_combination(
|
||||
} else {
|
||||
Some(expected_destination)
|
||||
};
|
||||
assert_eq!(expected, actual.as_deref(), "For folder {folder}, mvbox_move {mvbox_move}, chat_msg {chat_msg}, accepted {accepted_chat}, outgoing {outgoing}, setupmessage {setupmessage}: expected {expected:?}, got {actual:?}");
|
||||
assert_eq!(
|
||||
expected,
|
||||
actual.as_deref(),
|
||||
"For folder {folder}, mvbox_move {mvbox_move}, chat_msg {chat_msg}, accepted {accepted_chat}, outgoing {outgoing}, setupmessage {setupmessage}: expected {expected:?}, got {actual:?}"
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@ use anyhow::{Context as _, Result};
|
||||
|
||||
use super::{get_folder_meaning_by_attrs, get_folder_meaning_by_name};
|
||||
use crate::config::Config;
|
||||
use crate::imap::{session::Session, Imap};
|
||||
use crate::log::{info, LogExt};
|
||||
use crate::imap::{Imap, session::Session};
|
||||
use crate::log::{LogExt, info};
|
||||
use crate::tools::{self, time_elapsed};
|
||||
use crate::{context::Context, imap::FolderMeaning};
|
||||
|
||||
|
||||
@@ -11,7 +11,9 @@ type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum Error {
|
||||
#[error("Got a NO response when trying to select {0}, usually this means that it doesn't exist: {1}")]
|
||||
#[error(
|
||||
"Got a NO response when trying to select {0}, usually this means that it doesn't exist: {1}"
|
||||
)]
|
||||
NoFolder(String, String),
|
||||
|
||||
#[error("IMAP other error: {0}")]
|
||||
@@ -139,7 +141,7 @@ impl ImapSession {
|
||||
Error::NoFolder(..) => return Ok(false),
|
||||
_ => {
|
||||
return Err(err)
|
||||
.with_context(|| format!("Failed to select folder {folder:?}"))?
|
||||
.with_context(|| format!("Failed to select folder {folder:?}"))?;
|
||||
}
|
||||
},
|
||||
}
|
||||
@@ -210,7 +212,10 @@ impl ImapSession {
|
||||
// If UIDNEXT changed, there are new emails.
|
||||
self.new_mail |= new_uid_next != old_uid_next;
|
||||
} else {
|
||||
warn!(context, "Folder {folder} was just selected but we failed to determine UIDNEXT, assume that it has new mail.");
|
||||
warn!(
|
||||
context,
|
||||
"Folder {folder} was just selected but we failed to determine UIDNEXT, assume that it has new mail."
|
||||
);
|
||||
self.new_mail = true;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -2,8 +2,8 @@ use std::collections::BTreeMap;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
use anyhow::{Context as _, Result};
|
||||
use async_imap::types::Mailbox;
|
||||
use async_imap::Session as ImapSession;
|
||||
use async_imap::types::Mailbox;
|
||||
use futures::TryStreamExt;
|
||||
|
||||
use crate::imap::capabilities::Capabilities;
|
||||
|
||||
+15
-13
@@ -4,7 +4,7 @@ use std::ffi::OsStr;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::pin::Pin;
|
||||
|
||||
use anyhow::{bail, ensure, format_err, Context as _, Result};
|
||||
use anyhow::{Context as _, Result, bail, ensure, format_err};
|
||||
use futures::TryStreamExt;
|
||||
use futures_lite::FutureExt;
|
||||
use pin_project::pin_project;
|
||||
@@ -20,12 +20,12 @@ use crate::context::Context;
|
||||
use crate::e2ee;
|
||||
use crate::events::EventType;
|
||||
use crate::key::{self, DcKey, DcSecretKey, SignedPublicKey, SignedSecretKey};
|
||||
use crate::log::{error, info, warn, LogExt};
|
||||
use crate::log::{LogExt, error, info, warn};
|
||||
use crate::pgp;
|
||||
use crate::qr::DCBACKUP_VERSION;
|
||||
use crate::sql;
|
||||
use crate::tools::{
|
||||
create_folder, delete_file, get_filesuffix_lc, read_file, time, write_file, TempPathGuard,
|
||||
TempPathGuard, create_folder, delete_file, get_filesuffix_lc, read_file, time, write_file,
|
||||
};
|
||||
|
||||
mod key_transfer;
|
||||
@@ -33,7 +33,7 @@ mod transfer;
|
||||
|
||||
use ::pgp::types::KeyDetails;
|
||||
pub use key_transfer::{continue_key_transfer, initiate_key_transfer};
|
||||
pub use transfer::{get_backup, BackupProvider};
|
||||
pub use transfer::{BackupProvider, get_backup};
|
||||
|
||||
// Name of the database file in the backup.
|
||||
const DBFILE_BACKUP_NAME: &str = "dc_database_backup.sqlite";
|
||||
@@ -842,7 +842,7 @@ mod tests {
|
||||
|
||||
use super::*;
|
||||
use crate::config::Config;
|
||||
use crate::test_utils::{alice_keypair, TestContext};
|
||||
use crate::test_utils::{TestContext, alice_keypair};
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn test_export_public_key_to_asc_file() {
|
||||
@@ -982,14 +982,16 @@ mod tests {
|
||||
let backup = has_backup(&context2, backup_dir.path()).await?;
|
||||
|
||||
// Import of unencrypted backup with incorrect "foobar" backup passphrase fails.
|
||||
assert!(imex(
|
||||
&context2,
|
||||
ImexMode::ImportBackup,
|
||||
backup.as_ref(),
|
||||
Some("foobar".to_string())
|
||||
)
|
||||
.await
|
||||
.is_err());
|
||||
assert!(
|
||||
imex(
|
||||
&context2,
|
||||
ImexMode::ImportBackup,
|
||||
backup.as_ref(),
|
||||
Some("foobar".to_string())
|
||||
)
|
||||
.await
|
||||
.is_err()
|
||||
);
|
||||
|
||||
assert!(
|
||||
imex(&context2, ImexMode::ImportBackup, backup.as_ref(), None)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
//! # Key transfer via Autocrypt Setup Message.
|
||||
use std::io::BufReader;
|
||||
|
||||
use rand::{thread_rng, Rng};
|
||||
use rand::{Rng, thread_rng};
|
||||
|
||||
use anyhow::{bail, ensure, Result};
|
||||
use anyhow::{Result, bail, ensure};
|
||||
|
||||
use crate::blob::BlobObject;
|
||||
use crate::chat::{self, ChatId};
|
||||
@@ -12,7 +12,7 @@ use crate::constants::{ASM_BODY, ASM_SUBJECT};
|
||||
use crate::contact::ContactId;
|
||||
use crate::context::Context;
|
||||
use crate::imex::set_self_key;
|
||||
use crate::key::{load_self_secret_key, DcKey};
|
||||
use crate::key::{DcKey, load_self_secret_key};
|
||||
use crate::message::{Message, MsgId, Viewtype};
|
||||
use crate::mimeparser::SystemMessage;
|
||||
use crate::param::Param;
|
||||
@@ -141,7 +141,7 @@ fn create_setup_code(_context: &Context) -> String {
|
||||
|
||||
for i in 0..9 {
|
||||
loop {
|
||||
random_val = rng.gen();
|
||||
random_val = rng.r#gen();
|
||||
if random_val as usize <= 60000 {
|
||||
break;
|
||||
}
|
||||
@@ -184,7 +184,7 @@ fn normalize_setup_code(s: &str) -> String {
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use crate::pgp::{split_armored_data, HEADER_AUTOCRYPT, HEADER_SETUPCODE};
|
||||
use crate::pgp::{HEADER_AUTOCRYPT, HEADER_SETUPCODE, split_armored_data};
|
||||
use crate::receive_imf::receive_imf;
|
||||
use crate::test_utils::{TestContext, TestContextManager};
|
||||
use ::pgp::armor::BlockType;
|
||||
|
||||
@@ -31,7 +31,7 @@ use std::pin::Pin;
|
||||
use std::sync::Arc;
|
||||
use std::task::Poll;
|
||||
|
||||
use anyhow::{bail, format_err, Context as _, Result};
|
||||
use anyhow::{Context as _, Result, bail, format_err};
|
||||
use futures_lite::FutureExt;
|
||||
use iroh::{Endpoint, RelayMode};
|
||||
use tokio::fs;
|
||||
@@ -45,10 +45,10 @@ use crate::log::{info, warn};
|
||||
use crate::message::Message;
|
||||
use crate::qr::Qr;
|
||||
use crate::stock_str::backup_transfer_msg_body;
|
||||
use crate::tools::{create_id, time, TempPathGuard};
|
||||
use crate::{e2ee, EventType};
|
||||
use crate::tools::{TempPathGuard, create_id, time};
|
||||
use crate::{EventType, e2ee};
|
||||
|
||||
use super::{export_backup_stream, export_database, import_backup_stream, DBFILE_BACKUP_NAME};
|
||||
use super::{DBFILE_BACKUP_NAME, export_backup_stream, export_database, import_backup_stream};
|
||||
|
||||
/// ALPN protocol identifier for the backup transfer protocol.
|
||||
const BACKUP_ALPN: &[u8] = b"/deltachat/backup";
|
||||
@@ -382,7 +382,7 @@ pub async fn get_backup(context: &Context, qr: Qr) -> Result<()> {
|
||||
mod tests {
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::chat::{get_chat_msgs, send_msg, ChatItem};
|
||||
use crate::chat::{ChatItem, get_chat_msgs, send_msg};
|
||||
use crate::message::Viewtype;
|
||||
use crate::test_utils::TestContextManager;
|
||||
|
||||
|
||||
+3
-3
@@ -4,7 +4,7 @@ use std::collections::BTreeMap;
|
||||
use std::fmt;
|
||||
use std::io::Cursor;
|
||||
|
||||
use anyhow::{bail, ensure, Context as _, Result};
|
||||
use anyhow::{Context as _, Result, bail, ensure};
|
||||
use base64::Engine as _;
|
||||
use deltachat_contact_tools::EmailAddress;
|
||||
use pgp::composed::Deserializable;
|
||||
@@ -15,7 +15,7 @@ use rand::thread_rng;
|
||||
use tokio::runtime::Handle;
|
||||
|
||||
use crate::context::Context;
|
||||
use crate::log::{info, LogExt};
|
||||
use crate::log::{LogExt, info};
|
||||
use crate::pgp::KeyPair;
|
||||
use crate::tools::{self, time_elapsed};
|
||||
|
||||
@@ -526,7 +526,7 @@ mod tests {
|
||||
|
||||
use super::*;
|
||||
use crate::config::Config;
|
||||
use crate::test_utils::{alice_keypair, TestContext};
|
||||
use crate::test_utils::{TestContext, alice_keypair};
|
||||
|
||||
static KEYPAIR: LazyLock<KeyPair> = LazyLock::new(alice_keypair);
|
||||
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@
|
||||
|
||||
use std::time::Duration;
|
||||
|
||||
use anyhow::{ensure, Context as _, Result};
|
||||
use anyhow::{Context as _, Result, ensure};
|
||||
use async_channel::Receiver;
|
||||
use quick_xml::events::{BytesEnd, BytesStart, BytesText};
|
||||
use tokio::time::timeout;
|
||||
|
||||
+5
-9
@@ -2,19 +2,19 @@
|
||||
|
||||
use std::fmt;
|
||||
|
||||
use anyhow::{bail, ensure, format_err, Context as _, Result};
|
||||
use deltachat_contact_tools::{addr_cmp, addr_normalize, EmailAddress};
|
||||
use anyhow::{Context as _, Result, bail, ensure, format_err};
|
||||
use deltachat_contact_tools::{EmailAddress, addr_cmp, addr_normalize};
|
||||
use num_traits::ToPrimitive as _;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::config::Config;
|
||||
use crate::configure::server_params::{expand_param_vector, ServerParams};
|
||||
use crate::configure::server_params::{ServerParams, expand_param_vector};
|
||||
use crate::constants::{DC_LP_AUTH_FLAGS, DC_LP_AUTH_OAUTH2};
|
||||
use crate::context::Context;
|
||||
use crate::net::load_connection_timestamp;
|
||||
pub use crate::net::proxy::ProxyConfig;
|
||||
pub use crate::provider::Socket;
|
||||
use crate::provider::{get_provider_by_id, Protocol, Provider, UsernamePattern};
|
||||
use crate::provider::{Protocol, Provider, UsernamePattern, get_provider_by_id};
|
||||
use crate::sql::Sql;
|
||||
use crate::tools::ToOption;
|
||||
|
||||
@@ -330,11 +330,7 @@ impl fmt::Display for EnteredLoginParam {
|
||||
}
|
||||
|
||||
fn unset_empty(s: &str) -> &str {
|
||||
if s.is_empty() {
|
||||
"unset"
|
||||
} else {
|
||||
s
|
||||
}
|
||||
if s.is_empty() { "unset" } else { s }
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
|
||||
+6
-6
@@ -5,29 +5,29 @@ use std::collections::HashSet;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::str;
|
||||
|
||||
use anyhow::{ensure, format_err, Context as _, Result};
|
||||
use deltachat_contact_tools::{parse_vcard, VcardContact};
|
||||
use anyhow::{Context as _, Result, ensure, format_err};
|
||||
use deltachat_contact_tools::{VcardContact, parse_vcard};
|
||||
use deltachat_derive::{FromSql, ToSql};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::{fs, io};
|
||||
|
||||
use crate::blob::BlobObject;
|
||||
use crate::chat::{send_msg, Chat, ChatId, ChatIdBlocked, ChatVisibility};
|
||||
use crate::chat::{Chat, ChatId, ChatIdBlocked, ChatVisibility, send_msg};
|
||||
use crate::chatlist_events;
|
||||
use crate::config::Config;
|
||||
use crate::constants::{
|
||||
Blocked, Chattype, VideochatType, DC_CHAT_ID_TRASH, DC_MSG_ID_LAST_SPECIAL,
|
||||
Blocked, Chattype, DC_CHAT_ID_TRASH, DC_MSG_ID_LAST_SPECIAL, VideochatType,
|
||||
};
|
||||
use crate::contact::{self, Contact, ContactId};
|
||||
use crate::context::Context;
|
||||
use crate::debug_logging::set_debug_logging_xdc;
|
||||
use crate::download::DownloadState;
|
||||
use crate::ephemeral::{start_ephemeral_timers_msgids, Timer as EphemeralTimer};
|
||||
use crate::ephemeral::{Timer as EphemeralTimer, start_ephemeral_timers_msgids};
|
||||
use crate::events::EventType;
|
||||
use crate::imap::markseen_on_imap_table;
|
||||
use crate::location::delete_poi_location;
|
||||
use crate::log::{error, info, warn};
|
||||
use crate::mimeparser::{parse_message_id, SystemMessage};
|
||||
use crate::mimeparser::{SystemMessage, parse_message_id};
|
||||
use crate::param::{Param, Params};
|
||||
use crate::pgp::split_armored_data;
|
||||
use crate::reaction::get_msg_reactions;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use num_traits::FromPrimitive;
|
||||
|
||||
use super::*;
|
||||
use crate::chat::{self, forward_msgs, marknoticed_chat, save_msgs, send_text_msg, ChatItem};
|
||||
use crate::chat::{self, ChatItem, forward_msgs, marknoticed_chat, save_msgs, send_text_msg};
|
||||
use crate::chatlist::Chatlist;
|
||||
use crate::config::Config;
|
||||
use crate::reaction::send_reaction;
|
||||
@@ -734,9 +734,11 @@ async fn test_delete_msgs_offline() -> Result<()> {
|
||||
.create_chat_with_contact("Bob", "bob@example.org")
|
||||
.await;
|
||||
let mut msg = Message::new_text("hi".to_string());
|
||||
assert!(chat::send_msg_sync(&alice, chat.id, &mut msg)
|
||||
.await
|
||||
.is_err());
|
||||
assert!(
|
||||
chat::send_msg_sync(&alice, chat.id, &mut msg)
|
||||
.await
|
||||
.is_err()
|
||||
);
|
||||
let stmt = "SELECT COUNT(*) FROM smtp WHERE msg_id=?";
|
||||
assert!(alice.sql.exists(stmt, (msg.id,)).await?);
|
||||
delete_msgs(&alice, &[msg.id]).await?;
|
||||
|
||||
+11
-11
@@ -4,12 +4,12 @@ use std::collections::{BTreeSet, HashSet};
|
||||
use std::io::Cursor;
|
||||
use std::path::Path;
|
||||
|
||||
use anyhow::{bail, Context as _, Result};
|
||||
use anyhow::{Context as _, Result, bail};
|
||||
use base64::Engine as _;
|
||||
use chrono::TimeZone;
|
||||
use deltachat_contact_tools::sanitize_bidi_characters;
|
||||
use mail_builder::headers::address::{Address, EmailAddress};
|
||||
use mail_builder::headers::HeaderType;
|
||||
use mail_builder::headers::address::{Address, EmailAddress};
|
||||
use mail_builder::mime::MimePart;
|
||||
use tokio::fs;
|
||||
|
||||
@@ -28,14 +28,14 @@ use crate::key::{DcKey, SignedPublicKey};
|
||||
use crate::location;
|
||||
use crate::log::{info, warn};
|
||||
use crate::message::{self, Message, MsgId, Viewtype};
|
||||
use crate::mimeparser::{is_hidden, SystemMessage};
|
||||
use crate::mimeparser::{SystemMessage, is_hidden};
|
||||
use crate::param::Param;
|
||||
use crate::peer_channels::create_iroh_header;
|
||||
use crate::simplify::escape_message_footer_marks;
|
||||
use crate::stock_str;
|
||||
use crate::tools::{
|
||||
create_outgoing_rfc724_mid, create_smeared_timestamp, remove_subject_prefix, time,
|
||||
IsNoneOrEmpty,
|
||||
IsNoneOrEmpty, create_outgoing_rfc724_mid, create_smeared_timestamp, remove_subject_prefix,
|
||||
time,
|
||||
};
|
||||
use crate::webxdc::StatusUpdateSerial;
|
||||
|
||||
@@ -571,7 +571,7 @@ impl MimeFactory {
|
||||
return chat.param.get(Param::ProfileImage).map(Into::into);
|
||||
}
|
||||
SystemMessage::GroupImageChanged => {
|
||||
return msg.param.get(Param::Arg).map(Into::into)
|
||||
return msg.param.get(Param::Arg).map(Into::into);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@@ -592,7 +592,7 @@ impl MimeFactory {
|
||||
|
||||
async fn subject_str(&self, context: &Context) -> Result<String> {
|
||||
let subject = match &self.loaded {
|
||||
Loaded::Message { ref chat, msg } => {
|
||||
Loaded::Message { chat, msg } => {
|
||||
let quoted_msg_subject = msg.quoted_message(context).await?.map(|m| m.subject);
|
||||
|
||||
if !msg.subject.is_empty() {
|
||||
@@ -1100,9 +1100,9 @@ impl MimeFactory {
|
||||
}
|
||||
|
||||
// Set the appropriate Content-Type for the inner message.
|
||||
for (h, ref mut v) in &mut message.headers {
|
||||
for (h, v) in &mut message.headers {
|
||||
if h == "Content-Type" {
|
||||
if let mail_builder::headers::HeaderType::ContentType(ref mut ct) = v {
|
||||
if let mail_builder::headers::HeaderType::ContentType(ct) = v {
|
||||
*ct = ct.clone().attribute("protected-headers", "v1");
|
||||
}
|
||||
}
|
||||
@@ -1186,9 +1186,9 @@ impl MimeFactory {
|
||||
|
||||
message
|
||||
} else {
|
||||
for (h, ref mut v) in &mut message.headers {
|
||||
for (h, v) in &mut message.headers {
|
||||
if h == "Content-Type" {
|
||||
if let mail_builder::headers::HeaderType::ContentType(ref mut ct) = v {
|
||||
if let mail_builder::headers::HeaderType::ContentType(ct) = v {
|
||||
*ct = ct.clone().attribute("protected-headers", "v1");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
use deltachat_contact_tools::ContactAddress;
|
||||
use mail_builder::headers::Header;
|
||||
use mailparse::{addrparse_header, MailHeaderMap};
|
||||
use mailparse::{MailHeaderMap, addrparse_header};
|
||||
use std::str;
|
||||
|
||||
use super::*;
|
||||
use crate::chat::{
|
||||
self, add_contact_to_chat, create_group_chat, remove_contact_from_chat, send_text_msg, ChatId,
|
||||
ProtectionStatus,
|
||||
self, ChatId, ProtectionStatus, add_contact_to_chat, create_group_chat,
|
||||
remove_contact_from_chat, send_text_msg,
|
||||
};
|
||||
use crate::chatlist::Chatlist;
|
||||
use crate::constants;
|
||||
@@ -14,7 +14,7 @@ use crate::contact::Origin;
|
||||
use crate::headerdef::HeaderDef;
|
||||
use crate::mimeparser::MimeMessage;
|
||||
use crate::receive_imf::receive_imf;
|
||||
use crate::test_utils::{get_chat_msg, TestContext, TestContextManager};
|
||||
use crate::test_utils::{TestContext, TestContextManager, get_chat_msg};
|
||||
|
||||
fn render_email_address(display_name: &str, addr: &str) -> String {
|
||||
let mut output = Vec::<u8>::new();
|
||||
@@ -32,9 +32,11 @@ fn test_render_email_address() {
|
||||
let addr = "x@y.org";
|
||||
|
||||
assert!(!display_name.is_ascii());
|
||||
assert!(!display_name
|
||||
.chars()
|
||||
.all(|c| c.is_ascii_alphanumeric() || c == ' '));
|
||||
assert!(
|
||||
!display_name
|
||||
.chars()
|
||||
.all(|c| c.is_ascii_alphanumeric() || c == ' ')
|
||||
);
|
||||
|
||||
let s = render_email_address(display_name, addr);
|
||||
|
||||
@@ -49,9 +51,11 @@ fn test_render_email_address_noescape() {
|
||||
let addr = "x@y.org";
|
||||
|
||||
assert!(display_name.is_ascii());
|
||||
assert!(display_name
|
||||
.chars()
|
||||
.all(|c| c.is_ascii_alphanumeric() || c == ' '));
|
||||
assert!(
|
||||
display_name
|
||||
.chars()
|
||||
.all(|c| c.is_ascii_alphanumeric() || c == ' ')
|
||||
);
|
||||
|
||||
let s = render_email_address(display_name, addr);
|
||||
|
||||
@@ -676,11 +680,13 @@ async fn test_selfavatar_unencrypted_signed() {
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
let alice_contact = Contact::get_by_id(&bob.ctx, alice_id).await.unwrap();
|
||||
assert!(alice_contact
|
||||
.get_profile_image(&bob.ctx)
|
||||
.await
|
||||
.unwrap()
|
||||
.is_some());
|
||||
assert!(
|
||||
alice_contact
|
||||
.get_profile_image(&bob.ctx)
|
||||
.await
|
||||
.unwrap()
|
||||
.is_some()
|
||||
);
|
||||
|
||||
// if another message is sent, that one must not contain the avatar
|
||||
let mut msg = Message::new_text("this is the text!".to_string());
|
||||
@@ -719,11 +725,13 @@ async fn test_selfavatar_unencrypted_signed() {
|
||||
|
||||
bob.recv_msg(&sent_msg).await;
|
||||
let alice_contact = Contact::get_by_id(&bob.ctx, alice_id).await.unwrap();
|
||||
assert!(alice_contact
|
||||
.get_profile_image(&bob.ctx)
|
||||
.await
|
||||
.unwrap()
|
||||
.is_some());
|
||||
assert!(
|
||||
alice_contact
|
||||
.get_profile_image(&bob.ctx)
|
||||
.await
|
||||
.unwrap()
|
||||
.is_some()
|
||||
);
|
||||
}
|
||||
|
||||
/// Test that removed member address does not go into the `To:` field.
|
||||
@@ -757,7 +765,7 @@ async fn test_remove_member_bcc() -> Result<()> {
|
||||
let to = addrparse_header(to)?;
|
||||
for to_addr in to.iter() {
|
||||
match to_addr {
|
||||
mailparse::MailAddr::Single(ref info) => {
|
||||
mailparse::MailAddr::Single(info) => {
|
||||
// Addresses should be of existing members (Alice and Bob) and not Charlie.
|
||||
assert_ne!(info.addr, charlie_addr);
|
||||
}
|
||||
|
||||
+11
-8
@@ -6,11 +6,11 @@ use std::path::Path;
|
||||
use std::str;
|
||||
use std::str::FromStr;
|
||||
|
||||
use anyhow::{bail, Context as _, Result};
|
||||
use anyhow::{Context as _, Result, bail};
|
||||
use deltachat_contact_tools::{addr_cmp, addr_normalize, sanitize_bidi_characters};
|
||||
use deltachat_derive::{FromSql, ToSql};
|
||||
use format_flowed::unformat_flowed;
|
||||
use mailparse::{addrparse_header, DispositionType, MailHeader, MailHeaderMap, SingleInfo};
|
||||
use mailparse::{DispositionType, MailHeader, MailHeaderMap, SingleInfo, addrparse_header};
|
||||
use mime::Mime;
|
||||
|
||||
use crate::aheader::Aheader;
|
||||
@@ -25,11 +25,11 @@ use crate::decrypt::{try_decrypt, validate_detached_signature};
|
||||
use crate::dehtml::dehtml;
|
||||
use crate::events::EventType;
|
||||
use crate::headerdef::{HeaderDef, HeaderDefMap};
|
||||
use crate::key::{self, load_self_secret_keyring, DcKey, Fingerprint, SignedPublicKey};
|
||||
use crate::key::{self, DcKey, Fingerprint, SignedPublicKey, load_self_secret_keyring};
|
||||
use crate::log::{error, info, warn};
|
||||
use crate::message::{self, get_vcard_summary, set_msg_failed, Message, MsgId, Viewtype};
|
||||
use crate::message::{self, Message, MsgId, Viewtype, get_vcard_summary, set_msg_failed};
|
||||
use crate::param::{Param, Params};
|
||||
use crate::simplify::{simplify, SimplifiedText};
|
||||
use crate::simplify::{SimplifiedText, simplify};
|
||||
use crate::sync::SyncItems;
|
||||
use crate::tools::{
|
||||
get_filemeta, parse_receive_headers, smeared_time, time, truncate_msg_text, validate_id,
|
||||
@@ -1643,7 +1643,10 @@ impl MimeMessage {
|
||||
if status_part.ctype.mimetype != "message/delivery-status"
|
||||
&& status_part.ctype.mimetype != "message/global-delivery-status"
|
||||
{
|
||||
warn!(context, "Second part of Delivery Status Notification is not message/delivery-status or message/global-delivery-status, ignoring");
|
||||
warn!(
|
||||
context,
|
||||
"Second part of Delivery Status Notification is not message/delivery-status or message/global-delivery-status, ignoring"
|
||||
);
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
@@ -2222,13 +2225,13 @@ fn get_all_addresses_from_header(headers: &[MailHeader], header: &str) -> Vec<Si
|
||||
if let Ok(addrs) = mailparse::addrparse_header(header) {
|
||||
for addr in addrs.iter() {
|
||||
match addr {
|
||||
mailparse::MailAddr::Single(ref info) => {
|
||||
mailparse::MailAddr::Single(info) => {
|
||||
result.push(SingleInfo {
|
||||
addr: addr_normalize(&info.addr).to_lowercase(),
|
||||
display_name: info.display_name.clone(),
|
||||
});
|
||||
}
|
||||
mailparse::MailAddr::Group(ref infos) => {
|
||||
mailparse::MailAddr::Group(infos) => {
|
||||
for info in &infos.addrs {
|
||||
result.push(SingleInfo {
|
||||
addr: addr_normalize(&info.addr).to_lowercase(),
|
||||
|
||||
@@ -160,9 +160,11 @@ fn test_is_attachment() {
|
||||
fn load_mail_with_attachment<'a>(t: &'a TestContext, raw: &'a [u8]) -> ParsedMail<'a> {
|
||||
let mail = mailparse::parse_mail(raw).unwrap();
|
||||
assert!(get_attachment_filename(t, &mail).unwrap().is_none());
|
||||
assert!(get_attachment_filename(t, &mail.subparts[0])
|
||||
.unwrap()
|
||||
.is_none());
|
||||
assert!(
|
||||
get_attachment_filename(t, &mail.subparts[0])
|
||||
.unwrap()
|
||||
.is_none()
|
||||
);
|
||||
mail
|
||||
}
|
||||
|
||||
@@ -321,9 +323,11 @@ async fn test_mailparse_0_16_0_panic() {
|
||||
let raw = include_bytes!("../../test-data/message/mailparse-0.16.0-panic.eml");
|
||||
|
||||
// There should be an error, but no panic.
|
||||
assert!(MimeMessage::from_bytes(&context.ctx, &raw[..], None)
|
||||
.await
|
||||
.is_err());
|
||||
assert!(
|
||||
MimeMessage::from_bytes(&context.ctx, &raw[..], None)
|
||||
.await
|
||||
.is_err()
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
@@ -422,9 +426,11 @@ async fn test_mimeparser_with_context() {
|
||||
|
||||
// make sure, headers that are only allowed in the encrypted part
|
||||
// cannot be set from the outer part
|
||||
assert!(mimeparser
|
||||
.get_header(HeaderDef::SecureJoinFingerprint)
|
||||
.is_none());
|
||||
assert!(
|
||||
mimeparser
|
||||
.get_header(HeaderDef::SecureJoinFingerprint)
|
||||
.is_none()
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
@@ -485,9 +491,11 @@ async fn test_mimeparser_with_videochat() {
|
||||
.unwrap_or_default(),
|
||||
"https://example.org/p2p/?roomname=6HiduoAn4xN"
|
||||
);
|
||||
assert!(mimeparser.parts[0]
|
||||
.msg
|
||||
.contains("https://example.org/p2p/?roomname=6HiduoAn4xN"));
|
||||
assert!(
|
||||
mimeparser.parts[0]
|
||||
.msg
|
||||
.contains("https://example.org/p2p/?roomname=6HiduoAn4xN")
|
||||
);
|
||||
assert_eq!(mimeparser.user_avatar, None);
|
||||
assert_eq!(mimeparser.group_avatar, None);
|
||||
}
|
||||
@@ -1709,7 +1717,10 @@ async fn test_tlsrpt() -> Result<()> {
|
||||
assert_eq!(msg.parts.len(), 1);
|
||||
|
||||
assert_eq!(msg.parts[0].typ, Viewtype::File);
|
||||
assert_eq!(msg.parts[0].msg, "Report Domain: nine.testrun.org Submitter: google.com Report-ID: <2024.01.20T00.00.00Z+nine.testrun.org@google.com> – This is an aggregate TLS report from google.com");
|
||||
assert_eq!(
|
||||
msg.parts[0].msg,
|
||||
"Report Domain: nine.testrun.org Submitter: google.com Report-ID: <2024.01.20T00.00.00Z+nine.testrun.org@google.com> – This is an aggregate TLS report from google.com"
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
+3
-3
@@ -4,7 +4,7 @@ use std::net::SocketAddr;
|
||||
use std::pin::Pin;
|
||||
use std::time::Duration;
|
||||
|
||||
use anyhow::{format_err, Context as _, Result};
|
||||
use anyhow::{Context as _, Result, format_err};
|
||||
use tokio::net::TcpStream;
|
||||
use tokio::task::JoinSet;
|
||||
use tokio::time::timeout;
|
||||
@@ -22,7 +22,7 @@ pub(crate) mod session;
|
||||
pub(crate) mod tls;
|
||||
|
||||
use dns::lookup_host_with_cache;
|
||||
pub use http::{read_url, read_url_blob, Response as HttpResponse};
|
||||
pub use http::{Response as HttpResponse, read_url, read_url_blob};
|
||||
use tls::wrap_tls;
|
||||
|
||||
/// Connection, write and read timeout.
|
||||
@@ -128,7 +128,7 @@ pub(crate) async fn connect_tls_inner(
|
||||
host: &str,
|
||||
strict_tls: bool,
|
||||
alpn: &[&str],
|
||||
) -> Result<impl SessionStream> {
|
||||
) -> Result<impl SessionStream + 'static> {
|
||||
let tcp_stream = connect_tcp_inner(addr).await?;
|
||||
let tls_stream = wrap_tls(strict_tls, host, alpn, tcp_stream).await?;
|
||||
Ok(tls_stream)
|
||||
|
||||
+6
-4
@@ -912,10 +912,12 @@ mod tests {
|
||||
let ipv6_addr = IpAddr::V6(Ipv6Addr::new(0x2a01, 0x4f8, 0x241, 0x4ce8, 0, 0, 0, 2));
|
||||
|
||||
let now = time();
|
||||
assert!(lookup_cache(alice, "nine.testrun.org", 587, "smtp", now)
|
||||
.await
|
||||
.unwrap()
|
||||
.is_empty());
|
||||
assert!(
|
||||
lookup_cache(alice, "nine.testrun.org", 587, "smtp", now)
|
||||
.await
|
||||
.unwrap()
|
||||
.is_empty()
|
||||
);
|
||||
|
||||
update_cache(alice, "nine.testrun.org", "116.202.233.236", now)
|
||||
.await
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
//! # HTTP module.
|
||||
|
||||
use anyhow::{anyhow, bail, Context as _, Result};
|
||||
use anyhow::{Context as _, Result, anyhow, bail};
|
||||
use bytes::Bytes;
|
||||
use http_body_util::BodyExt;
|
||||
use hyper_util::rt::TokioIo;
|
||||
|
||||
+8
-5
@@ -5,14 +5,14 @@
|
||||
use std::fmt;
|
||||
use std::pin::Pin;
|
||||
|
||||
use anyhow::{bail, format_err, Context as _, Result};
|
||||
use anyhow::{Context as _, Result, bail, format_err};
|
||||
use base64::Engine;
|
||||
use bytes::{BufMut, BytesMut};
|
||||
use fast_socks5::client::Socks5Stream;
|
||||
use fast_socks5::util::target_addr::ToTargetAddr;
|
||||
use fast_socks5::AuthenticationMethod;
|
||||
use fast_socks5::Socks5Command;
|
||||
use percent_encoding::{percent_encode, utf8_percent_encode, NON_ALPHANUMERIC};
|
||||
use fast_socks5::client::Socks5Stream;
|
||||
use fast_socks5::util::target_addr::ToTargetAddr;
|
||||
use percent_encoding::{NON_ALPHANUMERIC, percent_encode, utf8_percent_encode};
|
||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||
use tokio::net::TcpStream;
|
||||
use tokio_io_timeout::TimeoutStream;
|
||||
@@ -624,7 +624,10 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_http_connect_request() {
|
||||
assert_eq!(http_connect_request("example.org", 143, Some(("aladdin", "opensesame"))), "CONNECT example.org:143 HTTP/1.1\r\nHost: example.org:143\r\nProxy-Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l\r\n\r\n");
|
||||
assert_eq!(
|
||||
http_connect_request("example.org", 143, Some(("aladdin", "opensesame"))),
|
||||
"CONNECT example.org:143 HTTP/1.1\r\nHost: example.org:143\r\nProxy-Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l\r\n\r\n"
|
||||
);
|
||||
assert_eq!(
|
||||
http_connect_request("example.net", 587, None),
|
||||
"CONNECT example.net:587 HTTP/1.1\r\nHost: example.net:587\r\n\r\n"
|
||||
|
||||
+5
-5
@@ -5,12 +5,12 @@ use anyhow::Result;
|
||||
|
||||
use crate::net::session::SessionStream;
|
||||
|
||||
pub async fn wrap_tls(
|
||||
pub async fn wrap_tls<'a>(
|
||||
strict_tls: bool,
|
||||
hostname: &str,
|
||||
alpn: &[&str],
|
||||
stream: impl SessionStream + 'static,
|
||||
) -> Result<impl SessionStream> {
|
||||
) -> Result<impl SessionStream + 'a> {
|
||||
if strict_tls {
|
||||
let tls_stream = wrap_rustls(hostname, alpn, stream).await?;
|
||||
let boxed_stream: Box<dyn SessionStream> = Box::new(tls_stream);
|
||||
@@ -30,11 +30,11 @@ pub async fn wrap_tls(
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn wrap_rustls(
|
||||
pub async fn wrap_rustls<'a>(
|
||||
hostname: &str,
|
||||
alpn: &[&str],
|
||||
stream: impl SessionStream,
|
||||
) -> Result<impl SessionStream> {
|
||||
stream: impl SessionStream + 'a,
|
||||
) -> Result<impl SessionStream + 'a> {
|
||||
let mut root_cert_store = rustls::RootCertStore::empty();
|
||||
root_cert_store.extend(webpki_roots::TLS_SERVER_ROOTS.iter().cloned());
|
||||
|
||||
|
||||
+4
-2
@@ -3,7 +3,7 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use anyhow::{Context as _, Result};
|
||||
use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC};
|
||||
use percent_encoding::{NON_ALPHANUMERIC, utf8_percent_encode};
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::context::Context;
|
||||
@@ -20,7 +20,9 @@ const OAUTH2_GMAIL: Oauth2 = Oauth2 {
|
||||
get_code: "https://accounts.google.com/o/oauth2/auth?client_id=$CLIENT_ID&redirect_uri=$REDIRECT_URI&response_type=code&scope=https%3A%2F%2Fmail.google.com%2F%20email&access_type=offline",
|
||||
init_token: "https://accounts.google.com/o/oauth2/token?client_id=$CLIENT_ID&redirect_uri=$REDIRECT_URI&code=$CODE&grant_type=authorization_code",
|
||||
refresh_token: "https://accounts.google.com/o/oauth2/token?client_id=$CLIENT_ID&redirect_uri=$REDIRECT_URI&refresh_token=$REFRESH_TOKEN&grant_type=refresh_token",
|
||||
get_userinfo: Some("https://www.googleapis.com/oauth2/v1/userinfo?alt=json&access_token=$ACCESS_TOKEN"),
|
||||
get_userinfo: Some(
|
||||
"https://www.googleapis.com/oauth2/v1/userinfo?alt=json&access_token=$ACCESS_TOKEN",
|
||||
),
|
||||
};
|
||||
|
||||
const OAUTH2_YANDEX: Oauth2 = Oauth2 {
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ use std::path::PathBuf;
|
||||
use std::str;
|
||||
|
||||
use anyhow::ensure;
|
||||
use anyhow::{bail, Error, Result};
|
||||
use anyhow::{Error, Result, bail};
|
||||
use num_traits::FromPrimitive;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
||||
+24
-20
@@ -23,26 +23,26 @@
|
||||
//! (scoped per WebXDC app instance/message-id). The other peers can then join the gossip with `joinRealtimeChannel().setListener()`
|
||||
//! and `joinRealtimeChannel().send()` just like the other peers.
|
||||
|
||||
use anyhow::{anyhow, bail, Context as _, Result};
|
||||
use anyhow::{Context as _, Result, anyhow, bail};
|
||||
use data_encoding::BASE32_NOPAD;
|
||||
use futures_lite::StreamExt;
|
||||
use iroh::{Endpoint, NodeAddr, NodeId, PublicKey, RelayMode, RelayUrl, SecretKey};
|
||||
use iroh_gossip::net::{Event, Gossip, GossipEvent, JoinOptions, GOSSIP_ALPN};
|
||||
use iroh_gossip::net::{Event, GOSSIP_ALPN, Gossip, GossipEvent, JoinOptions};
|
||||
use iroh_gossip::proto::TopicId;
|
||||
use parking_lot::Mutex;
|
||||
use std::collections::{BTreeSet, HashMap};
|
||||
use std::env;
|
||||
use tokio::sync::{oneshot, RwLock};
|
||||
use tokio::sync::{RwLock, oneshot};
|
||||
use tokio::task::JoinHandle;
|
||||
use url::Url;
|
||||
|
||||
use crate::EventType;
|
||||
use crate::chat::send_msg;
|
||||
use crate::config::Config;
|
||||
use crate::context::Context;
|
||||
use crate::log::{info, warn};
|
||||
use crate::message::{Message, MsgId, Viewtype};
|
||||
use crate::mimeparser::SystemMessage;
|
||||
use crate::EventType;
|
||||
|
||||
/// The length of an ed25519 `PublicKey`, in bytes.
|
||||
const PUBLIC_KEY_LENGTH: usize = 32;
|
||||
@@ -554,10 +554,10 @@ async fn subscribe_loop(
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::{
|
||||
EventType,
|
||||
chat::send_msg,
|
||||
message::{Message, Viewtype},
|
||||
test_utils::TestContextManager,
|
||||
EventType,
|
||||
};
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
@@ -733,10 +733,12 @@ mod tests {
|
||||
let alice = &mut tcm.alice().await;
|
||||
let bob = &mut tcm.bob().await;
|
||||
|
||||
assert!(alice
|
||||
.get_config_bool(Config::WebxdcRealtimeEnabled)
|
||||
.await
|
||||
.unwrap());
|
||||
assert!(
|
||||
alice
|
||||
.get_config_bool(Config::WebxdcRealtimeEnabled)
|
||||
.await
|
||||
.unwrap()
|
||||
);
|
||||
// Alice sends webxdc to bob
|
||||
let alice_chat = alice.create_chat(bob).await;
|
||||
let mut instance = Message::new(Viewtype::File);
|
||||
@@ -901,17 +903,19 @@ mod tests {
|
||||
.await
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
assert!(alice
|
||||
.iroh
|
||||
.read()
|
||||
.await
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.iroh_channels
|
||||
.read()
|
||||
.await
|
||||
.get(&topic)
|
||||
.is_none());
|
||||
assert!(
|
||||
alice
|
||||
.iroh
|
||||
.read()
|
||||
.await
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.iroh_channels
|
||||
.read()
|
||||
.await
|
||||
.get(&topic)
|
||||
.is_none()
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
|
||||
+10
-6
@@ -465,17 +465,21 @@ mod tests {
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn test_encrypt_signed() {
|
||||
assert!(!ctext_signed().await.is_empty());
|
||||
assert!(ctext_signed()
|
||||
.await
|
||||
.starts_with("-----BEGIN PGP MESSAGE-----"));
|
||||
assert!(
|
||||
ctext_signed()
|
||||
.await
|
||||
.starts_with("-----BEGIN PGP MESSAGE-----")
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn test_encrypt_unsigned() {
|
||||
assert!(!ctext_unsigned().await.is_empty());
|
||||
assert!(ctext_unsigned()
|
||||
.await
|
||||
.starts_with("-----BEGIN PGP MESSAGE-----"));
|
||||
assert!(
|
||||
ctext_unsigned()
|
||||
.await
|
||||
.starts_with("-----BEGIN PGP MESSAGE-----")
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
|
||||
+11
-7
@@ -5,7 +5,7 @@ pub(crate) mod data;
|
||||
use anyhow::Result;
|
||||
use deltachat_contact_tools::EmailAddress;
|
||||
use hickory_resolver::name_server::TokioConnectionProvider;
|
||||
use hickory_resolver::{config, Resolver, TokioResolver};
|
||||
use hickory_resolver::{Resolver, TokioResolver, config};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::config::Config;
|
||||
@@ -356,17 +356,21 @@ mod tests {
|
||||
let t = TestContext::new().await;
|
||||
assert!(get_provider_info(&t, "", false).await.is_none());
|
||||
assert!(get_provider_info(&t, "google.com", false).await.unwrap().id == "gmail");
|
||||
assert!(get_provider_info(&t, "example@google.com", false)
|
||||
.await
|
||||
.is_none());
|
||||
assert!(
|
||||
get_provider_info(&t, "example@google.com", false)
|
||||
.await
|
||||
.is_none()
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn test_get_provider_info_by_addr() -> Result<()> {
|
||||
let t = TestContext::new().await;
|
||||
assert!(get_provider_info_by_addr(&t, "google.com", false)
|
||||
.await
|
||||
.is_err());
|
||||
assert!(
|
||||
get_provider_info_by_addr(&t, "google.com", false)
|
||||
.await
|
||||
.is_err()
|
||||
);
|
||||
assert!(
|
||||
get_provider_info_by_addr(&t, "example@google.com", false)
|
||||
.await?
|
||||
|
||||
+220
-45
@@ -102,8 +102,20 @@ static P_AOL: Provider = Provider {
|
||||
after_login_hint: "",
|
||||
overview_page: "https://providers.delta.chat/aol",
|
||||
server: &[
|
||||
Server { protocol: Imap, socket: Ssl, hostname: "imap.aol.com", port: 993, username_pattern: Email },
|
||||
Server { protocol: Smtp, socket: Ssl, hostname: "smtp.aol.com", port: 465, username_pattern: Email },
|
||||
Server {
|
||||
protocol: Imap,
|
||||
socket: Ssl,
|
||||
hostname: "imap.aol.com",
|
||||
port: 993,
|
||||
username_pattern: Email,
|
||||
},
|
||||
Server {
|
||||
protocol: Smtp,
|
||||
socket: Ssl,
|
||||
hostname: "smtp.aol.com",
|
||||
port: 465,
|
||||
username_pattern: Email,
|
||||
},
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
@@ -423,8 +435,20 @@ static P_EXAMPLE_COM: Provider = Provider {
|
||||
after_login_hint: "This provider doesn't really exist, so you can't use it :/ If you need an email provider for Delta Chat, take a look at providers.delta.chat!",
|
||||
overview_page: "https://providers.delta.chat/example-com",
|
||||
server: &[
|
||||
Server { protocol: Imap, socket: Ssl, hostname: "imap.example.com", port: 1337, username_pattern: Emaillocalpart },
|
||||
Server { protocol: Smtp, socket: Starttls, hostname: "smtp.example.com", port: 1337, username_pattern: Email },
|
||||
Server {
|
||||
protocol: Imap,
|
||||
socket: Ssl,
|
||||
hostname: "imap.example.com",
|
||||
port: 1337,
|
||||
username_pattern: Emaillocalpart,
|
||||
},
|
||||
Server {
|
||||
protocol: Smtp,
|
||||
socket: Starttls,
|
||||
hostname: "smtp.example.com",
|
||||
port: 1337,
|
||||
username_pattern: Email,
|
||||
},
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
@@ -435,8 +459,7 @@ static P_EXAMPLE_COM: Provider = Provider {
|
||||
static P_FASTMAIL: Provider = Provider {
|
||||
id: "fastmail",
|
||||
status: Status::Preparation,
|
||||
before_login_hint:
|
||||
"You must create an app-specific password for Delta Chat before you can log in.",
|
||||
before_login_hint: "You must create an app-specific password for Delta Chat before you can log in.",
|
||||
after_login_hint: "",
|
||||
overview_page: "https://providers.delta.chat/fastmail",
|
||||
server: &[
|
||||
@@ -467,8 +490,7 @@ static P_FIREMAIL_DE: Provider = Provider {
|
||||
before_login_hint: "Firemail erlaubt nur bei bezahlten Accounts den vollen Zugriff auf das E-Mail-Protokoll. Wenn Sie nicht für Firemail bezahlen, verwenden Sie bitte einen anderen E-Mail-Anbieter.",
|
||||
after_login_hint: "Leider schränkt Firemail die maximale Gruppengröße ein. Je nach Bezahlmodell sind nur 5 bis 30 Gruppenmitglieder erlaubt.",
|
||||
overview_page: "https://providers.delta.chat/firemail-de",
|
||||
server: &[
|
||||
],
|
||||
server: &[],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
@@ -508,10 +530,34 @@ static P_FREENET_DE: Provider = Provider {
|
||||
after_login_hint: "",
|
||||
overview_page: "https://providers.delta.chat/freenet-de",
|
||||
server: &[
|
||||
Server { protocol: Imap, socket: Ssl, hostname: "mx.freenet.de", port: 993, username_pattern: Email },
|
||||
Server { protocol: Imap, socket: Starttls, hostname: "mx.freenet.de", port: 143, username_pattern: Email },
|
||||
Server { protocol: Smtp, socket: Ssl, hostname: "mx.freenet.de", port: 465, username_pattern: Email },
|
||||
Server { protocol: Smtp, socket: Starttls, hostname: "mx.freenet.de", port: 587, username_pattern: Email },
|
||||
Server {
|
||||
protocol: Imap,
|
||||
socket: Ssl,
|
||||
hostname: "mx.freenet.de",
|
||||
port: 993,
|
||||
username_pattern: Email,
|
||||
},
|
||||
Server {
|
||||
protocol: Imap,
|
||||
socket: Starttls,
|
||||
hostname: "mx.freenet.de",
|
||||
port: 143,
|
||||
username_pattern: Email,
|
||||
},
|
||||
Server {
|
||||
protocol: Smtp,
|
||||
socket: Ssl,
|
||||
hostname: "mx.freenet.de",
|
||||
port: 465,
|
||||
username_pattern: Email,
|
||||
},
|
||||
Server {
|
||||
protocol: Smtp,
|
||||
socket: Starttls,
|
||||
hostname: "mx.freenet.de",
|
||||
port: 587,
|
||||
username_pattern: Email,
|
||||
},
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
@@ -526,8 +572,20 @@ static P_GMAIL: Provider = Provider {
|
||||
after_login_hint: "",
|
||||
overview_page: "https://providers.delta.chat/gmail",
|
||||
server: &[
|
||||
Server { protocol: Imap, socket: Ssl, hostname: "imap.gmail.com", port: 993, username_pattern: Email },
|
||||
Server { protocol: Smtp, socket: Ssl, hostname: "smtp.gmail.com", port: 465, username_pattern: Email },
|
||||
Server {
|
||||
protocol: Imap,
|
||||
socket: Ssl,
|
||||
hostname: "imap.gmail.com",
|
||||
port: 993,
|
||||
username_pattern: Email,
|
||||
},
|
||||
Server {
|
||||
protocol: Smtp,
|
||||
socket: Ssl,
|
||||
hostname: "smtp.gmail.com",
|
||||
port: 465,
|
||||
username_pattern: Email,
|
||||
},
|
||||
],
|
||||
opt: ProviderOptions {
|
||||
delete_to_trash: true,
|
||||
@@ -608,8 +666,7 @@ static P_HEY_COM: Provider = Provider {
|
||||
before_login_hint: "hey.com does not offer the standard IMAP e-mail protocol, so you cannot log in with Delta Chat to hey.com.",
|
||||
after_login_hint: "",
|
||||
overview_page: "https://providers.delta.chat/hey-com",
|
||||
server: &[
|
||||
],
|
||||
server: &[],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
@@ -733,8 +790,7 @@ static P_MAIL_COM: Provider = Provider {
|
||||
before_login_hint: "To log in with Delta Chat, you first need to activate POP3/IMAP in your mail.com settings. Note that this is a mail.com Premium feature only.",
|
||||
after_login_hint: "",
|
||||
overview_page: "https://providers.delta.chat/mail-com",
|
||||
server: &[
|
||||
],
|
||||
server: &[],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
@@ -776,8 +832,20 @@ static P_MAIL_RU: Provider = Provider {
|
||||
after_login_hint: "",
|
||||
overview_page: "https://providers.delta.chat/mail-ru",
|
||||
server: &[
|
||||
Server { protocol: Imap, socket: Ssl, hostname: "imap.mail.ru", port: 993, username_pattern: Email },
|
||||
Server { protocol: Smtp, socket: Ssl, hostname: "smtp.mail.ru", port: 465, username_pattern: Email },
|
||||
Server {
|
||||
protocol: Imap,
|
||||
socket: Ssl,
|
||||
hostname: "imap.mail.ru",
|
||||
port: 993,
|
||||
username_pattern: Email,
|
||||
},
|
||||
Server {
|
||||
protocol: Smtp,
|
||||
socket: Ssl,
|
||||
hostname: "smtp.mail.ru",
|
||||
port: 465,
|
||||
username_pattern: Email,
|
||||
},
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
@@ -932,8 +1000,20 @@ static P_MEHL_STORE: Provider = Provider {
|
||||
after_login_hint: "This account provides 3GB storage for eMails and the possibility to access a NEXTCLOUD-instance by using the email-credits!",
|
||||
overview_page: "https://providers.delta.chat/mehl-store",
|
||||
server: &[
|
||||
Server { protocol: Imap, socket: Ssl, hostname: "mail.ende.in.net", port: 993, username_pattern: Email },
|
||||
Server { protocol: Smtp, socket: Starttls, hostname: "mail.ende.in.net", port: 587, username_pattern: Email },
|
||||
Server {
|
||||
protocol: Imap,
|
||||
socket: Ssl,
|
||||
hostname: "mail.ende.in.net",
|
||||
port: 993,
|
||||
username_pattern: Email,
|
||||
},
|
||||
Server {
|
||||
protocol: Smtp,
|
||||
socket: Starttls,
|
||||
hostname: "mail.ende.in.net",
|
||||
port: 587,
|
||||
username_pattern: Email,
|
||||
},
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
@@ -1244,8 +1324,7 @@ static P_PROTONMAIL: Provider = Provider {
|
||||
before_login_hint: "Protonmail does not offer the standard IMAP e-mail protocol, so you cannot log in with Delta Chat to Protonmail.",
|
||||
after_login_hint: "To use Delta Chat with Protonmail, the IMAP bridge must be running in the background. If you have connectivity issues, double check whether it works as expected.",
|
||||
overview_page: "https://providers.delta.chat/protonmail",
|
||||
server: &[
|
||||
],
|
||||
server: &[],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
@@ -1287,8 +1366,20 @@ static P_QQ: Provider = Provider {
|
||||
after_login_hint: "",
|
||||
overview_page: "https://providers.delta.chat/qq",
|
||||
server: &[
|
||||
Server { protocol: Imap, socket: Ssl, hostname: "imap.qq.com", port: 993, username_pattern: Emaillocalpart },
|
||||
Server { protocol: Smtp, socket: Ssl, hostname: "smtp.qq.com", port: 465, username_pattern: Email },
|
||||
Server {
|
||||
protocol: Imap,
|
||||
socket: Ssl,
|
||||
hostname: "imap.qq.com",
|
||||
port: 993,
|
||||
username_pattern: Emaillocalpart,
|
||||
},
|
||||
Server {
|
||||
protocol: Smtp,
|
||||
socket: Ssl,
|
||||
hostname: "smtp.qq.com",
|
||||
port: 465,
|
||||
username_pattern: Email,
|
||||
},
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
@@ -1303,9 +1394,27 @@ static P_RAMBLER_RU: Provider = Provider {
|
||||
after_login_hint: "",
|
||||
overview_page: "https://providers.delta.chat/rambler-ru",
|
||||
server: &[
|
||||
Server { protocol: Imap, socket: Ssl, hostname: "imap.rambler.ru", port: 993, username_pattern: Email },
|
||||
Server { protocol: Smtp, socket: Ssl, hostname: "smtp.rambler.ru", port: 465, username_pattern: Email },
|
||||
Server { protocol: Imap, socket: Starttls, hostname: "imap.rambler.ru", port: 143, username_pattern: Email },
|
||||
Server {
|
||||
protocol: Imap,
|
||||
socket: Ssl,
|
||||
hostname: "imap.rambler.ru",
|
||||
port: 993,
|
||||
username_pattern: Email,
|
||||
},
|
||||
Server {
|
||||
protocol: Smtp,
|
||||
socket: Ssl,
|
||||
hostname: "smtp.rambler.ru",
|
||||
port: 465,
|
||||
username_pattern: Email,
|
||||
},
|
||||
Server {
|
||||
protocol: Imap,
|
||||
socket: Starttls,
|
||||
hostname: "imap.rambler.ru",
|
||||
port: 143,
|
||||
username_pattern: Email,
|
||||
},
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
@@ -1461,8 +1570,20 @@ static P_T_ONLINE: Provider = Provider {
|
||||
after_login_hint: "",
|
||||
overview_page: "https://providers.delta.chat/t-online",
|
||||
server: &[
|
||||
Server { protocol: Imap, socket: Ssl, hostname: "secureimap.t-online.de", port: 993, username_pattern: Email },
|
||||
Server { protocol: Smtp, socket: Ssl, hostname: "securesmtp.t-online.de", port: 465, username_pattern: Email },
|
||||
Server {
|
||||
protocol: Imap,
|
||||
socket: Ssl,
|
||||
hostname: "secureimap.t-online.de",
|
||||
port: 993,
|
||||
username_pattern: Email,
|
||||
},
|
||||
Server {
|
||||
protocol: Smtp,
|
||||
socket: Ssl,
|
||||
hostname: "securesmtp.t-online.de",
|
||||
port: 465,
|
||||
username_pattern: Email,
|
||||
},
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
@@ -1559,8 +1680,7 @@ static P_TUTANOTA: Provider = Provider {
|
||||
before_login_hint: "Tutanota does not offer the standard IMAP e-mail protocol, so you cannot log in with Delta Chat to Tutanota.",
|
||||
after_login_hint: "",
|
||||
overview_page: "https://providers.delta.chat/tutanota",
|
||||
server: &[
|
||||
],
|
||||
server: &[],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
oauth2_authorizer: None,
|
||||
@@ -1671,8 +1791,20 @@ static P_VK_COM: Provider = Provider {
|
||||
after_login_hint: "",
|
||||
overview_page: "https://providers.delta.chat/vk-com",
|
||||
server: &[
|
||||
Server { protocol: Imap, socket: Ssl, hostname: "imap.mail.ru", port: 993, username_pattern: Email },
|
||||
Server { protocol: Smtp, socket: Ssl, hostname: "smtp.mail.ru", port: 465, username_pattern: Email },
|
||||
Server {
|
||||
protocol: Imap,
|
||||
socket: Ssl,
|
||||
hostname: "imap.mail.ru",
|
||||
port: 993,
|
||||
username_pattern: Email,
|
||||
},
|
||||
Server {
|
||||
protocol: Smtp,
|
||||
socket: Ssl,
|
||||
hostname: "smtp.mail.ru",
|
||||
port: 465,
|
||||
username_pattern: Email,
|
||||
},
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
@@ -1715,9 +1847,27 @@ static P_WEB_DE: Provider = Provider {
|
||||
after_login_hint: "Note: if you have your web.de spam settings too strict, you won't receive contact requests from new people. If you want to receive contact requests, you should disable the \"3-Wege-Spamschutz\" in the web.de settings. Read how: https://hilfe.web.de/email/spam-und-viren/spamschutz-einstellungen.html",
|
||||
overview_page: "https://providers.delta.chat/web-de",
|
||||
server: &[
|
||||
Server { protocol: Imap, socket: Ssl, hostname: "imap.web.de", port: 993, username_pattern: Emaillocalpart },
|
||||
Server { protocol: Imap, socket: Starttls, hostname: "imap.web.de", port: 143, username_pattern: Emaillocalpart },
|
||||
Server { protocol: Smtp, socket: Starttls, hostname: "smtp.web.de", port: 587, username_pattern: Emaillocalpart },
|
||||
Server {
|
||||
protocol: Imap,
|
||||
socket: Ssl,
|
||||
hostname: "imap.web.de",
|
||||
port: 993,
|
||||
username_pattern: Emaillocalpart,
|
||||
},
|
||||
Server {
|
||||
protocol: Imap,
|
||||
socket: Starttls,
|
||||
hostname: "imap.web.de",
|
||||
port: 143,
|
||||
username_pattern: Emaillocalpart,
|
||||
},
|
||||
Server {
|
||||
protocol: Smtp,
|
||||
socket: Starttls,
|
||||
hostname: "smtp.web.de",
|
||||
port: 587,
|
||||
username_pattern: Emaillocalpart,
|
||||
},
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
@@ -1760,8 +1910,20 @@ static P_YAHOO: Provider = Provider {
|
||||
after_login_hint: "",
|
||||
overview_page: "https://providers.delta.chat/yahoo",
|
||||
server: &[
|
||||
Server { protocol: Imap, socket: Ssl, hostname: "imap.mail.yahoo.com", port: 993, username_pattern: Email },
|
||||
Server { protocol: Smtp, socket: Ssl, hostname: "smtp.mail.yahoo.com", port: 465, username_pattern: Email },
|
||||
Server {
|
||||
protocol: Imap,
|
||||
socket: Ssl,
|
||||
hostname: "imap.mail.yahoo.com",
|
||||
port: 993,
|
||||
username_pattern: Email,
|
||||
},
|
||||
Server {
|
||||
protocol: Smtp,
|
||||
socket: Ssl,
|
||||
hostname: "smtp.mail.yahoo.com",
|
||||
port: 465,
|
||||
username_pattern: Email,
|
||||
},
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: None,
|
||||
@@ -1804,13 +1966,26 @@ static P_YGGMAIL: Provider = Provider {
|
||||
after_login_hint: "Make sure, the Yggmail companion app runs whenever you want to use this account. Note, that you usually cannot write from @yggmail addresses to normal e-mail-addresses (as @gmx.net). However, you can create another account in the normal e-mail-network for this purpose.",
|
||||
overview_page: "https://providers.delta.chat/yggmail",
|
||||
server: &[
|
||||
Server { protocol: Imap, socket: Plain, hostname: "localhost", port: 1143, username_pattern: Email },
|
||||
Server { protocol: Smtp, socket: Plain, hostname: "localhost", port: 1025, username_pattern: Email },
|
||||
Server {
|
||||
protocol: Imap,
|
||||
socket: Plain,
|
||||
hostname: "localhost",
|
||||
port: 1143,
|
||||
username_pattern: Email,
|
||||
},
|
||||
Server {
|
||||
protocol: Smtp,
|
||||
socket: Plain,
|
||||
hostname: "localhost",
|
||||
port: 1025,
|
||||
username_pattern: Email,
|
||||
},
|
||||
],
|
||||
opt: ProviderOptions::new(),
|
||||
config_defaults: Some(&[
|
||||
ConfigDefault { key: Config::MvboxMove, value: "0" },
|
||||
]),
|
||||
config_defaults: Some(&[ConfigDefault {
|
||||
key: Config::MvboxMove,
|
||||
value: "0",
|
||||
}]),
|
||||
oauth2_authorizer: None,
|
||||
};
|
||||
|
||||
|
||||
+1
-1
@@ -6,8 +6,8 @@
|
||||
//! It provides [`PushSubscriber`] type
|
||||
//! which holds push notification token for the device,
|
||||
//! shared by all accounts.
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
use anyhow::{Context as _, Result};
|
||||
use base64::Engine as _;
|
||||
|
||||
@@ -4,10 +4,10 @@ mod dclogin_scheme;
|
||||
use std::collections::BTreeMap;
|
||||
use std::sync::LazyLock;
|
||||
|
||||
use anyhow::{anyhow, bail, ensure, Context as _, Result};
|
||||
use anyhow::{Context as _, Result, anyhow, bail, ensure};
|
||||
pub use dclogin_scheme::LoginOptions;
|
||||
use deltachat_contact_tools::{addr_normalize, may_be_valid_addr, ContactAddress};
|
||||
use percent_encoding::{percent_decode_str, percent_encode, NON_ALPHANUMERIC};
|
||||
use deltachat_contact_tools::{ContactAddress, addr_normalize, may_be_valid_addr};
|
||||
use percent_encoding::{NON_ALPHANUMERIC, percent_decode_str, percent_encode};
|
||||
use serde::Deserialize;
|
||||
|
||||
pub(crate) use self::dclogin_scheme::configure_from_login_qr;
|
||||
@@ -18,7 +18,7 @@ use crate::events::EventType;
|
||||
use crate::key::Fingerprint;
|
||||
use crate::message::Message;
|
||||
use crate::net::http::post_empty;
|
||||
use crate::net::proxy::{ProxyConfig, DEFAULT_SOCKS_PORT};
|
||||
use crate::net::proxy::{DEFAULT_SOCKS_PORT, ProxyConfig};
|
||||
use crate::token;
|
||||
use crate::tools::validate_id;
|
||||
|
||||
@@ -367,8 +367,8 @@ pub async fn check_qr(context: &Context, qr: &str) -> Result<Qr> {
|
||||
pub fn format_backup(qr: &Qr) -> Result<String> {
|
||||
match qr {
|
||||
Qr::Backup2 {
|
||||
ref node_addr,
|
||||
ref auth_token,
|
||||
node_addr,
|
||||
auth_token,
|
||||
} => {
|
||||
let node_addr = serde_json::to_string(node_addr)?;
|
||||
Ok(format!(
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use anyhow::{bail, Context as _, Result};
|
||||
use anyhow::{Context as _, Result, bail};
|
||||
|
||||
use deltachat_contact_tools::may_be_valid_addr;
|
||||
use num_traits::cast::ToPrimitive;
|
||||
|
||||
use super::{Qr, DCLOGIN_SCHEME};
|
||||
use super::{DCLOGIN_SCHEME, Qr};
|
||||
use crate::config::Config;
|
||||
use crate::context::Context;
|
||||
use crate::login_param::EnteredCertificateChecks;
|
||||
@@ -263,7 +263,7 @@ pub(crate) async fn configure_from_login_qr(
|
||||
mod test {
|
||||
use anyhow::bail;
|
||||
|
||||
use super::{decode_login, LoginOptions};
|
||||
use super::{LoginOptions, decode_login};
|
||||
use crate::{login_param::EnteredCertificateChecks, provider::Socket, qr::Qr};
|
||||
|
||||
macro_rules! login_options_just_pw {
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
use super::*;
|
||||
use crate::chat::{create_group_chat, ProtectionStatus};
|
||||
use crate::chat::{ProtectionStatus, create_group_chat};
|
||||
use crate::config::Config;
|
||||
use crate::securejoin::get_securejoin_qr;
|
||||
use crate::test_utils::{TestContext, TestContextManager};
|
||||
|
||||
+2
-2
@@ -3,7 +3,7 @@
|
||||
use std::collections::BTreeMap;
|
||||
use std::time::Duration;
|
||||
|
||||
use anyhow::{anyhow, Context as _, Result};
|
||||
use anyhow::{Context as _, Result, anyhow};
|
||||
use async_imap::types::{Quota, QuotaResource};
|
||||
|
||||
use crate::chat::add_device_msg_with_importance;
|
||||
@@ -14,7 +14,7 @@ use crate::imap::session::Session as ImapSession;
|
||||
use crate::log::warn;
|
||||
use crate::message::Message;
|
||||
use crate::tools::{self, time_elapsed};
|
||||
use crate::{stock_str, EventType};
|
||||
use crate::{EventType, stock_str};
|
||||
|
||||
/// warn about a nearly full mailbox after this usage percentage is reached.
|
||||
/// quota icon is "yellow".
|
||||
|
||||
+3
-3
@@ -21,13 +21,13 @@ use std::fmt;
|
||||
use anyhow::Result;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::chat::{send_msg, Chat, ChatId};
|
||||
use crate::chat::{Chat, ChatId, send_msg};
|
||||
use crate::chatlist_events;
|
||||
use crate::contact::ContactId;
|
||||
use crate::context::Context;
|
||||
use crate::events::EventType;
|
||||
use crate::log::info;
|
||||
use crate::message::{rfc724_mid_exists, Message, MsgId};
|
||||
use crate::message::{Message, MsgId, rfc724_mid_exists};
|
||||
use crate::param::Param;
|
||||
|
||||
/// A single reaction consisting of multiple emoji sequences.
|
||||
@@ -404,7 +404,7 @@ mod tests {
|
||||
use crate::config::Config;
|
||||
use crate::contact::{Contact, Origin};
|
||||
use crate::download::DownloadState;
|
||||
use crate::message::{delete_msgs, MessageState};
|
||||
use crate::message::{MessageState, delete_msgs};
|
||||
use crate::receive_imf::{receive_imf, receive_imf_from_inbox};
|
||||
use crate::sql::housekeeping;
|
||||
use crate::test_utils::TestContext;
|
||||
|
||||
+13
-10
@@ -7,7 +7,7 @@ use std::sync::LazyLock;
|
||||
use anyhow::{Context as _, Result};
|
||||
use data_encoding::BASE32_NOPAD;
|
||||
use deltachat_contact_tools::{
|
||||
addr_cmp, addr_normalize, may_be_valid_addr, sanitize_single_line, ContactAddress,
|
||||
ContactAddress, addr_cmp, addr_normalize, may_be_valid_addr, sanitize_single_line,
|
||||
};
|
||||
use iroh_gossip::proto::TopicId;
|
||||
use mailparse::SingleInfo;
|
||||
@@ -16,26 +16,26 @@ use regex::Regex;
|
||||
|
||||
use crate::chat::{self, Chat, ChatId, ChatIdBlocked, ProtectionStatus};
|
||||
use crate::config::Config;
|
||||
use crate::constants::{Blocked, Chattype, ShowEmails, DC_CHAT_ID_TRASH, EDITED_PREFIX};
|
||||
use crate::contact::{mark_contact_id_as_verified, Contact, ContactId, Origin};
|
||||
use crate::constants::{Blocked, Chattype, DC_CHAT_ID_TRASH, EDITED_PREFIX, ShowEmails};
|
||||
use crate::contact::{Contact, ContactId, Origin, mark_contact_id_as_verified};
|
||||
use crate::context::Context;
|
||||
use crate::debug_logging::maybe_set_logging_xdc_inner;
|
||||
use crate::download::DownloadState;
|
||||
use crate::ephemeral::{stock_ephemeral_timer_changed, Timer as EphemeralTimer};
|
||||
use crate::ephemeral::{Timer as EphemeralTimer, stock_ephemeral_timer_changed};
|
||||
use crate::events::EventType;
|
||||
use crate::headerdef::{HeaderDef, HeaderDefMap};
|
||||
use crate::imap::{markseen_on_imap_table, GENERATED_PREFIX};
|
||||
use crate::imap::{GENERATED_PREFIX, markseen_on_imap_table};
|
||||
use crate::key::self_fingerprint_opt;
|
||||
use crate::key::{DcKey, Fingerprint, SignedPublicKey};
|
||||
use crate::log::LogExt;
|
||||
use crate::log::{info, warn};
|
||||
use crate::message::{
|
||||
self, rfc724_mid_exists, Message, MessageState, MessengerMessage, MsgId, Viewtype,
|
||||
self, Message, MessageState, MessengerMessage, MsgId, Viewtype, rfc724_mid_exists,
|
||||
};
|
||||
use crate::mimeparser::{parse_message_ids, AvatarAction, MimeMessage, SystemMessage};
|
||||
use crate::mimeparser::{AvatarAction, MimeMessage, SystemMessage, parse_message_ids};
|
||||
use crate::param::{Param, Params};
|
||||
use crate::peer_channels::{add_gossip_peer_from_header, insert_topic_stub};
|
||||
use crate::reaction::{set_msg_reaction, Reaction};
|
||||
use crate::reaction::{Reaction, set_msg_reaction};
|
||||
use crate::rusqlite::OptionalExtension;
|
||||
use crate::securejoin::{self, handle_securejoin_handshake, observe_securejoin_on_other_device};
|
||||
use crate::simplify;
|
||||
@@ -244,7 +244,7 @@ async fn get_to_and_past_contact_ids(
|
||||
// but want to assign the message to 1:1 chat.
|
||||
let chat_id = match chat_assignment {
|
||||
ChatAssignment::Trash => None,
|
||||
ChatAssignment::GroupChat { ref grpid } => {
|
||||
ChatAssignment::GroupChat { grpid } => {
|
||||
if let Some((chat_id, _protected, _blocked)) =
|
||||
chat::get_chat_id_by_grpid(context, grpid).await?
|
||||
{
|
||||
@@ -1729,7 +1729,10 @@ async fn add_parts(
|
||||
let is_from_in_chat =
|
||||
!chat_contacts.contains(&ContactId::SELF) || chat_contacts.contains(&from_id);
|
||||
|
||||
info!(context, "Received new ephemeral timer value {ephemeral_timer:?} for chat {chat_id}, checking if it should be applied.");
|
||||
info!(
|
||||
context,
|
||||
"Received new ephemeral timer value {ephemeral_timer:?} for chat {chat_id}, checking if it should be applied."
|
||||
);
|
||||
if !is_from_in_chat {
|
||||
warn!(
|
||||
context,
|
||||
|
||||
@@ -5,20 +5,19 @@ use tokio::fs;
|
||||
|
||||
use super::*;
|
||||
use crate::chat::{
|
||||
add_contact_to_chat, add_to_chat_contacts_table, create_group_chat, get_chat_contacts,
|
||||
get_chat_msgs, is_contact_in_chat, remove_contact_from_chat, send_text_msg, ChatItem,
|
||||
ChatVisibility,
|
||||
ChatItem, ChatVisibility, add_contact_to_chat, add_to_chat_contacts_table, create_group_chat,
|
||||
get_chat_contacts, get_chat_msgs, is_contact_in_chat, remove_contact_from_chat, send_text_msg,
|
||||
};
|
||||
use crate::chatlist::Chatlist;
|
||||
use crate::constants::DC_GCL_FOR_FORWARDING;
|
||||
use crate::contact;
|
||||
use crate::download::MIN_DOWNLOAD_LIMIT;
|
||||
use crate::imap::prefetch_should_download;
|
||||
use crate::imex::{imex, ImexMode};
|
||||
use crate::imex::{ImexMode, imex};
|
||||
use crate::securejoin::get_securejoin_qr;
|
||||
use crate::test_utils::mark_as_verified;
|
||||
use crate::test_utils::{get_chat_msg, TestContext, TestContextManager};
|
||||
use crate::tools::{time, SystemTime};
|
||||
use crate::test_utils::{TestContext, TestContextManager, get_chat_msg};
|
||||
use crate::tools::{SystemTime, time};
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn test_outgoing() -> Result<()> {
|
||||
@@ -358,10 +357,12 @@ async fn test_no_from() {
|
||||
assert!(chats.is_empty());
|
||||
|
||||
// Check that the message was added to the db:
|
||||
assert!(message::rfc724_mid_exists(context, "3924@example.com")
|
||||
.await
|
||||
.unwrap()
|
||||
.is_some());
|
||||
assert!(
|
||||
message::rfc724_mid_exists(context, "3924@example.com")
|
||||
.await
|
||||
.unwrap()
|
||||
.is_some()
|
||||
);
|
||||
}
|
||||
|
||||
/// If there is no Message-Id header, we generate a random id.
|
||||
@@ -390,14 +391,15 @@ async fn test_no_message_id_header() {
|
||||
.unwrap();
|
||||
assert!(received.is_none());
|
||||
|
||||
assert!(!t
|
||||
.sql
|
||||
.exists(
|
||||
"SELECT COUNT(*) FROM msgs WHERE chat_id=?;",
|
||||
(DC_CHAT_ID_TRASH,),
|
||||
)
|
||||
.await
|
||||
.unwrap());
|
||||
assert!(
|
||||
!t.sql
|
||||
.exists(
|
||||
"SELECT COUNT(*) FROM msgs WHERE chat_id=?;",
|
||||
(DC_CHAT_ID_TRASH,),
|
||||
)
|
||||
.await
|
||||
.unwrap()
|
||||
);
|
||||
|
||||
let chats = Chatlist::try_load(&t, 0, None, None).await.unwrap();
|
||||
// Check that the message is not shown to the user:
|
||||
@@ -827,7 +829,10 @@ async fn load_imf_email(context: &Context, imf_raw: &[u8]) -> Message {
|
||||
async fn test_html_only_mail() {
|
||||
let t = TestContext::new_alice().await;
|
||||
let msg = load_imf_email(&t, include_bytes!("../../test-data/message/wrong-html.eml")).await;
|
||||
assert_eq!(msg.text, "Guten Abend,\n\nLots of text\n\ntext with Umlaut ä...\n\nMfG\n\n--------------------------------------\n\n[Camping ](https://example.com/)\n\nsomeaddress\n\nsometown");
|
||||
assert_eq!(
|
||||
msg.text,
|
||||
"Guten Abend,\n\nLots of text\n\ntext with Umlaut ä...\n\nMfG\n\n--------------------------------------\n\n[Camping ](https://example.com/)\n\nsomeaddress\n\nsometown"
|
||||
);
|
||||
}
|
||||
|
||||
static GH_MAILINGLIST: &[u8] =
|
||||
@@ -843,8 +848,7 @@ static GH_MAILINGLIST: &[u8] =
|
||||
\n\
|
||||
hello\n";
|
||||
|
||||
static GH_MAILINGLIST2: &str =
|
||||
"Received: (Postfix, from userid 1000); Mon, 4 Dec 2006 14:51:39 +0100 (CET)\n\
|
||||
static GH_MAILINGLIST2: &str = "Received: (Postfix, from userid 1000); Mon, 4 Dec 2006 14:51:39 +0100 (CET)\n\
|
||||
From: Github <notifications@github.com>\n\
|
||||
To: deltachat/deltachat-core-rust <deltachat-core-rust@noreply.github.com>\n\
|
||||
Subject: [deltachat/deltachat-core-rust] PR run failed\n\
|
||||
@@ -2693,7 +2697,10 @@ async fn test_gmx_forwarded_msg() -> Result<()> {
|
||||
|
||||
let msg = t.get_last_msg().await;
|
||||
assert!(msg.has_html());
|
||||
assert_eq!(msg.id.get_html(&t).await?.unwrap().replace("\r\n", "\n"), "<html><head></head><body><div style=\"font-family: Verdana;font-size: 12.0px;\"><div> </div>\n\n<div> \n<div> \n<div data-darkreader-inline-border-left=\"\" name=\"quote\" style=\"margin: 10px 5px 5px 10px; padding: 10px 0px 10px 10px; border-left: 2px solid rgb(195, 217, 229); overflow-wrap: break-word; --darkreader-inline-border-left:#274759;\">\n<div style=\"margin:0 0 10px 0;\"><b>Gesendet:</b> Donnerstag, 12. August 2021 um 15:52 Uhr<br/>\n<b>Von:</b> "Claire" <claire@example.org><br/>\n<b>An:</b> alice@example.org<br/>\n<b>Betreff:</b> subject</div>\n\n<div name=\"quoted-content\">bodytext</div>\n</div>\n</div>\n</div></div></body></html>\n\n");
|
||||
assert_eq!(
|
||||
msg.id.get_html(&t).await?.unwrap().replace("\r\n", "\n"),
|
||||
"<html><head></head><body><div style=\"font-family: Verdana;font-size: 12.0px;\"><div> </div>\n\n<div> \n<div> \n<div data-darkreader-inline-border-left=\"\" name=\"quote\" style=\"margin: 10px 5px 5px 10px; padding: 10px 0px 10px 10px; border-left: 2px solid rgb(195, 217, 229); overflow-wrap: break-word; --darkreader-inline-border-left:#274759;\">\n<div style=\"margin:0 0 10px 0;\"><b>Gesendet:</b> Donnerstag, 12. August 2021 um 15:52 Uhr<br/>\n<b>Von:</b> "Claire" <claire@example.org><br/>\n<b>An:</b> alice@example.org<br/>\n<b>Betreff:</b> subject</div>\n\n<div name=\"quoted-content\">bodytext</div>\n</div>\n</div>\n</div></div></body></html>\n\n"
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -3233,9 +3240,11 @@ async fn test_outgoing_undecryptable() -> Result<()> {
|
||||
.unwrap();
|
||||
let dev_msg = alice.get_last_msg_in(dev_chat_id).await;
|
||||
assert!(dev_msg.error().is_none());
|
||||
assert!(dev_msg
|
||||
.text
|
||||
.contains(&stock_str::cant_decrypt_outgoing_msgs(alice).await));
|
||||
assert!(
|
||||
dev_msg
|
||||
.text
|
||||
.contains(&stock_str::cant_decrypt_outgoing_msgs(alice).await)
|
||||
);
|
||||
|
||||
let raw = include_bytes!("../../test-data/message/thunderbird_encrypted_signed.eml");
|
||||
receive_imf(alice, raw, false).await?;
|
||||
@@ -3462,9 +3471,10 @@ async fn test_big_forwarded_with_big_attachment() -> Result<()> {
|
||||
|
||||
let msg = Message::load_from_db(t, rcvd.msg_ids[1]).await?;
|
||||
assert_eq!(msg.get_viewtype(), Viewtype::Text);
|
||||
assert!(msg
|
||||
.get_text()
|
||||
.starts_with("this text with 42 chars is just repeated."));
|
||||
assert!(
|
||||
msg.get_text()
|
||||
.starts_with("this text with 42 chars is just repeated.")
|
||||
);
|
||||
assert!(msg.get_text().ends_with("[...]"));
|
||||
assert!(!msg.has_html());
|
||||
|
||||
|
||||
+6
-6
@@ -3,12 +3,12 @@ use std::iter::{self, once};
|
||||
use std::num::NonZeroUsize;
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
use anyhow::{bail, Context as _, Error, Result};
|
||||
use anyhow::{Context as _, Error, Result, bail};
|
||||
use async_channel::{self as channel, Receiver, Sender};
|
||||
use futures::future::try_join_all;
|
||||
use futures_lite::FutureExt;
|
||||
use rand::Rng;
|
||||
use tokio::sync::{oneshot, RwLock, RwLockWriteGuard};
|
||||
use tokio::sync::{RwLock, RwLockWriteGuard, oneshot};
|
||||
use tokio::task;
|
||||
use tokio_util::sync::CancellationToken;
|
||||
use tokio_util::task::TaskTracker;
|
||||
@@ -17,14 +17,14 @@ use self::connectivity::ConnectivityStore;
|
||||
use crate::config::{self, Config};
|
||||
use crate::contact::{ContactId, RecentlySeenLoop};
|
||||
use crate::context::Context;
|
||||
use crate::download::{download_msg, DownloadState};
|
||||
use crate::download::{DownloadState, download_msg};
|
||||
use crate::ephemeral::{self, delete_expired_imap_messages};
|
||||
use crate::events::EventType;
|
||||
use crate::imap::{session::Session, FolderMeaning, Imap};
|
||||
use crate::imap::{FolderMeaning, Imap, session::Session};
|
||||
use crate::location;
|
||||
use crate::log::{error, info, warn, LogExt};
|
||||
use crate::log::{LogExt, error, info, warn};
|
||||
use crate::message::MsgId;
|
||||
use crate::smtp::{send_smtp_messages, Smtp};
|
||||
use crate::smtp::{Smtp, send_smtp_messages};
|
||||
use crate::sql;
|
||||
use crate::tools::{self, duration_to_str, maybe_add_time_based_warnings, time, time_elapsed};
|
||||
|
||||
|
||||
@@ -3,11 +3,11 @@ use std::cmp::min;
|
||||
use std::{iter::once, ops::Deref, sync::Arc};
|
||||
|
||||
use anyhow::Result;
|
||||
use humansize::{format_size, BINARY};
|
||||
use humansize::{BINARY, format_size};
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
use crate::events::EventType;
|
||||
use crate::imap::{scan_folders::get_watched_folder_configs, FolderMeaning};
|
||||
use crate::imap::{FolderMeaning, scan_folders::get_watched_folder_configs};
|
||||
use crate::log::info;
|
||||
use crate::quota::{QUOTA_ERROR_THRESHOLD_PERCENTAGE, QUOTA_WARN_THRESHOLD_PERCENTAGE};
|
||||
use crate::stock_str;
|
||||
@@ -509,7 +509,9 @@ impl Context {
|
||||
"green"
|
||||
};
|
||||
let div_width_percent = min(100, percent);
|
||||
ret += &format!("<div class=\"bar\"><div class=\"progress {color}\" style=\"width: {div_width_percent}%\">{percent}%</div></div>");
|
||||
ret += &format!(
|
||||
"<div class=\"bar\"><div class=\"progress {color}\" style=\"width: {div_width_percent}%\">{percent}%</div></div>"
|
||||
);
|
||||
|
||||
ret += "</li>";
|
||||
}
|
||||
|
||||
+4
-4
@@ -1,10 +1,10 @@
|
||||
//! Implementation of [SecureJoin protocols](https://securejoin.delta.chat/).
|
||||
|
||||
use anyhow::{ensure, Context as _, Error, Result};
|
||||
use anyhow::{Context as _, Error, Result, ensure};
|
||||
use deltachat_contact_tools::ContactAddress;
|
||||
use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC};
|
||||
use percent_encoding::{NON_ALPHANUMERIC, utf8_percent_encode};
|
||||
|
||||
use crate::chat::{self, get_chat_id_by_grpid, Chat, ChatId, ChatIdBlocked, ProtectionStatus};
|
||||
use crate::chat::{self, Chat, ChatId, ChatIdBlocked, ProtectionStatus, get_chat_id_by_grpid};
|
||||
use crate::chatlist_events;
|
||||
use crate::config::Config;
|
||||
use crate::constants::{Blocked, Chattype, NON_ALPHANUMERIC_WITHOUT_DOT};
|
||||
@@ -14,7 +14,7 @@ use crate::context::Context;
|
||||
use crate::e2ee::ensure_secret_key_exists;
|
||||
use crate::events::EventType;
|
||||
use crate::headerdef::HeaderDef;
|
||||
use crate::key::{load_self_public_key, DcKey, Fingerprint};
|
||||
use crate::key::{DcKey, Fingerprint, load_self_public_key};
|
||||
use crate::log::{error, info, warn};
|
||||
use crate::message::{Message, Viewtype};
|
||||
use crate::mimeparser::{MimeMessage, SystemMessage};
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
use anyhow::{Context as _, Result};
|
||||
|
||||
use super::qrinvite::QrInvite;
|
||||
use super::HandshakeMessage;
|
||||
use crate::chat::{self, is_contact_in_chat, ChatId, ProtectionStatus};
|
||||
use super::qrinvite::QrInvite;
|
||||
use crate::chat::{self, ChatId, ProtectionStatus, is_contact_in_chat};
|
||||
use crate::constants::{Blocked, Chattype};
|
||||
use crate::contact::Origin;
|
||||
use crate::context::Context;
|
||||
@@ -14,7 +14,7 @@ use crate::log::info;
|
||||
use crate::message::{Message, Viewtype};
|
||||
use crate::mimeparser::{MimeMessage, SystemMessage};
|
||||
use crate::param::Param;
|
||||
use crate::securejoin::{encrypted_and_signed, verify_sender_by_fingerprint, ContactId};
|
||||
use crate::securejoin::{ContactId, encrypted_and_signed, verify_sender_by_fingerprint};
|
||||
use crate::stock_str;
|
||||
use crate::sync::Sync::*;
|
||||
use crate::tools::{create_smeared_timestamp, time};
|
||||
@@ -285,7 +285,7 @@ pub(crate) async fn send_handshake_message(
|
||||
// Previous Delta Chat core also sent `Secure-Join-Group` header
|
||||
// in `vg-request` messages,
|
||||
// but it was not used on the receiver.
|
||||
if let QrInvite::Group { ref grpid, .. } = invite {
|
||||
if let QrInvite::Group { grpid, .. } = invite {
|
||||
msg.param.set(Param::Arg4, grpid);
|
||||
}
|
||||
}
|
||||
@@ -346,11 +346,7 @@ async fn joining_chat_id(
|
||||
) -> Result<ChatId> {
|
||||
match invite {
|
||||
QrInvite::Contact { .. } => Ok(alice_chat_id),
|
||||
QrInvite::Group {
|
||||
ref grpid,
|
||||
ref name,
|
||||
..
|
||||
} => {
|
||||
QrInvite::Group { grpid, name, .. } => {
|
||||
let group_chat_id = match chat::get_chat_id_by_grpid(context, grpid).await? {
|
||||
Some((chat_id, _protected, _blocked)) => {
|
||||
chat_id.unblock_ex(context, Nosync).await?;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
//! with it rather hard, so here we have a wrapper type that specifically deals with Secure-Join
|
||||
//! QR-codes so that the Secure-Join code can have more guarantees when dealing with this.
|
||||
|
||||
use anyhow::{bail, Error, Result};
|
||||
use anyhow::{Error, Result, bail};
|
||||
|
||||
use crate::contact::ContactId;
|
||||
use crate::key::Fingerprint;
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
use deltachat_contact_tools::EmailAddress;
|
||||
|
||||
use super::*;
|
||||
use crate::chat::{remove_contact_from_chat, CantSendReason};
|
||||
use crate::chat::{CantSendReason, remove_contact_from_chat};
|
||||
use crate::chatlist::Chatlist;
|
||||
use crate::constants::Chattype;
|
||||
use crate::key::self_fingerprint;
|
||||
use crate::receive_imf::receive_imf;
|
||||
use crate::stock_str::{self, chat_protection_enabled};
|
||||
use crate::test_utils::{
|
||||
get_chat_msg, TestContext, TestContextManager, TimeShiftFalsePositiveNote,
|
||||
TestContext, TestContextManager, TimeShiftFalsePositiveNote, get_chat_msg,
|
||||
};
|
||||
use crate::tools::SystemTime;
|
||||
use std::time::Duration;
|
||||
@@ -405,11 +405,12 @@ async fn test_setup_contact_concurrent_calls() -> Result<()> {
|
||||
assert!(!alice_id.is_special());
|
||||
assert_eq!(chat.typ, Chattype::Single);
|
||||
assert_ne!(claire_id, alice_id);
|
||||
assert!(bob
|
||||
.pop_sent_msg()
|
||||
.await
|
||||
.payload()
|
||||
.contains("alice@example.org"));
|
||||
assert!(
|
||||
bob.pop_sent_msg()
|
||||
.await
|
||||
.payload()
|
||||
.contains("alice@example.org")
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
+6
-5
@@ -165,11 +165,12 @@ pub(crate) fn simplify(mut input: String, is_chat_message: bool) -> SimplifiedTe
|
||||
/// a message is forwarded or not.
|
||||
fn skip_forward_header<'a>(lines: &'a [&str]) -> (&'a [&'a str], bool) {
|
||||
match lines {
|
||||
["---------- Forwarded message ----------", first_line, "", rest @ ..]
|
||||
if first_line.starts_with("From: ") =>
|
||||
{
|
||||
(rest, true)
|
||||
}
|
||||
[
|
||||
"---------- Forwarded message ----------",
|
||||
first_line,
|
||||
"",
|
||||
rest @ ..,
|
||||
] if first_line.starts_with("From: ") => (rest, true),
|
||||
_ => (lines, false),
|
||||
}
|
||||
}
|
||||
|
||||
+6
-3
@@ -3,12 +3,12 @@
|
||||
mod connect;
|
||||
pub mod send;
|
||||
|
||||
use anyhow::{bail, format_err, Context as _, Error, Result};
|
||||
use anyhow::{Context as _, Error, Result, bail, format_err};
|
||||
use async_smtp::response::{Category, Code, Detail};
|
||||
use async_smtp::{EmailAddress, SmtpTransport};
|
||||
use tokio::task;
|
||||
|
||||
use crate::chat::{add_info_msg_with_cmd, ChatId};
|
||||
use crate::chat::{ChatId, add_info_msg_with_cmd};
|
||||
use crate::config::Config;
|
||||
use crate::contact::{Contact, ContactId};
|
||||
use crate::context::Context;
|
||||
@@ -231,7 +231,10 @@ pub(crate) async fn smtp_send(
|
||||
};
|
||||
|
||||
if maybe_transient {
|
||||
info!(context, "Permanent error that is likely to actually be transient, postponing retry for later.");
|
||||
info!(
|
||||
context,
|
||||
"Permanent error that is likely to actually be transient, postponing retry for later."
|
||||
);
|
||||
SendResult::Retry
|
||||
} else {
|
||||
info!(context, "Permanent error, message sending failed.");
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
use std::net::SocketAddr;
|
||||
|
||||
use anyhow::{bail, Context as _, Result};
|
||||
use anyhow::{Context as _, Result, bail};
|
||||
use async_smtp::{SmtpClient, SmtpTransport};
|
||||
use tokio::io::{AsyncBufRead, AsyncWrite, BufStream};
|
||||
|
||||
|
||||
+4
-4
@@ -3,8 +3,8 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use anyhow::{bail, Context as _, Result};
|
||||
use rusqlite::{config::DbConfig, types::ValueRef, Connection, OpenFlags, Row};
|
||||
use anyhow::{Context as _, Result, bail};
|
||||
use rusqlite::{Connection, OpenFlags, Row, config::DbConfig, types::ValueRef};
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
use crate::blob::BlobObject;
|
||||
@@ -16,14 +16,14 @@ use crate::debug_logging::set_debug_logging_xdc;
|
||||
use crate::ephemeral::start_ephemeral_timers;
|
||||
use crate::imex::BLOBS_BACKUP_NAME;
|
||||
use crate::location::delete_orphaned_poi_locations;
|
||||
use crate::log::{error, info, warn, LogExt};
|
||||
use crate::log::{LogExt, error, info, warn};
|
||||
use crate::message::{Message, MsgId};
|
||||
use crate::net::dns::prune_dns_cache;
|
||||
use crate::net::http::http_cache_cleanup;
|
||||
use crate::net::prune_connection_history;
|
||||
use crate::param::{Param, Params};
|
||||
use crate::stock_str;
|
||||
use crate::tools::{delete_file, time, SystemTime};
|
||||
use crate::tools::{SystemTime, delete_file, time};
|
||||
|
||||
/// Extension to [`rusqlite::ToSql`] trait
|
||||
/// which also includes [`Send`] and [`Sync`].
|
||||
|
||||
+22
-7
@@ -4,9 +4,9 @@ use std::collections::BTreeMap;
|
||||
use std::collections::BTreeSet;
|
||||
use std::time::Instant;
|
||||
|
||||
use anyhow::{ensure, Context as _, Result};
|
||||
use deltachat_contact_tools::addr_cmp;
|
||||
use anyhow::{Context as _, Result, ensure};
|
||||
use deltachat_contact_tools::EmailAddress;
|
||||
use deltachat_contact_tools::addr_cmp;
|
||||
use pgp::composed::SignedPublicKey;
|
||||
use rusqlite::OptionalExtension;
|
||||
|
||||
@@ -1521,7 +1521,10 @@ fn migrate_key_contacts(
|
||||
context,
|
||||
"Created key-contacts identified by autocrypt key: {autocrypt_key_contacts:?}"
|
||||
);
|
||||
info!(context, "Created key-contacts with 'reset' peerstate identified by autocrypt key: {autocrypt_key_contacts_with_reset_peerstate:?}");
|
||||
info!(
|
||||
context,
|
||||
"Created key-contacts with 'reset' peerstate identified by autocrypt key: {autocrypt_key_contacts_with_reset_peerstate:?}"
|
||||
);
|
||||
info!(
|
||||
context,
|
||||
"Created key-contacts identified by verified key: {verified_key_contacts:?}"
|
||||
@@ -1538,7 +1541,10 @@ fn migrate_key_contacts(
|
||||
match verified_key_contacts.get(&verifier_original_contact) {
|
||||
Some(v) => *v,
|
||||
None => {
|
||||
warn!(context, "Couldn't find key-contact for {verifier_original_contact} who verified {new_contact}");
|
||||
warn!(
|
||||
context,
|
||||
"Couldn't find key-contact for {verifier_original_contact} who verified {new_contact}"
|
||||
);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -1630,7 +1636,10 @@ fn migrate_key_contacts(
|
||||
.context("Step 26")?;
|
||||
|
||||
let mut keep_address_contacts = |reason: &str| {
|
||||
info!(context, "Chat {chat_id} will be an unencrypted chat with contacts identified by email address: {reason}");
|
||||
info!(
|
||||
context,
|
||||
"Chat {chat_id} will be an unencrypted chat with contacts identified by email address: {reason}"
|
||||
);
|
||||
for m in &old_members {
|
||||
orphaned_contacts.remove(m);
|
||||
}
|
||||
@@ -1645,7 +1654,10 @@ fn migrate_key_contacts(
|
||||
// and the effect will be the same.
|
||||
100 => {
|
||||
let Some(old_member) = old_members.first() else {
|
||||
info!(context, "1:1 chat {chat_id} doesn't contain contact, probably it's self or device chat");
|
||||
info!(
|
||||
context,
|
||||
"1:1 chat {chat_id} doesn't contain contact, probably it's self or device chat"
|
||||
);
|
||||
continue;
|
||||
};
|
||||
|
||||
@@ -1778,7 +1790,10 @@ fn migrate_key_contacts(
|
||||
update_member_stmt.execute((new_member, old_member, chat_id))?;
|
||||
}
|
||||
} else {
|
||||
info!(context, "Old member {old_member} in chat {chat_id} can't be upgraded to key-contact, removing them");
|
||||
info!(
|
||||
context,
|
||||
"Old member {old_member} in chat {chat_id} can't be upgraded to key-contact, removing them"
|
||||
);
|
||||
transaction
|
||||
.execute(
|
||||
"DELETE FROM chats_contacts WHERE contact_id=? AND chat_id=?",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use super::*;
|
||||
use crate::{test_utils::TestContext, EventType};
|
||||
use crate::{EventType, test_utils::TestContext};
|
||||
|
||||
#[test]
|
||||
fn test_maybe_add_file() {
|
||||
|
||||
+2
-2
@@ -3,8 +3,8 @@
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
use humansize::{format_size, BINARY};
|
||||
use anyhow::{Result, bail};
|
||||
use humansize::{BINARY, format_size};
|
||||
use strum::EnumProperty as EnumPropertyTrait;
|
||||
use strum_macros::EnumProperty;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
@@ -28,16 +28,18 @@ async fn test_set_stock_translation() {
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn test_set_stock_translation_wrong_replacements() {
|
||||
let t = TestContext::new().await;
|
||||
assert!(t
|
||||
.ctx
|
||||
.set_stock_translation(StockMessage::NoMessages, "xyz %1$s ".to_string())
|
||||
.await
|
||||
.is_err());
|
||||
assert!(t
|
||||
.ctx
|
||||
.set_stock_translation(StockMessage::NoMessages, "xyz %2$s ".to_string())
|
||||
.await
|
||||
.is_err());
|
||||
assert!(
|
||||
t.ctx
|
||||
.set_stock_translation(StockMessage::NoMessages, "xyz %1$s ".to_string())
|
||||
.await
|
||||
.is_err()
|
||||
);
|
||||
assert!(
|
||||
t.ctx
|
||||
.set_stock_translation(StockMessage::NoMessages, "xyz %2$s ".to_string())
|
||||
.await
|
||||
.is_err()
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
|
||||
+1
-1
@@ -332,7 +332,7 @@ mod tests {
|
||||
use anyhow::bail;
|
||||
|
||||
use super::*;
|
||||
use crate::chat::{remove_contact_from_chat, Chat, ProtectionStatus};
|
||||
use crate::chat::{Chat, ProtectionStatus, remove_contact_from_chat};
|
||||
use crate::chatlist::Chatlist;
|
||||
use crate::contact::{Contact, Origin};
|
||||
use crate::securejoin::get_securejoin_qr;
|
||||
|
||||
+17
-14
@@ -15,26 +15,26 @@ use deltachat_contact_tools::{ContactAddress, EmailAddress};
|
||||
use nu_ansi_term::Color;
|
||||
use pretty_assertions::assert_eq;
|
||||
use rand::Rng;
|
||||
use tempfile::{tempdir, TempDir};
|
||||
use tempfile::{TempDir, tempdir};
|
||||
use tokio::runtime::Handle;
|
||||
use tokio::{fs, task};
|
||||
|
||||
use crate::chat::{
|
||||
self, add_to_chat_contacts_table, create_group_chat, Chat, ChatId, ChatIdBlocked,
|
||||
MessageListOptions, ProtectionStatus,
|
||||
self, Chat, ChatId, ChatIdBlocked, MessageListOptions, ProtectionStatus,
|
||||
add_to_chat_contacts_table, create_group_chat,
|
||||
};
|
||||
use crate::chatlist::Chatlist;
|
||||
use crate::config::Config;
|
||||
use crate::constants::{Blocked, Chattype};
|
||||
use crate::constants::{DC_CHAT_ID_TRASH, DC_GCL_NO_SPECIALS};
|
||||
use crate::contact::{
|
||||
import_vcard, make_vcard, mark_contact_id_as_verified, Contact, ContactId, Modifier, Origin,
|
||||
Contact, ContactId, Modifier, Origin, import_vcard, make_vcard, mark_contact_id_as_verified,
|
||||
};
|
||||
use crate::context::Context;
|
||||
use crate::events::{Event, EventEmitter, EventType, Events};
|
||||
use crate::key::{self, self_fingerprint, DcKey, DcSecretKey};
|
||||
use crate::key::{self, DcKey, DcSecretKey, self_fingerprint};
|
||||
use crate::log::warn;
|
||||
use crate::message::{update_msg_state, Message, MessageState, MsgId, Viewtype};
|
||||
use crate::message::{Message, MessageState, MsgId, Viewtype, update_msg_state};
|
||||
use crate::mimeparser::{MimeMessage, SystemMessage};
|
||||
use crate::pgp::KeyPair;
|
||||
use crate::receive_imf::receive_imf;
|
||||
@@ -143,7 +143,8 @@ impl TestContextManager {
|
||||
) -> Message {
|
||||
let received_msg = self.send_recv(from, to, msg).await;
|
||||
assert_eq!(
|
||||
received_msg.chat_blocked, Blocked::Request,
|
||||
received_msg.chat_blocked,
|
||||
Blocked::Request,
|
||||
"`send_recv_accept()` is meant to be used for chat requests. Use `send_recv()` if the chat is already accepted."
|
||||
);
|
||||
received_msg.chat_id.accept(to).await.unwrap();
|
||||
@@ -418,7 +419,7 @@ impl TestContext {
|
||||
async fn new_internal(name: Option<String>, log_sink: Option<LogSink>) -> Self {
|
||||
let dir = tempdir().unwrap();
|
||||
let dbfile = dir.path().join("db.sqlite");
|
||||
let id = rand::thread_rng().gen();
|
||||
let id = rand::thread_rng().r#gen();
|
||||
if let Some(name) = name {
|
||||
let mut context_names = CONTEXT_NAMES.write().unwrap();
|
||||
context_names.insert(id, name);
|
||||
@@ -866,11 +867,13 @@ impl TestContext {
|
||||
|
||||
pub async fn assert_no_chat(&self, id: ChatId) {
|
||||
assert!(Chat::load_from_db(self, id).await.is_err());
|
||||
assert!(!self
|
||||
.sql
|
||||
.exists("SELECT COUNT(*) FROM chats WHERE id=?", (id,))
|
||||
.await
|
||||
.unwrap());
|
||||
assert!(
|
||||
!self
|
||||
.sql
|
||||
.exists("SELECT COUNT(*) FROM chats WHERE id=?", (id,))
|
||||
.await
|
||||
.unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
/// Sends out the text message.
|
||||
@@ -1311,7 +1314,7 @@ impl EventTracker {
|
||||
/// Consumes events looking for an [`EventType::Info`] with substring matching.
|
||||
pub async fn get_info_contains(&self, s: &str) -> EventType {
|
||||
self.get_matching(|evt| match evt {
|
||||
EventType::Info(ref msg) => msg.contains(s),
|
||||
EventType::Info(msg) => msg.contains(s),
|
||||
_ => false,
|
||||
})
|
||||
.await
|
||||
|
||||
@@ -5,11 +5,11 @@ use std::time::Duration;
|
||||
use anyhow::Result;
|
||||
use tempfile::tempdir;
|
||||
|
||||
use crate::EventType;
|
||||
use crate::accounts::Accounts;
|
||||
use crate::config::Config;
|
||||
use crate::imex::{get_backup, has_backup, imex, BackupProvider, ImexMode};
|
||||
use crate::test_utils::{sync, EventTracker, TestContext, TestContextManager};
|
||||
use crate::EventType;
|
||||
use crate::imex::{BackupProvider, ImexMode, get_backup, has_backup, imex};
|
||||
use crate::test_utils::{EventTracker, TestContext, TestContextManager, sync};
|
||||
|
||||
async fn wait_for_item_changed(context: &TestContext) {
|
||||
context
|
||||
|
||||
+1
-1
@@ -14,9 +14,9 @@ use crate::contact::{Contact, ContactId};
|
||||
use crate::message::Message;
|
||||
use crate::receive_imf::receive_imf;
|
||||
use crate::securejoin::get_securejoin_qr;
|
||||
use crate::test_utils::mark_as_verified;
|
||||
use crate::test_utils::TestContext;
|
||||
use crate::test_utils::TestContextManager;
|
||||
use crate::test_utils::mark_as_verified;
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn test_change_primary_self_addr() -> Result<()> {
|
||||
|
||||
@@ -3,19 +3,19 @@ use pretty_assertions::assert_eq;
|
||||
|
||||
use crate::chat::resend_msgs;
|
||||
use crate::chat::{
|
||||
self, add_contact_to_chat, remove_contact_from_chat, send_msg, Chat, ProtectionStatus,
|
||||
self, Chat, ProtectionStatus, add_contact_to_chat, remove_contact_from_chat, send_msg,
|
||||
};
|
||||
use crate::config::Config;
|
||||
use crate::constants::Chattype;
|
||||
use crate::contact::{Contact, ContactId};
|
||||
use crate::key::{load_self_public_key, DcKey};
|
||||
use crate::key::{DcKey, load_self_public_key};
|
||||
use crate::message::{Message, Viewtype};
|
||||
use crate::mimefactory::MimeFactory;
|
||||
use crate::mimeparser::SystemMessage;
|
||||
use crate::receive_imf::receive_imf;
|
||||
use crate::securejoin::{get_securejoin_qr, join_securejoin};
|
||||
use crate::stock_str;
|
||||
use crate::test_utils::{get_chat_msg, mark_as_verified, TestContext, TestContextManager};
|
||||
use crate::test_utils::{TestContext, TestContextManager, get_chat_msg, mark_as_verified};
|
||||
use crate::tools::SystemTime;
|
||||
use crate::{e2ee, message};
|
||||
|
||||
|
||||
+1
-1
@@ -82,7 +82,7 @@ mod tests {
|
||||
use super::*;
|
||||
use crate::test_utils::TestContext;
|
||||
use crate::tools::{
|
||||
create_smeared_timestamp, create_smeared_timestamps, smeared_time, time, SystemTime,
|
||||
SystemTime, create_smeared_timestamp, create_smeared_timestamps, smeared_time, time,
|
||||
};
|
||||
|
||||
#[test]
|
||||
|
||||
+4
-8
@@ -20,18 +20,18 @@ pub use std::time::SystemTime as Time;
|
||||
#[cfg(not(test))]
|
||||
pub use std::time::SystemTime;
|
||||
|
||||
use anyhow::{bail, ensure, Context as _, Result};
|
||||
use anyhow::{Context as _, Result, bail, ensure};
|
||||
use base64::Engine as _;
|
||||
use chrono::{Local, NaiveDateTime, NaiveTime, TimeZone};
|
||||
use deltachat_contact_tools::EmailAddress;
|
||||
#[cfg(test)]
|
||||
pub use deltachat_time::SystemTimeTools as SystemTime;
|
||||
use futures::TryStreamExt;
|
||||
use mailparse::MailHeaderMap;
|
||||
use mailparse::dateparse;
|
||||
use mailparse::headers::Headers;
|
||||
use mailparse::MailHeaderMap;
|
||||
use num_traits::PrimInt;
|
||||
use rand::{thread_rng, Rng};
|
||||
use rand::{Rng, thread_rng};
|
||||
use tokio::{fs, io};
|
||||
use url::Url;
|
||||
use uuid::Uuid;
|
||||
@@ -609,11 +609,7 @@ pub(crate) trait ToOption<T> {
|
||||
}
|
||||
impl<'a> ToOption<&'a str> for &'a String {
|
||||
fn to_option(self) -> Option<&'a str> {
|
||||
if self.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(self)
|
||||
}
|
||||
if self.is_empty() { None } else { Some(self) }
|
||||
}
|
||||
}
|
||||
impl ToOption<String> for u16 {
|
||||
|
||||
+28
-21
@@ -10,20 +10,17 @@ use crate::{receive_imf::receive_imf, test_utils::TestContext};
|
||||
fn test_parse_receive_headers() {
|
||||
// Test `parse_receive_headers()` with some more-or-less random emails from the test-data
|
||||
let raw = include_bytes!("../../test-data/message/mail_with_cc.txt");
|
||||
let expected =
|
||||
"Hop: From: localhost; By: hq5.merlinux.eu; Date: Sat, 14 Sep 2019 17:00:22 +0000\n\
|
||||
let expected = "Hop: From: localhost; By: hq5.merlinux.eu; Date: Sat, 14 Sep 2019 17:00:22 +0000\n\
|
||||
Hop: From: hq5.merlinux.eu; By: hq5.merlinux.eu; Date: Sat, 14 Sep 2019 17:00:25 +0000";
|
||||
check_parse_receive_headers(raw, expected);
|
||||
|
||||
let raw = include_bytes!("../../test-data/message/wrong-html.eml");
|
||||
let expected =
|
||||
"Hop: From: oxbsltgw18.schlund.de; By: mrelayeu.kundenserver.de; Date: Thu, 6 Aug 2020 16:40:31 +0000\n\
|
||||
let expected = "Hop: From: oxbsltgw18.schlund.de; By: mrelayeu.kundenserver.de; Date: Thu, 6 Aug 2020 16:40:31 +0000\n\
|
||||
Hop: From: mout.kundenserver.de; By: dd37930.kasserver.com; Date: Thu, 6 Aug 2020 16:40:32 +0000";
|
||||
check_parse_receive_headers(raw, expected);
|
||||
|
||||
let raw = include_bytes!("../../test-data/message/posteo_ndn.eml");
|
||||
let expected =
|
||||
"Hop: By: mout01.posteo.de; Date: Tue, 9 Jun 2020 18:44:22 +0000\n\
|
||||
let expected = "Hop: By: mout01.posteo.de; Date: Tue, 9 Jun 2020 18:44:22 +0000\n\
|
||||
Hop: From: mout01.posteo.de; By: mx04.posteo.de; Date: Tue, 9 Jun 2020 18:44:22 +0000\n\
|
||||
Hop: From: mx04.posteo.de; By: mailin06.posteo.de; Date: Tue, 9 Jun 2020 18:44:23 +0000\n\
|
||||
Hop: From: mailin06.posteo.de; By: proxy02.posteo.de; Date: Tue, 9 Jun 2020 18:44:23 +0000\n\
|
||||
@@ -273,9 +270,11 @@ async fn test_file_handling() {
|
||||
};
|
||||
}
|
||||
|
||||
assert!(delete_file(context, Path::new("$BLOBDIR/lkqwjelqkwlje"))
|
||||
.await
|
||||
.is_err());
|
||||
assert!(
|
||||
delete_file(context, Path::new("$BLOBDIR/lkqwjelqkwlje"))
|
||||
.await
|
||||
.is_err()
|
||||
);
|
||||
assert!(
|
||||
write_file(context, Path::new("$BLOBDIR/foobar"), b"content")
|
||||
.await
|
||||
@@ -298,21 +297,29 @@ async fn test_file_handling() {
|
||||
|
||||
assert!(file_exist!(context, &abs_path));
|
||||
|
||||
assert!(delete_file(context, Path::new("$BLOBDIR/foobar"))
|
||||
.await
|
||||
.is_ok());
|
||||
assert!(create_folder(context, Path::new("$BLOBDIR/foobar-folder"))
|
||||
.await
|
||||
.is_ok());
|
||||
assert!(
|
||||
delete_file(context, Path::new("$BLOBDIR/foobar"))
|
||||
.await
|
||||
.is_ok()
|
||||
);
|
||||
assert!(
|
||||
create_folder(context, Path::new("$BLOBDIR/foobar-folder"))
|
||||
.await
|
||||
.is_ok()
|
||||
);
|
||||
assert!(file_exist!(context, "$BLOBDIR/foobar-folder"));
|
||||
assert!(delete_file(context, Path::new("$BLOBDIR/foobar-folder"))
|
||||
.await
|
||||
.is_err());
|
||||
assert!(
|
||||
delete_file(context, Path::new("$BLOBDIR/foobar-folder"))
|
||||
.await
|
||||
.is_err()
|
||||
);
|
||||
|
||||
let fn0 = "$BLOBDIR/data.data";
|
||||
assert!(write_file(context, Path::new(fn0), b"content")
|
||||
.await
|
||||
.is_ok());
|
||||
assert!(
|
||||
write_file(context, Path::new(fn0), b"content")
|
||||
.await
|
||||
.is_ok()
|
||||
);
|
||||
|
||||
assert!(delete_file(context, Path::new(fn0)).await.is_ok());
|
||||
assert!(!file_exist!(context, &fn0));
|
||||
|
||||
+7
-3
@@ -22,7 +22,7 @@ use std::cmp::max;
|
||||
use std::collections::HashMap;
|
||||
use std::path::Path;
|
||||
|
||||
use anyhow::{anyhow, bail, ensure, format_err, Context as _, Result};
|
||||
use anyhow::{Context as _, Result, anyhow, bail, ensure, format_err};
|
||||
|
||||
use async_zip::tokio::read::seek::ZipFileReader as SeekZipFileReader;
|
||||
use deltachat_contact_tools::sanitize_bidi_characters;
|
||||
@@ -518,7 +518,9 @@ impl Context {
|
||||
})?;
|
||||
let viewtype = instance.viewtype;
|
||||
if viewtype != Viewtype::Webxdc {
|
||||
bail!("send_webxdc_status_update: message {instance_msg_id} is not a webxdc message, but a {viewtype} message.");
|
||||
bail!(
|
||||
"send_webxdc_status_update: message {instance_msg_id} is not a webxdc message, but a {viewtype} message."
|
||||
);
|
||||
}
|
||||
|
||||
if instance.param.get_int(Param::WebxdcIntegration).is_some() {
|
||||
@@ -683,7 +685,9 @@ impl Context {
|
||||
.await?
|
||||
.with_context(|| format!("Chat type for chat {chat_id} not found"))?;
|
||||
if chat_type != Chattype::Mailinglist {
|
||||
bail!("receive_status_update: status sender {from_id} is not a member of chat {chat_id}")
|
||||
bail!(
|
||||
"receive_status_update: status sender {from_id} is not a member of chat {chat_id}"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
use std::path::Path;
|
||||
|
||||
use crate::chat::{send_msg, ChatId};
|
||||
use crate::chat::{ChatId, send_msg};
|
||||
use crate::config::Config;
|
||||
use crate::contact::ContactId;
|
||||
use crate::context::Context;
|
||||
use crate::message::{Message, MsgId, Viewtype};
|
||||
use crate::param::Param;
|
||||
use crate::webxdc::{maps_integration, StatusUpdateItem, StatusUpdateSerial};
|
||||
use crate::webxdc::{StatusUpdateItem, StatusUpdateSerial, maps_integration};
|
||||
use anyhow::Result;
|
||||
|
||||
impl Context {
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
//! ```
|
||||
|
||||
use crate::{chat, location};
|
||||
use std::collections::{hash_map, HashMap};
|
||||
use std::collections::{HashMap, hash_map};
|
||||
|
||||
use crate::context::Context;
|
||||
use crate::message::{Message, MsgId};
|
||||
@@ -169,13 +169,13 @@ pub(crate) async fn intercept_get_updates(
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::chat::{create_group_chat, ChatId, ProtectionStatus};
|
||||
use crate::chat::{ChatId, ProtectionStatus, create_group_chat};
|
||||
use crate::chatlist::Chatlist;
|
||||
use crate::contact::Contact;
|
||||
use crate::message::Message;
|
||||
use crate::test_utils::TestContext;
|
||||
use crate::webxdc::StatusUpdateSerial;
|
||||
use crate::{location, EventType};
|
||||
use crate::{EventType, location};
|
||||
use anyhow::Result;
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
|
||||
+56
-43
@@ -5,8 +5,8 @@ use serde_json::json;
|
||||
|
||||
use super::*;
|
||||
use crate::chat::{
|
||||
add_contact_to_chat, create_broadcast_list, create_group_chat, forward_msgs,
|
||||
remove_contact_from_chat, resend_msgs, send_msg, send_text_msg, ChatId, ProtectionStatus,
|
||||
ChatId, ProtectionStatus, add_contact_to_chat, create_broadcast_list, create_group_chat,
|
||||
forward_msgs, remove_contact_from_chat, resend_msgs, send_msg, send_text_msg,
|
||||
};
|
||||
use crate::chatlist::Chatlist;
|
||||
use crate::config::Config;
|
||||
@@ -296,14 +296,17 @@ async fn test_webxdc_contact_request() -> Result<()> {
|
||||
let bob_instance = bob.get_last_msg().await;
|
||||
let bob_chat = Chat::load_from_db(&bob, bob_instance.chat_id).await?;
|
||||
assert!(bob_chat.is_contact_request());
|
||||
assert!(bob_instance
|
||||
.get_webxdc_blob(&bob, "index.html")
|
||||
.await
|
||||
.is_ok());
|
||||
assert!(bob
|
||||
.send_webxdc_status_update(bob_instance.id, r#"{"payload":42}"#)
|
||||
.await
|
||||
.is_err());
|
||||
assert!(
|
||||
bob_instance
|
||||
.get_webxdc_blob(&bob, "index.html")
|
||||
.await
|
||||
.is_ok()
|
||||
);
|
||||
assert!(
|
||||
bob.send_webxdc_status_update(bob_instance.id, r#"{"payload":42}"#)
|
||||
.await
|
||||
.is_err()
|
||||
);
|
||||
assert_eq!(
|
||||
bob.get_webxdc_status_updates(bob_instance.id, StatusUpdateSerial(0))
|
||||
.await?,
|
||||
@@ -312,10 +315,11 @@ async fn test_webxdc_contact_request() -> Result<()> {
|
||||
|
||||
// Once the contact request is accepted, Bob can send updates
|
||||
bob_chat.id.accept(&bob).await?;
|
||||
assert!(bob
|
||||
.send_webxdc_status_update(bob_instance.id, r#"{"payload":42}"#)
|
||||
.await
|
||||
.is_ok());
|
||||
assert!(
|
||||
bob.send_webxdc_status_update(bob_instance.id, r#"{"payload":42}"#)
|
||||
.await
|
||||
.is_ok()
|
||||
);
|
||||
assert_eq!(
|
||||
bob.get_webxdc_status_updates(bob_instance.id, StatusUpdateSerial(0))
|
||||
.await?,
|
||||
@@ -548,15 +552,17 @@ async fn test_create_status_update_record() -> Result<()> {
|
||||
.await?;
|
||||
assert_eq!(update_id1_duplicate, None);
|
||||
|
||||
assert!(t
|
||||
.send_webxdc_status_update(instance.id, "\n\n\n")
|
||||
.await
|
||||
.is_err());
|
||||
assert!(
|
||||
t.send_webxdc_status_update(instance.id, "\n\n\n")
|
||||
.await
|
||||
.is_err()
|
||||
);
|
||||
|
||||
assert!(t
|
||||
.send_webxdc_status_update(instance.id, "bad json")
|
||||
.await
|
||||
.is_err());
|
||||
assert!(
|
||||
t.send_webxdc_status_update(instance.id, "bad json")
|
||||
.await
|
||||
.is_err()
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
t.get_webxdc_status_updates(instance.id, StatusUpdateSerial(0))
|
||||
@@ -631,12 +637,13 @@ async fn test_receive_status_update() -> Result<()> {
|
||||
let instance = send_webxdc_instance(&t, chat_id).await?;
|
||||
let now = tools::time();
|
||||
|
||||
assert!(t
|
||||
.receive_status_update(ContactId::SELF, &instance, now, true, r#"foo: bar"#)
|
||||
.await
|
||||
.is_err()); // no json
|
||||
assert!(t
|
||||
.receive_status_update(
|
||||
assert!(
|
||||
t.receive_status_update(ContactId::SELF, &instance, now, true, r#"foo: bar"#)
|
||||
.await
|
||||
.is_err()
|
||||
); // no json
|
||||
assert!(
|
||||
t.receive_status_update(
|
||||
ContactId::SELF,
|
||||
&instance,
|
||||
now,
|
||||
@@ -644,9 +651,10 @@ async fn test_receive_status_update() -> Result<()> {
|
||||
r#"{"updada":[{"payload":{"foo":"bar"}}]}"#
|
||||
)
|
||||
.await
|
||||
.is_err()); // "updates" object missing
|
||||
assert!(t
|
||||
.receive_status_update(
|
||||
.is_err()
|
||||
); // "updates" object missing
|
||||
assert!(
|
||||
t.receive_status_update(
|
||||
ContactId::SELF,
|
||||
&instance,
|
||||
now,
|
||||
@@ -654,9 +662,10 @@ async fn test_receive_status_update() -> Result<()> {
|
||||
r#"{"updates":[{"foo":"bar"}]}"#
|
||||
)
|
||||
.await
|
||||
.is_err()); // "payload" field missing
|
||||
assert!(t
|
||||
.receive_status_update(
|
||||
.is_err()
|
||||
); // "payload" field missing
|
||||
assert!(
|
||||
t.receive_status_update(
|
||||
ContactId::SELF,
|
||||
&instance,
|
||||
now,
|
||||
@@ -664,7 +673,8 @@ async fn test_receive_status_update() -> Result<()> {
|
||||
r#"{"updates":{"payload":{"foo":"bar"}}}"#
|
||||
)
|
||||
.await
|
||||
.is_err()); // not an array
|
||||
.is_err()
|
||||
); // not an array
|
||||
|
||||
t.receive_status_update(
|
||||
ContactId::SELF,
|
||||
@@ -1101,10 +1111,11 @@ async fn test_send_webxdc_status_update_to_non_webxdc() -> Result<()> {
|
||||
let t = TestContext::new_alice().await;
|
||||
let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo").await?;
|
||||
let msg_id = send_text_msg(&t, chat_id, "ho!".to_string()).await?;
|
||||
assert!(t
|
||||
.send_webxdc_status_update(msg_id, r#"{"foo":"bar"}"#)
|
||||
.await
|
||||
.is_err());
|
||||
assert!(
|
||||
t.send_webxdc_status_update(msg_id, r#"{"foo":"bar"}"#)
|
||||
.await
|
||||
.is_err()
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1118,10 +1129,12 @@ async fn test_get_webxdc_blob() -> Result<()> {
|
||||
assert_eq!(buf.len(), 188);
|
||||
assert!(String::from_utf8_lossy(&buf).contains("document.write"));
|
||||
|
||||
assert!(instance
|
||||
.get_webxdc_blob(&t, "not-existent.html")
|
||||
.await
|
||||
.is_err());
|
||||
assert!(
|
||||
instance
|
||||
.get_webxdc_blob(&t, "not-existent.html")
|
||||
.await
|
||||
.is_err()
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user