Merge branch 'master' into flub/send-backup

This commit is contained in:
Floris Bruynooghe
2023-03-07 12:52:09 +01:00
74 changed files with 270 additions and 226 deletions

View File

@@ -427,7 +427,7 @@ impl Config {
Ok(cfg)
}
/// Removes an existing acccount entirely.
/// Removes an existing account entirely.
pub async fn remove_account(&mut self, id: u32) -> Result<()> {
{
if let Some(idx) = self.inner.accounts.iter().position(|e| e.id == id) {
@@ -487,7 +487,7 @@ struct AccountConfig {
}
impl AccountConfig {
/// Get the canoncial dbfile name for this configuration.
/// Get the canonical dbfile name for this configuration.
pub fn dbfile(&self, accounts_dir: &Path) -> std::path::PathBuf {
accounts_dir.join(&self.dir).join(DB_NAME)
}

View File

@@ -235,7 +235,7 @@ mod tests {
assert!(Aheader::from_str("foo").is_err());
assert!(Aheader::from_str("\n\n\n").is_err());
assert!(Aheader::from_str(" ;;").is_err());
assert!(Aheader::from_str("addr=a@t.de; unknwon=1; keydata=jau").is_err());
assert!(Aheader::from_str("addr=a@t.de; unknown=1; keydata=jau").is_err());
}
#[test]

View File

@@ -46,7 +46,7 @@ use crate::{location, sql};
pub enum ChatItem {
/// Chat message stored in the database.
Message {
/// Database ID of the messsage.
/// Database ID of the message.
msg_id: MsgId,
},
@@ -1206,7 +1206,10 @@ impl Chat {
}
}
Err(err) => {
error!(context, "faild to load contacts for {}: {:#}", chat.id, err);
error!(
context,
"failed to load contacts for {}: {:#}", chat.id, err
);
}
}
chat.name = chat_name;
@@ -2147,7 +2150,7 @@ pub async fn is_contact_in_chat(
/// Sends a message object to a chat.
///
/// Sends the event #DC_EVENT_MSGS_CHANGED on succcess.
/// Sends the event #DC_EVENT_MSGS_CHANGED on success.
/// However, this does not imply, the message really reached the recipient -
/// sending may be delayed eg. due to network problems. However, from your
/// view, you're done with the message. Sooner or later it will find its way.
@@ -2511,7 +2514,7 @@ pub async fn get_chat_msgs_ex(
context
.sql
.query_map(
// GLOB is used here instead of LIKE becase it is case-sensitive
// GLOB is used here instead of LIKE because it is case-sensitive
"SELECT m.id AS id, m.timestamp AS timestamp, m.param AS param, m.from_id AS from_id, m.to_id AS to_id
FROM msgs m
WHERE m.chat_id=?
@@ -3662,7 +3665,7 @@ pub async fn was_device_msg_ever_added(context: &Context, label: &str) -> Result
// - deletion in `msgs` with `ContactId::DEVICE` makes sure,
// no wrong information are shown in the device chat
// - deletion in `devmsglabels` makes sure,
// deleted messages are resetted and useful messages can be added again
// deleted messages are reset and useful messages can be added again
// - we reset the config-option `QuotaExceeding`
// that is used as a helper to drive the corresponding device message.
pub(crate) async fn delete_and_reset_all_device_msgs(context: &Context) -> Result<()> {
@@ -4431,7 +4434,7 @@ mod tests {
.unwrap();
assert!(msg_id2.is_unset());
// ... unless everything is deleted and resetted - as needed eg. on device switch
// ... unless everything is deleted and reset - as needed eg. on device switch
delete_and_reset_all_device_msgs(&t).await.unwrap();
assert!(!was_device_msg_ever_added(&t, "some-label").await.unwrap());
let msg_id3 = add_device_msg(&t, Some("some-label"), Some(&mut msg))

View File

@@ -246,7 +246,7 @@ pub enum Config {
Configured,
/// All secondary self addresses separated by spaces
/// (`addr1@example.org addr2@exapmle.org addr3@example.org`)
/// (`addr1@example.org addr2@example.org addr3@example.org`)
SecondaryAddrs,
/// Read-only core version string.

View File

@@ -4,7 +4,7 @@ use crate::provider::{Protocol, Socket};
/// Set of variable parameters to try during configuration.
///
/// Can be loaded from offline provider database, online configuraiton
/// Can be loaded from offline provider database, online configuration
/// or derived from user entered parameters.
#[derive(Debug, Clone, PartialEq)]
pub(crate) struct ServerParams {

View File

@@ -103,7 +103,7 @@ pub(crate) const DC_RESEND_USER_AVATAR_DAYS: i64 = 14;
// warn about an outdated app after a given number of days.
// as we use the "provider-db generation date" as reference (that might not be updated very often)
// and as not all system get speedy updates,
// do not use too small value that will annoy users checking for nonexistant updates.
// do not use too small value that will annoy users checking for nonexistent updates.
pub(crate) const DC_OUTDATED_WARNING_DAYS: i64 = 365;
/// messages that should be deleted get this chat_id; the messages are deleted from the working thread later then. This is also needed as rfc724_mid should be preset as long as the message is not deleted on the server (otherwise it is downloaded again)

View File

@@ -115,7 +115,7 @@ impl ContextBuilder {
/// Sets the event channel for this [`Context`].
///
/// Mostly useful when using multiple [`Context`]s, this allows creating one [`Events`]
/// channel and passing it to all [`Context`]s so all events are recieved on the same
/// channel and passing it to all [`Context`]s so all events are received on the same
/// channel.
///
/// Note that the [account manager](crate::accounts::Accounts) is designed to handle the
@@ -201,7 +201,7 @@ pub struct InnerContext {
pub(crate) generating_key_mutex: Mutex<()>,
/// Mutex to enforce only a single running oauth2 is running.
pub(crate) oauth2_mutex: Mutex<()>,
/// Mutex to prevent a race condition when a "your pw is wrong" warning is sent, resulting in multiple messeges being sent.
/// Mutex to prevent a race condition when a "your pw is wrong" warning is sent, resulting in multiple messages being sent.
pub(crate) wrong_pw_warning_mutex: Mutex<()>,
pub(crate) translated_stockstrings: StockStrings,
pub(crate) events: Events,
@@ -239,7 +239,7 @@ pub struct InnerContext {
/// `last_error` should be used to avoid races with the event thread.
pub(crate) last_error: std::sync::RwLock<String>,
/// If debug logging is enabled, this contains all neccesary information
/// If debug logging is enabled, this contains all necessary information
pub(crate) debug_logging: RwLock<Option<DebugLogging>>,
/// QR code for currently running [`BackupProvider`].
@@ -255,7 +255,7 @@ pub struct InnerContext {
pub(crate) struct DebugLogging {
/// The message containing the logging xdc
pub(crate) msg_id: MsgId,
/// Handle to the background task responisble for sending
/// Handle to the background task responsible for sending
pub(crate) loop_handle: task::JoinHandle<()>,
/// Channel that log events should be send to
/// A background loop will receive and handle them

View File

@@ -22,7 +22,7 @@ use crate::{job_try, stock_str, EventType};
/// need to be downloaded completely to handle them correctly,
/// eg. to assign them to the correct chat.
/// As these messages are typically small,
/// they're catched by `MIN_DOWNLOAD_LIMIT`.
/// they're caught by `MIN_DOWNLOAD_LIMIT`.
const MIN_DOWNLOAD_LIMIT: u32 = 32768;
/// If a message is downloaded only partially

View File

@@ -1273,7 +1273,7 @@ mod tests {
// protection.
//
// Previously Delta Chat fallen back to using <first@example.com> in this case and
// compared received timer value to the timer value of the <first@examle.com>. Because
// compared received timer value to the timer value of the <first@example.com>. Because
// their timer values are the same ("disabled"), Delta Chat assumed that the timer was not
// changed explicitly and the change should be ignored.
//

View File

@@ -70,7 +70,7 @@ impl Events {
pub struct EventEmitter(Receiver<Event>);
impl EventEmitter {
/// Async recv of an event. Return `None` if the `Sender` has been droped.
/// Async recv of an event. Return `None` if the `Sender` has been dropped.
pub async fn recv(&self) -> Option<Event> {
self.0.recv().await.ok()
}
@@ -89,7 +89,7 @@ impl futures::stream::Stream for EventEmitter {
/// The event emitted by a [`Context`] from an [`EventEmitter`].
///
/// Events are documented on the C/FFI API in `deltachat.h` as `DC_EVENT_*` contants. The
/// Events are documented on the C/FFI API in `deltachat.h` as `DC_EVENT_*` constants. The
/// context emits them in relation to various operations happening, a lot of these are again
/// documented in `deltachat.h`.
///

View File

@@ -5,7 +5,7 @@
/// Fuzzing target for simplify().
///
/// Calls simplify() and panics if simplify() panics.
/// Does not return any vaule to avoid exposing internal crate types.
/// Does not return any value to avoid exposing internal crate types.
#[cfg(fuzzing)]
pub fn simplify(input: String, is_chat_message: bool) {
crate::simplify::simplify(input, is_chat_message);

View File

@@ -1394,7 +1394,7 @@ impl Imap {
// Check if FETCH response is already in `uid_msgs`.
let mut fetch_response = uid_msgs.remove(&request_uid);
// Try to find a requsted UID in returned FETCH responses.
// 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 {
@@ -2204,11 +2204,11 @@ async fn mark_seen_by_uid(
.with_context(|| format!("failed to start ephemeral timer for message {msg_id}"))?;
Ok(Some(chat_id))
} else {
// Message state has not chnaged.
// Message state has not changed.
Ok(None)
}
} else {
// There is no message is `msgs` table matchng the given UID.
// There is no message is `msgs` table matching the given UID.
Ok(None)
}
}

View File

@@ -38,7 +38,7 @@ pub use transfer::{get_backup, BackupProvider};
// Name of the database file in the backup.
const DBFILE_BACKUP_NAME: &str = "dc_database_backup.sqlite";
const BLOBS_BACKUP_NAME: &str = "blobs_backup";
pub(crate) const BLOBS_BACKUP_NAME: &str = "blobs_backup";
/// Import/export command.
#[derive(Debug, Display, Copy, Clone, PartialEq, Eq, FromPrimitive, ToPrimitive)]
@@ -253,7 +253,7 @@ async fn maybe_add_bcc_self_device_msg(context: &Context) -> Result<()> {
// TODO: define this as a stockstring once the wording is settled.
msg.text = Some(
"It seems you are using multiple devices with Delta Chat. Great!\n\n\
If you also want to synchronize outgoing messages accross all devices, \
If you also want to synchronize outgoing messages across all devices, \
go to the settings and enable \"Send copy to self\"."
.to_string(),
);
@@ -799,7 +799,7 @@ mod tests {
println!("{}", &msg);
// Check some substrings, indicating things got substituted.
// In particular note the mixing of `\r\n` and `\n` depending
// on who generated the stings.
// on who generated the strings.
assert!(msg.contains("<title>Autocrypt Setup Message</title"));
assert!(msg.contains("<h1>Autocrypt Setup Message</h1>"));
assert!(msg.contains("<p>This is the Autocrypt Setup Message used to"));

View File

@@ -610,7 +610,7 @@ impl Message {
// It's a little unfortunate that the UI has to first call `dc_msg_get_override_sender_name` and then if it was `NULL`, call
// `dc_contact_get_display_name` but this was the best solution:
// - We could load a Contact struct from the db here to call `dc_get_display_name` instead of returning `None`, but then we had a db
// call everytime (and this fn is called a lot while the user is scrolling through a group), so performance would be bad
// call every time (and this fn is called a lot while the user is scrolling through a group), so performance would be bad
// - We could pass both a Contact struct and a Message struct in the FFI, but at least on Android we would need to handle raw
// C-data in the Java code (i.e. a `long` storing a C pointer)
// - We can't make a param `SenderDisplayname` for messages as sometimes the display name of a contact changes, and we want to show

View File

@@ -1932,7 +1932,7 @@ mod tests {
// These two combinations are different: If `message_arrives_inbetween` is true, but
// `reply` is false, the core is actually expected to use the subject of the message
// that arrived inbetween.
// that arrived in between.
assert_eq!(
"Re: Some other, completely unrelated subject",
msg_to_subject_str_inner(imf_raw, false, false, true).await

View File

@@ -357,7 +357,7 @@ impl MimeMessage {
// where this would be useful.
warn!(
context,
"From header in signed part does't match the outer one",
"From header in signed part doesn't match the outer one",
);
}
}
@@ -525,7 +525,7 @@ impl MimeMessage {
}
}
/// Squashes mutlipart chat messages with attachment into single-part messages.
/// Squashes mutitpart chat messages with attachment into single-part messages.
///
/// Delta Chat sends attachments, such as images, in two-part messages, with the first message
/// containing a description. If such a message is detected, text from the first part can be
@@ -855,9 +855,9 @@ impl MimeMessage {
let mut any_part_added = false;
let mimetype = get_mime_type(mail)?.0;
match (mimetype.type_(), mimetype.subtype().as_str()) {
/* Most times, mutlipart/alternative contains true alternatives
/* Most times, multipart/alternative contains true alternatives
as text/plain and text/html. If we find a multipart/mixed
inside mutlipart/alternative, we use this (happens eg in
inside multipart/alternative, we use this (happens eg in
apple mail: "plaintext" as an alternative to "html+PDF attachment") */
(mime::MULTIPART, "alternative") => {
for cur_data in &mail.subparts {
@@ -1682,7 +1682,7 @@ impl MimeMessage {
/// Parses `Autocrypt-Gossip` headers from the email and applies them to peerstates.
/// Params:
/// from: The address which sent the message currently beeing parsed
/// from: The address which sent the message currently being parsed
///
/// Returns the set of mail recipient addresses for which valid gossip headers were found.
async fn update_gossip_peerstates(

View File

@@ -23,7 +23,7 @@ pub enum Param {
/// For messages: This name should be shown instead of contact.get_display_name()
/// (used if this is a mailinglist
/// or explictly set using set_override_sender_name(), eg. by bots)
/// or explicitly set using set_override_sender_name(), eg. by bots)
OverrideSenderDisplayname = b'O',
/// For Messages
@@ -129,7 +129,7 @@ pub enum Param {
ProfileImage = b'i',
/// For Chats
/// Signals wheter the chat is the `saved messages` chat
/// Signals whether the chat is the `saved messages` chat
Selftalk = b'K',
/// For Chats: On sending a new message we set the subject to `Re: <last subject>`.
@@ -341,7 +341,7 @@ impl Params {
/// returned.
///
/// Note that in the [ParamsFile::FsPath] case the blob can be
/// created without copying if the path already referes to a valid
/// created without copying if the path already refers to a valid
/// blob. If so a [BlobObject] will be returned regardless of the
/// `create` argument.
#[allow(clippy::needless_lifetimes)]
@@ -389,13 +389,13 @@ impl Params {
.map(MsgId::new)
}
/// Set the given paramter to the passed in `i32`.
/// Set the given parameter to the passed in `i32`.
pub fn set_int(&mut self, key: Param, value: i32) -> &mut Self {
self.set(key, format!("{value}"));
self
}
/// Set the given paramter to the passed in `i64`.
/// Set the given parameter to the passed in `i64`.
pub fn set_i64(&mut self, key: Param, value: i64) -> &mut Self {
self.set(key, value.to_string());
self

View File

@@ -595,7 +595,7 @@ impl Peerstate {
Err(err) => {
warn!(
context,
"New address {:?} is not vaild, not doing AEAP: {:#}.",
"New address {:?} is not valid, not doing AEAP: {:#}.",
new_addr,
err
)

View File

@@ -480,7 +480,7 @@ mod tests {
static CTEXT_SIGNED: OnceCell<String> = OnceCell::const_new();
static CTEXT_UNSIGNED: OnceCell<String> = OnceCell::const_new();
/// A cyphertext encrypted to Alice & Bob, signed by Alice.
/// A ciphertext encrypted to Alice & Bob, signed by Alice.
async fn ctext_signed() -> &'static String {
CTEXT_SIGNED
.get_or_init(|| async {
@@ -495,7 +495,7 @@ mod tests {
.await
}
/// A cyphertext encrypted to Alice & Bob, not signed.
/// A ciphertext encrypted to Alice & Bob, not signed.
async fn ctext_unsigned() -> &'static String {
CTEXT_UNSIGNED
.get_or_init(|| async {

View File

@@ -124,7 +124,7 @@ fn inner_generate_secure_join_qr_code(
Ok(())
})?
.build(|w| {
// White Background apears like a card
// White Background appears like a card
w.single("rect", |d| {
d.attr("x", card_border_size)?;
d.attr("y", card_border_size)?;

View File

@@ -68,7 +68,7 @@ async fn get_unique_quota_roots_and_usage(
.cloned()
.context("quota_root should have a quota")?;
// replace old quotas, because between fetching quotaroots for folders,
// messages could be recieved and so the usage could have been changed
// messages could be received and so the usage could have been changed
*unique_quota_roots
.entry(quota_root_name.clone())
.or_insert_with(Vec::new) = quota.resources;

View File

@@ -30,7 +30,7 @@ use crate::message::{rfc724_mid_exists, Message, MsgId, Viewtype};
/// It is guaranteed to have all emojis sorted and deduplicated inside.
#[derive(Debug, Default, Clone)]
pub struct Reaction {
/// Canonical represntation of reaction as a string of space-separated emojis.
/// Canonical representation of reaction as a string of space-separated emojis.
reaction: String,
}
@@ -195,7 +195,7 @@ pub async fn send_reaction(context: &Context, msg_id: MsgId, reaction: &str) ->
reaction_msg.in_reply_to = Some(msg.rfc724_mid);
reaction_msg.hidden = true;
// Send messsage first.
// Send message first.
let reaction_msg_id = send_msg(context, chat_id, &mut reaction_msg).await?;
// Only set reaction if we successfully sent the message.

View File

@@ -150,7 +150,7 @@ pub(crate) async fn receive_imf_inner(
if let Some(old_msg_id) = message::rfc724_mid_exists(context, rfc724_mid).await? {
let msg = Message::load_from_db(context, old_msg_id).await?;
if msg.download_state() != DownloadState::Done && is_partial_download.is_none() {
// the mesage was partially downloaded before and is fully downloaded now.
// the message was partially downloaded before and is fully downloaded now.
info!(
context,
"Message already partly in DB, replacing by full message."
@@ -422,7 +422,7 @@ pub async fn from_field_to_contact_id(
}
/// Creates a `ReceivedMsg` from given parts which might consist of
/// mulitple messages (if there are multiple attachments).
/// multiple messages (if there are multiple attachments).
/// Every entry in `mime_parser.parts` produces a new row in the `msgs` table.
#[allow(clippy::too_many_arguments, clippy::cognitive_complexity)]
async fn add_parts(
@@ -550,7 +550,7 @@ async fn add_parts(
}
}
// signals wether the current user is a bot
// signals whether the current user is a bot
let is_bot = context.get_config_bool(Config::Bot).await?;
if chat_id.is_none() {
@@ -1981,7 +1981,7 @@ async fn apply_mailinglist_changes(
if let Some(old_list_post) = chat.param.get(Param::ListPost) {
if list_post.as_ref() != old_list_post {
// Apparently the mailing list is using a different List-Post header in each message.
// Make the mailing list read-only because we would't know which message the user wants to reply to.
// Make the mailing list read-only because we wouldn't know which message the user wants to reply to.
chat.param.remove(Param::ListPost);
chat.update_param(context).await?;
}
@@ -2296,7 +2296,7 @@ pub(crate) async fn get_prefetch_parent_message(
///
/// * param `prevent_rename`: if true, the display_name of this contact will not be changed. Useful for
/// mailing lists: In some mailing lists, many users write from the same address but with different
/// display names. We don't want the display name to change everytime the user gets a new email from
/// display names. We don't want the display name to change every time the user gets a new email from
/// a mailing list.
async fn add_or_lookup_contacts_by_address_list(
context: &Context,

View File

@@ -2485,7 +2485,7 @@ Reply to all"#,
/// Tests that replies to similar ad hoc groups are correctly assigned to chats.
///
/// The difficutly here is that ad hoc groups don't have unique group IDs, because both
/// The difficulty here is that ad hoc groups don't have unique group IDs, because both
/// messages have the same recipient lists and only differ in the subject and message contents.
/// The messages can be properly assigned to chats only using the In-Reply-To or References
/// headers.

View File

@@ -539,7 +539,7 @@ impl SecureJoinStep {
false
}
SecureJoinStep::Completed => {
warn!(context, "Complted state for next securejoin step");
warn!(context, "Completed state for next securejoin step");
false
}
}

View File

@@ -436,7 +436,7 @@ pub(crate) async fn smtp_send(
// Any extended smtp status codes like x.1.1, x.1.2 or x.1.3 that we
// receive as a transient error are misconfigurations of the smtp server.
// See <https://tools.ietf.org/html/rfc3463#section-3.2>
info!(context, "Received extended status code {} for a transient error. This looks like a misconfigured smtp server, let's fail immediatly", first_word);
info!(context, "Received extended status code {} for a transient error. This looks like a misconfigured SMTP server, let's fail immediately", first_word);
SendResult::Failure(format_err!("Permanent SMTP error: {}", err))
} else {
info!(
@@ -656,7 +656,7 @@ pub(crate) async fn send_smtp_messages(context: &Context, connection: &mut Smtp)
}
// although by slow sending, ratelimit may have been expired meanwhile,
// do not attempt to send MDNs if ratelimited happend before on status-updates/sync:
// do not attempt to send MDNs if ratelimited happened before on status-updates/sync:
// instead, let the caller recall this function so that more important status-updates/sync are sent out.
if !ratelimited {
send_mdns(context, connection)

View File

@@ -9,7 +9,7 @@ use crate::events::EventType;
pub type Result<T> = std::result::Result<T, Error>;
// if more recipients are needed in SMTP's `RCPT TO:` header, recipient-list is splitted to chunks.
// if more recipients are needed in SMTP's `RCPT TO:` header, recipient-list is split to chunks.
// this does not affect MIME'e `To:` header.
// can be overwritten by the setting `max_smtp_rcpt_to` in provider-db.
pub(crate) const DEFAULT_MAX_SMTP_RCPT_TO: usize = 50;

View File

@@ -15,6 +15,7 @@ use crate::constants::DC_CHAT_ID_TRASH;
use crate::context::Context;
use crate::debug_logging::set_debug_logging_xdc;
use crate::ephemeral::start_ephemeral_timers;
use crate::imex::BLOBS_BACKUP_NAME;
use crate::log::LogExt;
use crate::message::{Message, MsgId, Viewtype};
use crate::param::{Param, Params};
@@ -686,7 +687,7 @@ pub async fn housekeeping(context: &Context) -> Result<()> {
if let Err(err) = remove_unused_files(context).await {
warn!(
context,
"Housekeeping: cannot remove unusued files: {:#}", err
"Housekeeping: cannot remove unused files: {:#}", err
);
}
@@ -792,74 +793,93 @@ pub async fn remove_unused_files(context: &Context) -> Result<()> {
.context("housekeeping: failed to SELECT value FROM config")?;
info!(context, "{} files in use.", files_in_use.len(),);
/* go through directory and delete unused files */
let p = context.get_blobdir();
match tokio::fs::read_dir(p).await {
Ok(mut dir_handle) => {
/* avoid deletion of files that are just created to build a message object */
let diff = std::time::Duration::from_secs(60 * 60);
let keep_files_newer_than = std::time::SystemTime::now()
.checked_sub(diff)
.unwrap_or(std::time::SystemTime::UNIX_EPOCH);
/* go through directories and delete unused files */
let blobdir = context.get_blobdir();
for p in [&blobdir.join(BLOBS_BACKUP_NAME), blobdir] {
match tokio::fs::read_dir(p).await {
Ok(mut dir_handle) => {
/* avoid deletion of files that are just created to build a message object */
let diff = std::time::Duration::from_secs(60 * 60);
let keep_files_newer_than = std::time::SystemTime::now()
.checked_sub(diff)
.unwrap_or(std::time::SystemTime::UNIX_EPOCH);
while let Ok(Some(entry)) = dir_handle.next_entry().await {
let name_f = entry.file_name();
let name_s = name_f.to_string_lossy();
while let Ok(Some(entry)) = dir_handle.next_entry().await {
let name_f = entry.file_name();
let name_s = name_f.to_string_lossy();
if is_file_in_use(&files_in_use, None, &name_s)
|| is_file_in_use(&files_in_use, Some(".increation"), &name_s)
|| is_file_in_use(&files_in_use, Some(".waveform"), &name_s)
|| is_file_in_use(&files_in_use, Some("-preview.jpg"), &name_s)
{
continue;
}
unreferenced_count += 1;
if let Ok(stats) = tokio::fs::metadata(entry.path()).await {
let recently_created =
stats.created().map_or(false, |t| t > keep_files_newer_than);
let recently_modified = stats
.modified()
.map_or(false, |t| t > keep_files_newer_than);
let recently_accessed = stats
.accessed()
.map_or(false, |t| t > keep_files_newer_than);
if recently_created || recently_modified || recently_accessed {
info!(
context,
"Housekeeping: Keeping new unreferenced file #{}: {:?}",
unreferenced_count,
entry.file_name(),
);
if p == blobdir
&& (is_file_in_use(&files_in_use, None, &name_s)
|| is_file_in_use(&files_in_use, Some(".increation"), &name_s)
|| is_file_in_use(&files_in_use, Some(".waveform"), &name_s)
|| is_file_in_use(&files_in_use, Some("-preview.jpg"), &name_s))
{
continue;
}
}
info!(
context,
"Housekeeping: Deleting unreferenced file #{}: {:?}",
unreferenced_count,
entry.file_name()
);
let path = entry.path();
if let Err(err) = delete_file(context, &path).await {
error!(
if let Ok(stats) = tokio::fs::metadata(entry.path()).await {
if stats.is_dir() {
if let Err(e) = tokio::fs::remove_dir(entry.path()).await {
// The dir could be created not by a user, but by a desktop
// environment f.e. So, no warning.
info!(
context,
"Housekeeping: Cannot rmdir {}: {:#}",
entry.path().display(),
e
);
}
continue;
}
unreferenced_count += 1;
let recently_created =
stats.created().map_or(false, |t| t > keep_files_newer_than);
let recently_modified = stats
.modified()
.map_or(false, |t| t > keep_files_newer_than);
let recently_accessed = stats
.accessed()
.map_or(false, |t| t > keep_files_newer_than);
if p == blobdir
&& (recently_created || recently_modified || recently_accessed)
{
info!(
context,
"Housekeeping: Keeping new unreferenced file #{}: {:?}",
unreferenced_count,
entry.file_name(),
);
continue;
}
} else {
unreferenced_count += 1;
}
info!(
context,
"Failed to delete unused file {}: {:#}.",
path.display(),
err
"Housekeeping: Deleting unreferenced file #{}: {:?}",
unreferenced_count,
entry.file_name()
);
let path = entry.path();
if let Err(err) = delete_file(context, &path).await {
error!(
context,
"Failed to delete unused file {}: {:#}.",
path.display(),
err
);
}
}
}
}
Err(err) => {
warn!(
context,
"Housekeeping: Cannot open {}. ({})",
context.get_blobdir().display(),
err
);
Err(err) => {
warn!(
context,
"Housekeeping: Cannot read dir {}: {:#}",
p.display(),
err
);
}
}
}
@@ -1061,6 +1081,18 @@ mod tests {
assert_eq!(loaded_draft.unwrap().text.unwrap(), "This is my draft");
}
/// Tests that `housekeeping` deletes the blobs backup dir which is created normally by
/// `imex::import_backup`.
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_housekeeping_delete_blobs_backup_dir() {
let t = TestContext::new_alice().await;
let dir = t.get_blobdir().join(BLOBS_BACKUP_NAME);
tokio::fs::create_dir(&dir).await.unwrap();
tokio::fs::write(dir.join("f"), "").await.unwrap();
housekeeping(&t).await.unwrap();
tokio::fs::create_dir(&dir).await.unwrap();
}
/// Regression test.
///
/// Previously the code checking for existence of `config` table

View File

@@ -804,7 +804,7 @@ pub(crate) async fn sync_msg_subject(context: &Context) -> String {
translated(context, StockMessage::SyncMsgSubject).await
}
/// Stock string: `This message is used to synchronize data betweeen your devices.`.
/// Stock string: `This message is used to synchronize data between your devices.`.
pub(crate) async fn sync_msg_body(context: &Context) -> String {
translated(context, StockMessage::SyncMsgBody).await
}

View File

@@ -53,7 +53,7 @@ pub struct Summary {
}
impl Summary {
/// Constucts chatlist summary
/// Constructs chatlist summary
/// from the provided message, chat and message author contact snapshots.
pub async fn new(
context: &Context,

View File

@@ -434,9 +434,9 @@ mod tests {
.parse_sync_items(
r#"{"items":[
{"timestamp":1631781316,"data":{"AddQrToken":{"invitenumber":"yip-in","auth":"a"}}},
{"timestamp":1631781316,"data":{"DeleteQrToken":{"invitenumber":"in","auth":"delete unexistant, shall continue"}}},
{"timestamp":1631781316,"data":{"DeleteQrToken":{"invitenumber":"in","auth":"delete unexistent, shall continue"}}},
{"timestamp":1631781316,"data":{"AddQrToken":{"invitenumber":"in","auth":"yip-auth"}}},
{"timestamp":1631781316,"data":{"AddQrToken":{"invitenumber":"in","auth":"foo","grpid":"non-existant"}}},
{"timestamp":1631781316,"data":{"AddQrToken":{"invitenumber":"in","auth":"foo","grpid":"non-existent"}}},
{"timestamp":1631781316,"data":{"AddQrToken":{"invitenumber":"in","auth":"directly deleted"}}},
{"timestamp":1631781316,"data":{"DeleteQrToken":{"invitenumber":"in","auth":"directly deleted"}}}
]}"#
@@ -447,7 +447,7 @@ mod tests {
assert!(token::exists(&t, Namespace::InviteNumber, "yip-in").await);
assert!(token::exists(&t, Namespace::Auth, "yip-auth").await);
assert!(!token::exists(&t, Namespace::Auth, "non-existant").await);
assert!(!token::exists(&t, Namespace::Auth, "non-existent").await);
assert!(!token::exists(&t, Namespace::Auth, "directly deleted").await);
Ok(())

View File

@@ -1,7 +1,7 @@
//! # Time smearing.
//!
//! As e-mails typically only use a second-based-resolution for timestamps,
//! the order of two mails sent withing one second is unclear.
//! the order of two mails sent within one second is unclear.
//! This is bad e.g. when forwarding some messages from a chat -
//! these messages will appear at the recipient easily out of order.
//!

View File

@@ -387,7 +387,7 @@ pub(crate) async fn create_folder(
}
}
/// Write a the given content to provied file path.
/// Write a the given content to provided file path.
pub(crate) async fn write_file(
context: &Context,
path: impl AsRef<Path>,

View File

@@ -658,7 +658,7 @@ async fn get_blob(archive: &mut async_zip::read::fs::ZipFileReader, name: &str)
impl Message {
/// Get handle to a webxdc ZIP-archive.
/// To check for file existance use archive.by_name(), to read a file, use get_blob(archive).
/// To check for file existence use archive.by_name(), to read a file, use get_blob(archive).
async fn get_webxdc_archive(
&self,
context: &Context,