diff --git a/src/download.rs b/src/download.rs index 4146cd966..285dce2e8 100644 --- a/src/download.rs +++ b/src/download.rs @@ -23,7 +23,7 @@ use crate::{job_try, stock_str, EventType}; /// eg. to assign them to the correct chat. /// As these messages are typically small, /// they're caught by `MIN_DOWNLOAD_LIMIT`. -const MIN_DOWNLOAD_LIMIT: u32 = 32768; +pub(crate) const MIN_DOWNLOAD_LIMIT: u32 = 32768; /// If a message is downloaded only partially /// and `delete_server_after` is set to small timeouts (eg. "at once"), diff --git a/src/receive_imf.rs b/src/receive_imf.rs index b16ce3805..57215c8f0 100644 --- a/src/receive_imf.rs +++ b/src/receive_imf.rs @@ -77,6 +77,24 @@ pub async fn receive_imf( let mail = parse_mail(imf_raw).context("can't parse mail")?; let rfc724_mid = imap::prefetch_get_message_id(&mail.headers).unwrap_or_else(imap::create_message_id); + if let Some(download_limit) = context.download_limit().await? { + let download_limit: usize = download_limit.try_into()?; + if imf_raw.len() > download_limit { + let head = std::str::from_utf8(imf_raw)? + .split("\r\n\r\n") + .next() + .context("No empty line in the message")?; + return receive_imf_inner( + context, + &rfc724_mid, + head.as_bytes(), + seen, + Some(imf_raw.len().try_into()?), + false, + ) + .await; + } + } receive_imf_inner(context, &rfc724_mid, imf_raw, seen, None, false).await } @@ -1186,8 +1204,8 @@ INSERT INTO msgs ) ON CONFLICT (id) DO UPDATE SET rfc724_mid=excluded.rfc724_mid, chat_id=excluded.chat_id, - from_id=excluded.from_id, to_id=excluded.to_id, timestamp=excluded.timestamp, timestamp_sent=excluded.timestamp_sent, - timestamp_rcvd=excluded.timestamp_rcvd, type=excluded.type, state=excluded.state, msgrmsg=excluded.msgrmsg, + from_id=excluded.from_id, to_id=excluded.to_id, timestamp_sent=excluded.timestamp_sent, + type=excluded.type, msgrmsg=excluded.msgrmsg, txt=excluded.txt, subject=excluded.subject, txt_raw=excluded.txt_raw, param=excluded.param, bytes=excluded.bytes, mime_headers=excluded.mime_headers, mime_compressed=excluded.mime_compressed, mime_in_reply_to=excluded.mime_in_reply_to, diff --git a/src/receive_imf/tests.rs b/src/receive_imf/tests.rs index dba3d5305..f11f3d31c 100644 --- a/src/receive_imf/tests.rs +++ b/src/receive_imf/tests.rs @@ -10,8 +10,9 @@ use crate::chat::{get_chat_msgs, ChatItem, ChatVisibility}; use crate::chatlist::Chatlist; use crate::config::Config; use crate::constants::{DC_GCL_FOR_FORWARDING, DC_GCL_NO_SPECIALS}; +use crate::download::{DownloadState, MIN_DOWNLOAD_LIMIT}; use crate::imap::prefetch_should_download; -use crate::message::Message; +use crate::message::{self, Message}; use crate::test_utils::{get_chat_msg, TestContext, TestContextManager}; #[tokio::test(flavor = "multi_thread", worker_threads = 2)] @@ -3697,3 +3698,30 @@ async fn test_keep_member_list_if_possibly_nomember() -> Result<()> { assert!(is_contact_in_chat(&bob, bob_chat_id, bob_alice_contact).await?); Ok(()) } + +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn test_download_later() -> Result<()> { + let mut tcm = TestContextManager::new(); + let alice = tcm.alice().await; + alice.set_config(Config::DownloadLimit, Some("1")).await?; + assert_eq!(alice.download_limit().await?, Some(MIN_DOWNLOAD_LIMIT)); + + let bob = tcm.bob().await; + let bob_chat = bob.create_chat(&alice).await; + let text = String::from_utf8(vec![b'a'; MIN_DOWNLOAD_LIMIT as usize])?; + let sent_msg = bob.send_text(bob_chat.id, &text).await; + let msg = alice.recv_msg(&sent_msg).await; + assert_eq!(msg.download_state, DownloadState::Available); + assert_eq!(msg.state, MessageState::InFresh); + + let hi_msg = tcm.send_recv(&bob, &alice, "hi").await; + + alice.set_config(Config::DownloadLimit, None).await?; + let msg = alice.recv_msg(&sent_msg).await; + assert_eq!(msg.download_state, DownloadState::Done); + assert_eq!(msg.state, MessageState::InFresh); + assert_eq!(alice.get_last_msg_in(msg.chat_id).await.id, hi_msg.id); + assert!(msg.timestamp_sort <= hi_msg.timestamp_sort); + + Ok(()) +}