Skip to content

Commit b6dc11a

Browse files
Simon-Lauxlink2xt
authored andcommitted
feat: receive pre-messages and adapt download on demand
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.
1 parent ee5472b commit b6dc11a

File tree

29 files changed

+2155
-500
lines changed

29 files changed

+2155
-500
lines changed

deltachat-ffi/deltachat.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -488,11 +488,11 @@ char* dc_get_blobdir (const dc_context_t* context);
488488
* 0=use IMAP IDLE if the server supports it.
489489
* This is a developer option used for testing polling used as an IDLE fallback.
490490
* - `download_limit` = Messages up to this number of bytes are downloaded automatically.
491-
* For larger messages, only the header is downloaded and a placeholder is shown.
491+
* For messages with large attachements, two messages are sent:
492+
* a Pre-Message containing metadata and a Post-Message containing the attachment.
493+
* Pre-Messages are always downloaded and show a placeholder message
492494
* These messages can be downloaded fully using dc_download_full_msg() later.
493-
* The limit is compared against raw message sizes, including headers.
494-
* The actually used limit may be corrected
495-
* to not mess up with non-delivery-reports or read-receipts.
495+
* Post-Messages are automatically downloaded if they are smaller than the download_limit.
496496
* 0=no limit (default).
497497
* Changes affect future messages only.
498498
* - `protect_autocrypt` = Enable Header Protection for Autocrypt header.
@@ -4310,7 +4310,8 @@ char* dc_msg_get_webxdc_info (const dc_msg_t* msg);
43104310

43114311
/**
43124312
* Get the size of the file. Returns the size of the file associated with a
4313-
* message, if applicable.
4313+
* message, if applicable.
4314+
* If message is a pre-message, then this returns size of the to be downloaded file.
43144315
*
43154316
* Typically, this is used to show the size of document files, e.g. a PDF.
43164317
*

deltachat-jsonrpc/src/api/types/message.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ pub struct MessageObject {
9292

9393
file: Option<String>,
9494
file_mime: Option<String>,
95+
/// Returns the size of the file in bytes, if applicable.
96+
/// If message is a pre-message, then this returns size of the to be downloaded file.
9597
file_bytes: u64,
9698
file_name: Option<String>,
9799

deltachat-rpc-client/tests/test_something.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
import pytest
1212

1313
from deltachat_rpc_client import Contact, EventType, Message, events
14-
from deltachat_rpc_client.const import DownloadState, MessageState
14+
from deltachat_rpc_client.const import MessageState
1515
from deltachat_rpc_client.pytestplugin import E2EE_INFO_MSGS
1616
from deltachat_rpc_client.rpc import JsonRpcError
1717

src/chat.rs

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use std::time::Duration;
1212
use anyhow::{Context as _, Result, anyhow, bail, ensure};
1313
use chrono::TimeZone;
1414
use deltachat_contact_tools::{ContactAddress, sanitize_bidi_characters, sanitize_single_line};
15+
use humansize::{BINARY, format_size};
1516
use mail_builder::mime::MimePart;
1617
use serde::{Deserialize, Serialize};
1718
use strum_macros::EnumIter;
@@ -2730,10 +2731,10 @@ async fn prepare_send_msg(
27302731
Ok(row_ids)
27312732
}
27322733

2733-
/// Renders the message or Full-Message and Pre-Message.
2734+
/// Renders the Message or splits it into Post-Message and Pre-Message.
27342735
///
2735-
/// Pre-Message is a small message with metadata which announces a larger Full-Message.
2736-
/// Full messages are not downloaded in the background.
2736+
/// Pre-Message is a small message with metadata which announces a larger Post-Message.
2737+
/// Post-Messages are not downloaded in the background.
27372738
///
27382739
/// If pre-message is not nessesary this returns a normal message instead.
27392740
async fn render_mime_message_and_pre_message(
@@ -2750,9 +2751,14 @@ async fn render_mime_message_and_pre_message(
27502751
> PRE_MSG_ATTACHMENT_SIZE_THRESHOLD;
27512752

27522753
if needs_pre_message {
2753-
let mut mimefactory_full_msg = mimefactory.clone();
2754-
mimefactory_full_msg.set_as_full_message();
2755-
let rendered_msg = mimefactory_full_msg.render(context).await?;
2754+
info!(
2755+
context,
2756+
"Message is large and will be split into a pre- and a post-message.",
2757+
);
2758+
2759+
let mut mimefactory_post_msg = mimefactory.clone();
2760+
mimefactory_post_msg.set_as_post_message();
2761+
let rendered_msg = mimefactory_post_msg.render(context).await?;
27562762

27572763
let mut mimefactory_pre_msg = mimefactory;
27582764
mimefactory_pre_msg.set_as_pre_message_for(&rendered_msg);
@@ -2856,6 +2862,21 @@ pub(crate) async fn create_send_msg_jobs(context: &Context, msg: &mut Message) -
28562862
}
28572863
}?;
28582864

2865+
if let (post_msg, Some(pre_msg)) = (&rendered_msg, &rendered_pre_msg) {
2866+
info!(
2867+
context,
2868+
"Message Sizes: Pre-Message {}; Post-Message: {}",
2869+
format_size(pre_msg.message.len(), BINARY),
2870+
format_size(post_msg.message.len(), BINARY)
2871+
);
2872+
} else {
2873+
info!(
2874+
context,
2875+
"Message will be sent as normal message (no pre- and post message). Size: {}",
2876+
format_size(rendered_msg.message.len(), BINARY)
2877+
);
2878+
}
2879+
28592880
if needs_encryption && !rendered_msg.is_encrypted {
28602881
/* unrecoverable */
28612882
message::set_msg_failed(
@@ -4319,6 +4340,14 @@ pub async fn forward_msgs_2ctx(
43194340
msg.viewtype = Viewtype::Text;
43204341
}
43214342

4343+
if msg.download_state != DownloadState::Done {
4344+
// we don't use Message.get_text() here,
4345+
// because it may change in future,
4346+
// when UI shows this info itself,
4347+
// then the additional_text will not be added in get_text anymore.
4348+
msg.text += &msg.additional_text;
4349+
}
4350+
43224351
let param = &mut param;
43234352
msg.param.steal(param, Param::File);
43244353
msg.param.steal(param, Param::Filename);
@@ -4329,6 +4358,7 @@ pub async fn forward_msgs_2ctx(
43294358
msg.param.steal(param, Param::ProtectQuote);
43304359
msg.param.steal(param, Param::Quote);
43314360
msg.param.steal(param, Param::Summary1);
4361+
43324362
msg.in_reply_to = None;
43334363

43344364
// do not leak data as group names; a default subject is generated by mimefactory
@@ -4395,31 +4425,42 @@ pub(crate) async fn save_copy_in_self_talk(
43954425
msg.param.remove(Param::WebxdcDocumentTimestamp);
43964426
msg.param.remove(Param::WebxdcSummary);
43974427
msg.param.remove(Param::WebxdcSummaryTimestamp);
4428+
msg.param.remove(Param::PostMessageFileBytes);
4429+
msg.param.remove(Param::PostMessageViewtype);
4430+
4431+
if msg.download_state != DownloadState::Done {
4432+
// we don't use Message.get_text() here,
4433+
// because it may change in future,
4434+
// when UI shows this info itself,
4435+
// then the additional_text will not be added in get_text anymore.
4436+
msg.text += &msg.additional_text;
4437+
}
43984438

43994439
if !msg.original_msg_id.is_unset() {
44004440
bail!("message already saved.");
44014441
}
44024442

4403-
let copy_fields = "from_id, to_id, timestamp_rcvd, type, txt,
4443+
let copy_fields = "from_id, to_id, timestamp_rcvd, type,
44044444
mime_modified, mime_headers, mime_compressed, mime_in_reply_to, subject, msgrmsg";
44054445
let row_id = context
44064446
.sql
44074447
.insert(
44084448
&format!(
44094449
"INSERT INTO msgs ({copy_fields},
44104450
timestamp_sent,
4411-
chat_id, rfc724_mid, state, timestamp, param, starred)
4451+
txt, chat_id, rfc724_mid, state, timestamp, param, starred)
44124452
SELECT {copy_fields},
44134453
-- Outgoing messages on originating device
44144454
-- have timestamp_sent == 0.
44154455
-- We copy sort timestamp instead
44164456
-- so UIs display the same timestamp
44174457
-- for saved and original message.
44184458
IIF(timestamp_sent == 0, timestamp, timestamp_sent),
4419-
?, ?, ?, ?, ?, ?
4459+
?, ?, ?, ?, ?, ?, ?
44204460
FROM msgs WHERE id=?;"
44214461
),
44224462
(
4463+
msg.text,
44234464
dest_chat_id,
44244465
dest_rfc724_mid,
44254466
if msg.from_id == ContactId::SELF {

src/context.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -609,7 +609,7 @@ impl Context {
609609
convert_folder_meaning(self, folder_meaning).await?
610610
{
611611
connection
612-
.fetch_move_delete(self, &mut session, &watch_folder, folder_meaning)
612+
.fetch_move_delete(self, &mut session, true, &watch_folder, folder_meaning)
613613
.await?;
614614
}
615615
}
@@ -622,6 +622,12 @@ impl Context {
622622
{
623623
warn!(self, "Failed to update quota: {err:#}.");
624624
}
625+
626+
// OPTIONAL TODO: if time left start downloading messages
627+
// while (msg = download_when_normal_starts) {
628+
// if not time_left {break;}
629+
// connection.download_message(msg) }
630+
// }
625631
}
626632

627633
info!(
@@ -1080,13 +1086,6 @@ impl Context {
10801086
.await?
10811087
.unwrap_or_default(),
10821088
);
1083-
res.insert(
1084-
"fail_on_receiving_full_msg",
1085-
self.sql
1086-
.get_raw_config("fail_on_receiving_full_msg")
1087-
.await?
1088-
.unwrap_or_default(),
1089-
);
10901089
res.insert(
10911090
"std_header_protection_composing",
10921091
self.sql

src/context/context_tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ async fn test_get_info_completeness() {
297297
"encrypted_device_token",
298298
"stats_last_update",
299299
"stats_last_old_contact_id",
300-
"simulate_receive_imf_error",
300+
"simulate_receive_imf_error", // only used in tests
301301
];
302302
let t = TestContext::new().await;
303303
let info = t.get_info().await.unwrap();

0 commit comments

Comments
 (0)