From 7de58f5329115f19d0f03690212752d7db53fdf6 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Sat, 25 Apr 2026 01:31:20 +0200 Subject: [PATCH] feat: adapt quota warning to automatic cleanup --- deltachat-ffi/deltachat.h | 9 +-- src/chat.rs | 5 -- src/config.rs | 5 -- src/context.rs | 6 -- src/quota.rs | 98 +------------------------------- src/stock_str.rs | 16 ------ src/stock_str/stock_str_tests.rs | 10 ---- 7 files changed, 4 insertions(+), 145 deletions(-) diff --git a/deltachat-ffi/deltachat.h b/deltachat-ffi/deltachat.h index 928332a98..783ad4f6c 100644 --- a/deltachat-ffi/deltachat.h +++ b/deltachat-ffi/deltachat.h @@ -541,9 +541,6 @@ int dc_set_config (dc_context_t* context, const char* * an error (no warning as it should be shown to the user) is logged but the attachment is sent anyway. * - `sys.config_keys` = get a space-separated list of all config-keys available. * The config-keys are the keys that can be passed to the parameter `key` of this function. - * - `quota_exceeding` = 0: quota is unknown or in normal range; - * >=80: quota is about to exceed, the value is the concrete percentage, - * a device message is added when that happens, however, that value may still be interesting for bots. * * @memberof dc_context_t * @param context The context object. For querying system values, this can be NULL. @@ -7026,11 +7023,7 @@ void dc_event_unref(dc_event_t* event); /// Used in message summary text for notifications and chatlist. #define DC_STR_FORWARDED 97 -/// "Quota exceeding, already %1$s%% used." -/// -/// Used as device message text. -/// -/// `%1$s` will be replaced by the percentage used +/// @deprecated 2026-04-25 #define DC_STR_QUOTA_EXCEEDING_MSG_BODY 98 /// "Multi Device Synchronization" diff --git a/src/chat.rs b/src/chat.rs index f5a8d8328..768ec8a02 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -4961,8 +4961,6 @@ pub async fn was_device_msg_ever_added(context: &Context, label: &str) -> Result // no wrong information are shown in the device chat // - deletion in `devmsglabels` makes sure, // 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<()> { context .sql @@ -4978,9 +4976,6 @@ pub(crate) async fn delete_and_reset_all_device_msgs(context: &Context) -> Resul (), ) .await?; - context - .set_config_internal(Config::QuotaExceeding, None) - .await?; Ok(()) } diff --git a/src/config.rs b/src/config.rs index d3143f827..7599ee44a 100644 --- a/src/config.rs +++ b/src/config.rs @@ -371,11 +371,6 @@ pub enum Config { #[strum(props(default = "0"))] NotifyAboutWrongPw, - /// If a warning about exceeding quota was shown recently, - /// this is the percentage of quota at the time the warning was given. - /// Unset, when quota falls below minimal warning threshold again. - QuotaExceeding, - /// Timestamp of the last time housekeeping was run LastHousekeeping, diff --git a/src/context.rs b/src/context.rs index 93869b84b..60fe63386 100644 --- a/src/context.rs +++ b/src/context.rs @@ -1004,12 +1004,6 @@ impl Context { .await? .to_string(), ); - res.insert( - "quota_exceeding", - self.get_config_int(Config::QuotaExceeding) - .await? - .to_string(), - ); res.insert( "authserv_id_candidates", self.get_config(Config::AuthservIdCandidates) diff --git a/src/quota.rs b/src/quota.rs index 1591fdb41..d34ebfcf0 100644 --- a/src/quota.rs +++ b/src/quota.rs @@ -6,33 +6,17 @@ use std::time::Duration; use anyhow::{Context as _, Result, anyhow}; use async_imap::types::{Quota, QuotaResource}; -use crate::chat::add_device_msg_with_importance; -use crate::config::Config; use crate::context::Context; use crate::imap::session::Session as ImapSession; -use crate::log::warn; -use crate::message::Message; use crate::tools::{self, time_elapsed}; use crate::{EventType, stock_str}; -/// warn about a nearly full mailbox after this usage percentage is reached. -/// quota icon is "yellow". +/// quota icon in connectivity is "yellow". pub const QUOTA_WARN_THRESHOLD_PERCENTAGE: u64 = 80; -/// warning again after this usage percentage is reached, -/// quota icon is "red". +/// quota icon in connectivity is "red". pub const QUOTA_ERROR_THRESHOLD_PERCENTAGE: u64 = 95; -/// if quota is below this value (again), -/// QuotaExceeding is cleared. -/// -/// This value should be a bit below QUOTA_WARN_THRESHOLD_PERCENTAGE to -/// avoid jittering and lots of warnings when quota is exactly at the warning threshold. -/// -/// We do not repeat warnings on a daily base or so as some provider -/// providers report bad values and we would then spam the user. -pub const QUOTA_ALLCLEAR_PERCENTAGE: u64 = 75; - /// Server quota information with an update timestamp. #[derive(Debug)] pub struct QuotaInfo { @@ -70,37 +54,6 @@ async fn get_unique_quota_roots_and_usage( Ok(unique_quota_roots) } -fn get_highest_usage<'t>( - unique_quota_roots: &'t BTreeMap>, -) -> Result<(u64, &'t String, &'t QuotaResource)> { - let mut highest: Option<(u64, &'t String, &QuotaResource)> = None; - for (name, resources) in unique_quota_roots { - for r in resources { - let usage_percent = r.get_usage_percentage(); - match highest { - None => { - highest = Some((usage_percent, name, r)); - } - Some((up, ..)) => { - if up <= usage_percent { - highest = Some((usage_percent, name, r)); - } - } - }; - } - } - - highest.context("no quota_resource found, this is unexpected") -} - -/// Checks if a quota warning is needed. -pub fn needs_quota_warning(curr_percentage: u64, warned_at_percentage: u64) -> bool { - (curr_percentage >= QUOTA_WARN_THRESHOLD_PERCENTAGE - && warned_at_percentage < QUOTA_WARN_THRESHOLD_PERCENTAGE) - || (curr_percentage >= QUOTA_ERROR_THRESHOLD_PERCENTAGE - && warned_at_percentage < QUOTA_ERROR_THRESHOLD_PERCENTAGE) -} - impl Context { /// Returns whether the quota value needs an update. If so, `update_recent_quota()` should be /// called. @@ -134,32 +87,6 @@ impl Context { Err(anyhow!(stock_str::not_supported_by_provider(self))) }; - if let Ok(quota) = "a { - match get_highest_usage(quota) { - Ok((highest, _, _)) => { - if needs_quota_warning( - highest, - self.get_config_int(Config::QuotaExceeding).await? as u64, - ) { - self.set_config_internal( - Config::QuotaExceeding, - Some(&highest.to_string()), - ) - .await?; - let mut msg = Message::new_text(stock_str::quota_exceeding(self, highest)); - add_device_msg_with_importance(self, None, Some(&mut msg), true).await?; - } else if highest <= QUOTA_ALLCLEAR_PERCENTAGE { - self.set_config_internal(Config::QuotaExceeding, None) - .await?; - } - } - Err(err) => warn!( - self, - "Transport {transport_id}: Cannot get highest quota usage: {err:#}" - ), - } - } - self.quota.write().await.insert( transport_id, QuotaInfo { @@ -179,29 +106,10 @@ mod tests { use super::*; use crate::test_utils::TestContextManager; - #[tokio::test(flavor = "multi_thread", worker_threads = 2)] - async fn test_needs_quota_warning() -> Result<()> { - assert!(!needs_quota_warning(0, 0)); - assert!(!needs_quota_warning(10, 0)); - assert!(!needs_quota_warning(70, 0)); - assert!(!needs_quota_warning(75, 0)); - assert!(!needs_quota_warning(79, 0)); - assert!(needs_quota_warning(80, 0)); - assert!(needs_quota_warning(81, 0)); - assert!(!needs_quota_warning(85, 80)); - assert!(!needs_quota_warning(85, 81)); - assert!(needs_quota_warning(95, 82)); - assert!(!needs_quota_warning(97, 95)); - assert!(!needs_quota_warning(97, 96)); - assert!(!needs_quota_warning(1000, 96)); - Ok(()) - } - #[expect(clippy::assertions_on_constants)] #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_quota_thresholds() -> anyhow::Result<()> { - assert!(QUOTA_ALLCLEAR_PERCENTAGE > 50); - assert!(QUOTA_ALLCLEAR_PERCENTAGE < QUOTA_WARN_THRESHOLD_PERCENTAGE); + assert!(0 < QUOTA_WARN_THRESHOLD_PERCENTAGE); assert!(QUOTA_WARN_THRESHOLD_PERCENTAGE < QUOTA_ERROR_THRESHOLD_PERCENTAGE); assert!(QUOTA_ERROR_THRESHOLD_PERCENTAGE < 100); Ok(()) diff --git a/src/stock_str.rs b/src/stock_str.rs index 32b1955b9..dd2677e23 100644 --- a/src/stock_str.rs +++ b/src/stock_str.rs @@ -153,15 +153,6 @@ pub enum StockMessage { #[strum(props(fallback = "Forwarded"))] Forwarded = 97, - #[strum(props( - fallback = "⚠️ Your provider's storage is about to exceed, already %1$s%% are used.\n\n\ - You may not be able to receive message when the storage is 100%% used.\n\n\ - 👉 Please check if you can delete old data in the provider's webinterface \ - and consider to enable \"Settings / Delete Old Messages\". \ - You can check your current storage usage anytime at \"Settings / Connectivity\"." - ))] - QuotaExceedingMsgBody = 98, - #[strum(props(fallback = "Multi Device Synchronization"))] SyncMsgSubject = 101, @@ -1100,13 +1091,6 @@ pub(crate) fn forwarded(context: &Context) -> String { translated(context, StockMessage::Forwarded) } -/// Stock string: `⚠️ Your provider's storage is about to exceed...`. -pub(crate) fn quota_exceeding(context: &Context, highest_usage: u64) -> String { - translated(context, StockMessage::QuotaExceedingMsgBody) - .replace1(&format!("{highest_usage}")) - .replace("%%", "%") -} - /// Stock string: `Incoming Messages`. pub(crate) fn incoming_messages(context: &Context) -> String { translated(context, StockMessage::IncomingMessages) diff --git a/src/stock_str/stock_str_tests.rs b/src/stock_str/stock_str_tests.rs index 62774a1ab..8f501c64f 100644 --- a/src/stock_str/stock_str_tests.rs +++ b/src/stock_str/stock_str_tests.rs @@ -102,16 +102,6 @@ async fn test_stock_system_msg_add_member_by_other_with_displayname() { ); } -#[tokio::test(flavor = "multi_thread", worker_threads = 2)] -async fn test_quota_exceeding_stock_str() -> Result<()> { - let t = TestContext::new().await; - let str = quota_exceeding(&t, 81); - assert!(str.contains("81% ")); - assert!(str.contains("100% ")); - assert!(!str.contains("%%")); - Ok(()) -} - #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_update_device_chats() { let t = TestContext::new_alice().await;