diff --git a/src/chat.rs b/src/chat.rs index a42c932c5..15f77375c 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -635,44 +635,6 @@ impl Chat { &self.name } - fn parent_query(fields: &str) -> String { - // Check for server_uid guarantees that we don't - // select a draft or undelivered message. - format!( - "SELECT {} \ - FROM msgs WHERE chat_id=?1 AND server_uid!=0 \ - ORDER BY timestamp DESC, id DESC \ - LIMIT 1;", - fields - ) - } - - async fn get_parent_mime_headers(&self, context: &Context) -> Option<(String, String, String)> { - let collect = |row: &rusqlite::Row| Ok((row.get(0)?, row.get(1)?, row.get(2)?)); - let params = paramsv![self.id]; - let sql = &context.sql; - - let query = Self::parent_query("rfc724_mid, mime_in_reply_to, mime_references"); - - sql.query_row(&query, params, collect).await.ok() - } - - async fn parent_is_encrypted(&self, context: &Context) -> Result { - let sql = &context.sql; - let params = paramsv![self.id]; - let query = Self::parent_query("param"); - - let packed: Option = sql.query_get_value_result(&query, params).await?; - - if let Some(ref packed) = packed { - let param = packed.parse::()?; - Ok(param.exists(Param::GuaranteeE2ee)) - } else { - // No messages - Ok(false) - } - } - pub async fn get_profile_image(&self, context: &Context) -> Option { if let Some(image_rel) = self.param.get(Param::ProfileImage) { if !image_rel.is_empty() { diff --git a/src/configure/mod.rs b/src/configure/mod.rs index 65ce5a83c..96b21fb9d 100644 --- a/src/configure/mod.rs +++ b/src/configure/mod.rs @@ -44,11 +44,11 @@ impl Context { ensure!( !self.scheduler.read().await.is_running(), - "Can not configure, already running" + "cannot configure, already running" ); ensure!( self.sql.is_open().await, - "Cannot configure, database not opened." + "cannot configure, database not opened." ); let cancel_channel = self.alloc_ongoing().await?; diff --git a/src/context.rs b/src/context.rs index 414cd8069..edd436fa5 100644 --- a/src/context.rs +++ b/src/context.rs @@ -52,6 +52,8 @@ pub struct InnerContext { pub(crate) running_state: RwLock, /// Mutex to avoid generating the key for the user more than once. pub(crate) generating_key_mutex: Mutex<()>, + /// Mutex to enforce only a single running oauth2 is running. + pub(crate) oauth2_mutex: Mutex<()>, pub(crate) translated_stockstrings: RwLock>, pub(crate) logs: (SyncSender, SyncReceiver), @@ -117,6 +119,7 @@ impl Context { bob: RwLock::new(Default::default()), last_smeared_timestamp: RwLock::new(0), generating_key_mutex: Mutex::new(()), + oauth2_mutex: Mutex::new(()), translated_stockstrings: RwLock::new(HashMap::new()), logs: unbounded(), scheduler: RwLock::new(Scheduler::Stopped), diff --git a/src/imap/mod.rs b/src/imap/mod.rs index b53f3cb3b..794e01d8c 100644 --- a/src/imap/mod.rs +++ b/src/imap/mod.rs @@ -1227,6 +1227,14 @@ impl Imap { return; } + if !self + .add_flag_finalized_with_set(context, SELECT_ALL, "\\Deleted") + .await + { + error!(context, "Cannot mark messages for deletion {}", folder); + return; + } + // we now trigger expunge to actually delete messages self.config.selected_folder_needs_expunge = true; match self.select_folder::(context, None).await { diff --git a/src/imap/select_folder.rs b/src/imap/select_folder.rs index 819f11db8..35e2b4eb4 100644 --- a/src/imap/select_folder.rs +++ b/src/imap/select_folder.rs @@ -47,6 +47,7 @@ impl Imap { } self.config.selected_folder = None; self.config.selected_folder_needs_expunge = false; + Ok(()) } @@ -77,26 +78,7 @@ impl Imap { // deselect existing folder, if needed (it's also done implicitly by SELECT, however, without EXPUNGE then) let needs_expunge = { self.config.selected_folder_needs_expunge }; if needs_expunge { - if let Some(ref folder) = self.config.selected_folder { - info!(context, "Expunge messages in \"{}\".", folder); - - // A CLOSE-SELECT is considerably faster than an EXPUNGE-SELECT, see - // https://tools.ietf.org/html/rfc3501#section-6.4.2 - if let Some(ref mut session) = &mut self.session { - match session.close().await { - Ok(_) => { - info!(context, "close/expunge succeeded"); - } - Err(err) => { - self.trigger_reconnect(); - return Err(Error::CloseExpungeFailed(err)); - } - } - } else { - return Err(Error::NoSession); - } - } - self.config.selected_folder_needs_expunge = false; + self.close_folder(context).await?; } // select new folder diff --git a/src/job.rs b/src/job.rs index 208d42625..43b795c54 100644 --- a/src/job.rs +++ b/src/job.rs @@ -810,45 +810,6 @@ pub enum Connection<'a> { Smtp(&'a mut Smtp), } -async fn add_imap_deletion_jobs(context: &Context) -> sql::Result<()> { - if let Some(delete_server_after) = context.get_config_delete_server_after().await { - let threshold_timestamp = time() - delete_server_after; - - // Select all expired messages which don't have a - // corresponding message deletion job yet. - let msg_ids = context - .sql - .query_map( - "SELECT id FROM msgs \ - WHERE timestamp < ? \ - AND server_uid != 0 \ - AND NOT EXISTS (SELECT 1 FROM jobs WHERE foreign_id = msgs.id \ - AND action = ?)", - paramsv![threshold_timestamp, Action::DeleteMsgOnImap], - |row| row.get::<_, MsgId>(0), - |ids| { - ids.collect::, _>>() - .map_err(Into::into) - }, - ) - .await?; - - // Schedule IMAP deletion for expired messages. - for msg_id in msg_ids { - add( - context, - Action::DeleteMsgOnImap, - msg_id.to_u32() as i32, - Params::new(), - 0, - ) - .await; - } - } - - Ok(()) -} - async fn load_imap_deletion_msgid(context: &Context) -> sql::Result> { if let Some(delete_server_after) = context.get_config_delete_server_after().await { let threshold_timestamp = time() - delete_server_after; diff --git a/src/oauth2.rs b/src/oauth2.rs index 6bb657882..89354f651 100644 --- a/src/oauth2.rs +++ b/src/oauth2.rs @@ -75,8 +75,6 @@ pub async fn dc_get_oauth2_url( } } -// The following function may block due http-requests; -// must not be called from the main thread or by the ui! pub async fn dc_get_oauth2_access_token( context: &Context, addr: impl AsRef, @@ -84,9 +82,7 @@ pub async fn dc_get_oauth2_access_token( regenerate: bool, ) -> Option { if let Some(oauth2) = Oauth2::from_address(addr) { - // TODO: FIXME - // let lock = context.oauth2_critical.clone(); - // let _l = lock.lock().await; + let lock = context.oauth2_mutex.lock().await; // read generated token if !regenerate && !is_expired(context).await { @@ -243,6 +239,8 @@ pub async fn dc_get_oauth2_access_token( warn!(context, "Failed to find OAuth2 access token"); } + drop(lock); + response.access_token } else { warn!(context, "Internal OAuth2 error: 2");