mirror of
https://github.com/chatmail/core.git
synced 2026-04-28 19:06:35 +03:00
feat: pre-messages / next version of download on demand (#7371)
Closes <https://github.com/chatmail/core/issues/7367> Co-authored-by: iequidoo <dgreshilov@gmail.com> Co-authored-by: Hocuri <hocuri@gmx.de>
This commit is contained in:
166
src/chat.rs
166
src/chat.rs
@@ -12,6 +12,7 @@ use std::time::Duration;
|
||||
use anyhow::{Context as _, Result, anyhow, bail, ensure};
|
||||
use chrono::TimeZone;
|
||||
use deltachat_contact_tools::{ContactAddress, sanitize_bidi_characters, sanitize_single_line};
|
||||
use humansize::{BINARY, format_size};
|
||||
use mail_builder::mime::MimePart;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use strum_macros::EnumIter;
|
||||
@@ -27,7 +28,9 @@ use crate::constants::{
|
||||
use crate::contact::{self, Contact, ContactId, Origin};
|
||||
use crate::context::Context;
|
||||
use crate::debug_logging::maybe_set_logging_xdc;
|
||||
use crate::download::DownloadState;
|
||||
use crate::download::{
|
||||
DownloadState, PRE_MSG_ATTACHMENT_SIZE_THRESHOLD, PRE_MSG_SIZE_WARNING_THRESHOLD,
|
||||
};
|
||||
use crate::ephemeral::{Timer as EphemeralTimer, start_chat_ephemeral_timers};
|
||||
use crate::events::EventType;
|
||||
use crate::key::self_fingerprint;
|
||||
@@ -35,7 +38,7 @@ use crate::location;
|
||||
use crate::log::{LogExt, warn};
|
||||
use crate::logged_debug_assert;
|
||||
use crate::message::{self, Message, MessageState, MsgId, Viewtype};
|
||||
use crate::mimefactory::MimeFactory;
|
||||
use crate::mimefactory::{MimeFactory, RenderedEmail};
|
||||
use crate::mimeparser::SystemMessage;
|
||||
use crate::param::{Param, Params};
|
||||
use crate::receive_imf::ReceivedMsg;
|
||||
@@ -625,8 +628,12 @@ impl ChatId {
|
||||
.sql
|
||||
.transaction(|transaction| {
|
||||
transaction.execute(
|
||||
"UPDATE imap SET target=? WHERE rfc724_mid IN (SELECT rfc724_mid FROM msgs WHERE chat_id=?)",
|
||||
(delete_msgs_target, self,),
|
||||
"UPDATE imap SET target=? WHERE rfc724_mid IN (SELECT rfc724_mid FROM msgs WHERE chat_id=? AND rfc724_mid!='')",
|
||||
(&delete_msgs_target, self,),
|
||||
)?;
|
||||
transaction.execute(
|
||||
"UPDATE imap SET target=? WHERE rfc724_mid IN (SELECT pre_rfc724_mid FROM msgs WHERE chat_id=? AND pre_rfc724_mid!='')",
|
||||
(&delete_msgs_target, self,),
|
||||
)?;
|
||||
transaction.execute(
|
||||
"DELETE FROM smtp WHERE msg_id IN (SELECT id FROM msgs WHERE chat_id=?)",
|
||||
@@ -636,7 +643,15 @@ impl ChatId {
|
||||
"DELETE FROM msgs_mdns WHERE msg_id IN (SELECT id FROM msgs WHERE chat_id=?)",
|
||||
(self,),
|
||||
)?;
|
||||
transaction.execute("DELETE FROM msgs WHERE chat_id=?", (self,))?;
|
||||
// If you change which information is preserved here, also change `MsgId::trash()`
|
||||
// and other places it references.
|
||||
transaction.execute(
|
||||
"
|
||||
INSERT OR REPLACE INTO msgs (id, rfc724_mid, pre_rfc724_mid, timestamp, chat_id, deleted)
|
||||
SELECT id, rfc724_mid, pre_rfc724_mid, timestamp, ?, 1 FROM msgs WHERE chat_id=?
|
||||
",
|
||||
(DC_CHAT_ID_TRASH, self),
|
||||
)?;
|
||||
transaction.execute("DELETE FROM chats_contacts WHERE chat_id=?", (self,))?;
|
||||
transaction.execute("DELETE FROM chats WHERE id=?", (self,))?;
|
||||
Ok(())
|
||||
@@ -2736,6 +2751,60 @@ async fn prepare_send_msg(
|
||||
Ok(row_ids)
|
||||
}
|
||||
|
||||
/// Renders the Message or splits it into Pre- and Post-Message.
|
||||
///
|
||||
/// Pre-Message is a small message with metadata which announces a larger Post-Message.
|
||||
/// Post-Messages are not downloaded in the background.
|
||||
///
|
||||
/// If pre-message is not nessesary, this returns `None` as the 0th value.
|
||||
async fn render_mime_message_and_pre_message(
|
||||
context: &Context,
|
||||
msg: &mut Message,
|
||||
mimefactory: MimeFactory,
|
||||
) -> Result<(Option<RenderedEmail>, RenderedEmail)> {
|
||||
let needs_pre_message = msg.viewtype.has_file()
|
||||
&& mimefactory.will_be_encrypted() // unencrypted is likely email, we don't want to spam by sending multiple messages
|
||||
&& msg
|
||||
.get_filebytes(context)
|
||||
.await?
|
||||
.context("filebytes not available, even though message has attachment")?
|
||||
> PRE_MSG_ATTACHMENT_SIZE_THRESHOLD;
|
||||
|
||||
if needs_pre_message {
|
||||
info!(
|
||||
context,
|
||||
"Message {} is large and will be split into pre- and post-messages.", msg.id,
|
||||
);
|
||||
|
||||
let mut mimefactory_post_msg = mimefactory.clone();
|
||||
mimefactory_post_msg.set_as_post_message();
|
||||
let rendered_msg = mimefactory_post_msg
|
||||
.render(context)
|
||||
.await
|
||||
.context("Failed to render post-message")?;
|
||||
|
||||
let mut mimefactory_pre_msg = mimefactory;
|
||||
mimefactory_pre_msg.set_as_pre_message_for(&rendered_msg);
|
||||
let rendered_pre_msg = mimefactory_pre_msg
|
||||
.render(context)
|
||||
.await
|
||||
.context("pre-message failed to render")?;
|
||||
|
||||
if rendered_pre_msg.message.len() > PRE_MSG_SIZE_WARNING_THRESHOLD {
|
||||
warn!(
|
||||
context,
|
||||
"Pre-message for message {} is larger than expected: {}.",
|
||||
msg.id,
|
||||
rendered_pre_msg.message.len()
|
||||
);
|
||||
}
|
||||
|
||||
Ok((Some(rendered_pre_msg), rendered_msg))
|
||||
} else {
|
||||
Ok((None, mimefactory.render(context).await?))
|
||||
}
|
||||
}
|
||||
|
||||
/// Constructs jobs for sending a message and inserts them into the `smtp` table.
|
||||
///
|
||||
/// Updates the message `GuaranteeE2ee` parameter and persists it
|
||||
@@ -2807,13 +2876,32 @@ pub(crate) async fn create_send_msg_jobs(context: &Context, msg: &mut Message) -
|
||||
return Ok(Vec::new());
|
||||
}
|
||||
|
||||
let rendered_msg = match mimefactory.render(context).await {
|
||||
Ok(res) => Ok(res),
|
||||
Err(err) => {
|
||||
message::set_msg_failed(context, msg, &err.to_string()).await?;
|
||||
Err(err)
|
||||
}
|
||||
}?;
|
||||
let (rendered_pre_msg, rendered_msg) =
|
||||
match render_mime_message_and_pre_message(context, msg, mimefactory).await {
|
||||
Ok(res) => Ok(res),
|
||||
Err(err) => {
|
||||
message::set_msg_failed(context, msg, &err.to_string()).await?;
|
||||
Err(err)
|
||||
}
|
||||
}?;
|
||||
|
||||
if let (post_msg, Some(pre_msg)) = (&rendered_msg, &rendered_pre_msg) {
|
||||
info!(
|
||||
context,
|
||||
"Message {} sizes: pre-message: {}; post-message: {}.",
|
||||
msg.id,
|
||||
format_size(pre_msg.message.len(), BINARY),
|
||||
format_size(post_msg.message.len(), BINARY),
|
||||
);
|
||||
msg.pre_rfc724_mid = pre_msg.rfc724_mid.clone();
|
||||
} else {
|
||||
info!(
|
||||
context,
|
||||
"Message {} will be sent in one shot (no pre- and post-message). Size: {}.",
|
||||
msg.id,
|
||||
format_size(rendered_msg.message.len(), BINARY),
|
||||
);
|
||||
}
|
||||
|
||||
if needs_encryption && !rendered_msg.is_encrypted {
|
||||
/* unrecoverable */
|
||||
@@ -2852,8 +2940,13 @@ pub(crate) async fn create_send_msg_jobs(context: &Context, msg: &mut Message) -
|
||||
context
|
||||
.sql
|
||||
.execute(
|
||||
"UPDATE msgs SET subject=?, param=? WHERE id=?",
|
||||
(&msg.subject, msg.param.to_string(), msg.id),
|
||||
"UPDATE msgs SET pre_rfc724_mid=?, subject=?, param=? WHERE id=?",
|
||||
(
|
||||
&msg.pre_rfc724_mid,
|
||||
&msg.subject,
|
||||
msg.param.to_string(),
|
||||
msg.id,
|
||||
),
|
||||
)
|
||||
.await?;
|
||||
|
||||
@@ -2867,19 +2960,27 @@ pub(crate) async fn create_send_msg_jobs(context: &Context, msg: &mut Message) -
|
||||
(),
|
||||
)?;
|
||||
}
|
||||
|
||||
let mut stmt = t.prepare(
|
||||
"INSERT INTO smtp (rfc724_mid, recipients, mime, msg_id)
|
||||
VALUES (?1, ?2, ?3, ?4)",
|
||||
)?;
|
||||
for recipients_chunk in recipients.chunks(chunk_size) {
|
||||
let recipients_chunk = recipients_chunk.join(" ");
|
||||
let row_id = t.execute(
|
||||
"INSERT INTO smtp (rfc724_mid, recipients, mime, msg_id) \
|
||||
VALUES (?1, ?2, ?3, ?4)",
|
||||
(
|
||||
&rendered_msg.rfc724_mid,
|
||||
recipients_chunk,
|
||||
&rendered_msg.message,
|
||||
if let Some(pre_msg) = &rendered_pre_msg {
|
||||
let row_id = stmt.execute((
|
||||
&pre_msg.rfc724_mid,
|
||||
&recipients_chunk,
|
||||
&pre_msg.message,
|
||||
msg.id,
|
||||
),
|
||||
)?;
|
||||
))?;
|
||||
row_ids.push(row_id.try_into()?);
|
||||
}
|
||||
let row_id = stmt.execute((
|
||||
&rendered_msg.rfc724_mid,
|
||||
&recipients_chunk,
|
||||
&rendered_msg.message,
|
||||
msg.id,
|
||||
))?;
|
||||
row_ids.push(row_id.try_into()?);
|
||||
}
|
||||
Ok(row_ids)
|
||||
@@ -4261,6 +4362,10 @@ pub async fn forward_msgs_2ctx(
|
||||
msg.viewtype = Viewtype::Text;
|
||||
}
|
||||
|
||||
if msg.download_state != DownloadState::Done {
|
||||
msg.text += &msg.additional_text;
|
||||
}
|
||||
|
||||
let param = &mut param;
|
||||
msg.param.steal(param, Param::File);
|
||||
msg.param.steal(param, Param::Filename);
|
||||
@@ -4337,12 +4442,18 @@ pub(crate) async fn save_copy_in_self_talk(
|
||||
msg.param.remove(Param::WebxdcDocumentTimestamp);
|
||||
msg.param.remove(Param::WebxdcSummary);
|
||||
msg.param.remove(Param::WebxdcSummaryTimestamp);
|
||||
msg.param.remove(Param::PostMessageFileBytes);
|
||||
msg.param.remove(Param::PostMessageViewtype);
|
||||
|
||||
if msg.download_state != DownloadState::Done {
|
||||
msg.text += &msg.additional_text;
|
||||
}
|
||||
|
||||
if !msg.original_msg_id.is_unset() {
|
||||
bail!("message already saved.");
|
||||
}
|
||||
|
||||
let copy_fields = "from_id, to_id, timestamp_rcvd, type, txt,
|
||||
let copy_fields = "from_id, to_id, timestamp_rcvd, type,
|
||||
mime_modified, mime_headers, mime_compressed, mime_in_reply_to, subject, msgrmsg";
|
||||
let row_id = context
|
||||
.sql
|
||||
@@ -4350,7 +4461,7 @@ pub(crate) async fn save_copy_in_self_talk(
|
||||
&format!(
|
||||
"INSERT INTO msgs ({copy_fields},
|
||||
timestamp_sent,
|
||||
chat_id, rfc724_mid, state, timestamp, param, starred)
|
||||
txt, chat_id, rfc724_mid, state, timestamp, param, starred)
|
||||
SELECT {copy_fields},
|
||||
-- Outgoing messages on originating device
|
||||
-- have timestamp_sent == 0.
|
||||
@@ -4358,10 +4469,11 @@ pub(crate) async fn save_copy_in_self_talk(
|
||||
-- so UIs display the same timestamp
|
||||
-- for saved and original message.
|
||||
IIF(timestamp_sent == 0, timestamp, timestamp_sent),
|
||||
?, ?, ?, ?, ?, ?
|
||||
?, ?, ?, ?, ?, ?, ?
|
||||
FROM msgs WHERE id=?;"
|
||||
),
|
||||
(
|
||||
msg.text,
|
||||
dest_chat_id,
|
||||
dest_rfc724_mid,
|
||||
if msg.from_id == ContactId::SELF {
|
||||
|
||||
Reference in New Issue
Block a user