mirror of
https://github.com/chatmail/core.git
synced 2026-04-26 01:46:34 +03:00
fix python lint errors receive pre-mesages, start with changes to imap loop. refactor: move download code from `scheduler.rs` to `download.rs`, also move `get_msg_id_by_rfc724_mid` to `MsgId::get_by_rfc724_mid` `MAX_FETCH_MSG_SIZE` is no longer unused Parse if it is a pre-message or full-message start with receiving logic get rid of `MsgId::get_by_rfc724_mid` because it was a duplicate of `message::rfc724_mid_exists` docs: add hint to `MimeMessage::from_bytes` stating that it has side-effects. receiving full message send and receive `attachment_size` and set viewtype to text in pre_message metadata as struct in pre-message in header. And fill params that we can already fill from the metadata. Also add a new api to check what viewtype the message will have once downloaded. api: jsonrpc: add `full_message_view_type` to `Message` and `MessageInfo` make PreMsgMetadata.to_header_value not consume self/PreMsgMetadata add api to merge params on download full message: merge new params into old params and remove full-message metadata params move tests to `src/tests/pre_messages.rs` dynamically allocate test attachment bytes fix detection of pre-messages. (it looked for the ChatFullMessageId header in the unencrypted headers before) fix setting dl state to avaiable on pre-messages fix: save pre message with rfc724_mid of full message als disable replacement for full messages add some receiving tests and update test todo for premessage metadata test: process full message before pre-message test receive normal message some serialization tests for PreMsgMetadata remove outdated todo comment test that pre-message contains message text PreMsgMetadata: test_build_from_file_msg and test_build_from_file_msg test: test_receive_pre_message_image Test receiving the full message after receiving an edit after receiving the pre-message test_reaction_on_pre_message test_full_download_after_trashed test_webxdc_update_for_not_downloaded_instance simplify fake webxdc generation in test_webxdc_update_for_not_downloaded_instance test_markseen_pre_msg test_pre_msg_can_start_chat and test_full_msg_can_start_chat test_download_later_keeps_message_order test_chatlist_event_on_full_msg_download fix download not working log splitting into pre-message add pre-message info to text when loading from db. this can be disabled with config key `hide_pre_message_metadata_text` if ui wants to display it in a prettier way. update `download_limit` documentation more logging: log size of pre and post messages rename full message to Post-Message split up the pre-message tests into multiple files dedup test code by extracting code to create test messages into util methods remove post_message_view_type from api, now it is only used internally for tests remove `hide_pre_message_metadata_text` config option, as there currently is no way to get the full message viewtype anymore Update src/download.rs resolve comment use `parse_message_id` instead of removing `<>`parenthesis it manually fix available_post_msgs gets no entries handle forwarding and add a test for it. convert comment to log warning event on unexpected download failure add doc comment to `simple_imap_loop` more logging handle saving pre-message to self messages and test.
120 lines
4.6 KiB
Rust
120 lines
4.6 KiB
Rust
use std::collections::BTreeMap;
|
|
|
|
use anyhow::{Context as _, Result};
|
|
|
|
use super::{get_folder_meaning_by_attrs, get_folder_meaning_by_name};
|
|
use crate::config::Config;
|
|
use crate::imap::{Imap, session::Session};
|
|
use crate::log::LogExt;
|
|
use crate::tools::{self, time_elapsed};
|
|
use crate::{context::Context, imap::FolderMeaning};
|
|
|
|
impl Imap {
|
|
/// Returns true if folders were scanned, false if scanning was postponed.
|
|
pub(crate) async fn scan_folders(
|
|
&mut self,
|
|
context: &Context,
|
|
session: &mut Session,
|
|
) -> Result<bool> {
|
|
// First of all, debounce to once per minute:
|
|
{
|
|
let mut last_scan = session.last_full_folder_scan.lock().await;
|
|
if let Some(last_scan) = *last_scan {
|
|
let elapsed_secs = time_elapsed(&last_scan).as_secs();
|
|
let debounce_secs = context
|
|
.get_config_u64(Config::ScanAllFoldersDebounceSecs)
|
|
.await?;
|
|
|
|
if elapsed_secs < debounce_secs {
|
|
return Ok(false);
|
|
}
|
|
}
|
|
|
|
// Update the timestamp before scanning the folders
|
|
// to avoid holding the lock for too long.
|
|
// This means next scan is delayed even if
|
|
// the current one fails.
|
|
last_scan.replace(tools::Time::now());
|
|
}
|
|
info!(context, "Starting full folder scan");
|
|
|
|
let folders = session.list_folders().await?;
|
|
let watched_folders = get_watched_folders(context).await?;
|
|
|
|
let mut folder_configs = BTreeMap::new();
|
|
let mut folder_names = Vec::new();
|
|
|
|
for folder in folders {
|
|
let folder_meaning = get_folder_meaning_by_attrs(folder.attributes());
|
|
if folder_meaning == FolderMeaning::Virtual {
|
|
// Gmail has virtual folders that should be skipped. For example,
|
|
// emails appear in the inbox and under "All Mail" as soon as it is
|
|
// received. The code used to wrongly conclude that the email had
|
|
// already been moved and left it in the inbox.
|
|
continue;
|
|
}
|
|
folder_names.push(folder.name().to_string());
|
|
let folder_name_meaning = get_folder_meaning_by_name(folder.name());
|
|
|
|
if let Some(config) = folder_meaning.to_config() {
|
|
// Always takes precedence
|
|
folder_configs.insert(config, folder.name().to_string());
|
|
} else if let Some(config) = folder_name_meaning.to_config() {
|
|
// only set if none has been already set
|
|
folder_configs
|
|
.entry(config)
|
|
.or_insert_with(|| folder.name().to_string());
|
|
}
|
|
|
|
let folder_meaning = match folder_meaning {
|
|
FolderMeaning::Unknown => folder_name_meaning,
|
|
_ => folder_meaning,
|
|
};
|
|
|
|
// Don't scan folders that are watched anyway
|
|
if !watched_folders.contains(&folder.name().to_string())
|
|
&& folder_meaning != FolderMeaning::Trash
|
|
&& folder_meaning != FolderMeaning::Unknown
|
|
{
|
|
self.fetch_move_delete(context, session, false, folder.name(), folder_meaning)
|
|
.await
|
|
.context("Can't fetch new msgs in scanned folder")
|
|
.log_err(context)
|
|
.ok();
|
|
}
|
|
}
|
|
|
|
// Set config for the Trash folder. Or reset if the folder was deleted.
|
|
let conf = Config::ConfiguredTrashFolder;
|
|
let val = folder_configs.get(&conf).map(|s| s.as_str());
|
|
let interrupt = val.is_some() && context.get_config(conf).await?.is_none();
|
|
context.set_config_internal(conf, val).await?;
|
|
if interrupt {
|
|
// `Imap::fetch_move_delete()`, particularly message deletion, is possible now for other
|
|
// folders (NB: we are in the Inbox loop).
|
|
context.scheduler.interrupt_oboxes().await;
|
|
}
|
|
|
|
info!(context, "Found folders: {folder_names:?}.");
|
|
Ok(true)
|
|
}
|
|
}
|
|
|
|
pub(crate) async fn get_watched_folder_configs(context: &Context) -> Result<Vec<Config>> {
|
|
let mut res = vec![Config::ConfiguredInboxFolder];
|
|
if context.should_watch_mvbox().await? {
|
|
res.push(Config::ConfiguredMvboxFolder);
|
|
}
|
|
Ok(res)
|
|
}
|
|
|
|
pub(crate) async fn get_watched_folders(context: &Context) -> Result<Vec<String>> {
|
|
let mut res = Vec::new();
|
|
for folder_config in get_watched_folder_configs(context).await? {
|
|
if let Some(folder) = context.get_config(folder_config).await? {
|
|
res.push(folder);
|
|
}
|
|
}
|
|
Ok(res)
|
|
}
|