mirror of
https://github.com/chatmail/core.git
synced 2026-05-06 06:46:35 +03:00
feat: send pre-message on messages with large attachments (#7410)
part of #7367 progress / what's to do: - [x] send pre-message - [x] The message's state must be set to MessageState::OutDelivered only after both messages are sent. If a read receipt is received, the message can be OutMdnRcvd or OutPending; let's just do whatever is easiest for now. Take care not to revert from OutMdnReceived to OutDelivered if we first receive a read receipt and then deliver the full message. - this is already the case: - `OutDelivered` is set when a message is sent out and has no remaining send jobs in the smtp table for this message id - so already works since full message and pre message have same msgId in that table. - `OutMdnRcvd` is a "virtual" state (https://github.com/chatmail/core/issues/7367#issuecomment-3500891040), so going back to `OutDelivered` can't happen anymore - [x] delimit `ChatFullMessageId` with `<` and `>` like the other message ids - [x] add tests - [x] test that pre message is sent for attachment larger than X - test that correct headers are present on both messages - also test that Autocrypt-gossip and selfavatar should never go into full-messages - [x] test that no pre message is sent for attachment smaller than X - no "is full message" header should be present - [x] test that pre message is not send for large webxdc update or large text - [x] fix test `receive_imf::receive_imf_tests::test_dont_reverify_by_self_on_outgoing_msg` --------- Co-authored-by: iequidoo <117991069+iequidoo@users.noreply.github.com> Co-authored-by: Hocuri <hocuri@gmx.de>
This commit is contained in:
@@ -59,6 +59,15 @@ pub enum Loaded {
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum PreMessageMode {
|
||||
/// adds the Chat-Is-Full-Message header in unprotected part
|
||||
FullMessage,
|
||||
/// adds the Chat-Full-Message-ID header to protected part
|
||||
/// also adds metadata and explicitly excludes attachment
|
||||
PreMessage { full_msg_rfc724_mid: String },
|
||||
}
|
||||
|
||||
/// Helper to construct mime messages.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MimeFactory {
|
||||
@@ -146,6 +155,9 @@ pub struct MimeFactory {
|
||||
|
||||
/// This field is used to sustain the topic id of webxdcs needed for peer channels.
|
||||
webxdc_topic: Option<TopicId>,
|
||||
|
||||
/// This field is used when this is either a pre-message or a full-message.
|
||||
pre_message_mode: Option<PreMessageMode>,
|
||||
}
|
||||
|
||||
/// Result of rendering a message, ready to be submitted to a send job.
|
||||
@@ -500,6 +512,7 @@ impl MimeFactory {
|
||||
sync_ids_to_delete: None,
|
||||
attach_selfavatar,
|
||||
webxdc_topic,
|
||||
pre_message_mode: None,
|
||||
};
|
||||
Ok(factory)
|
||||
}
|
||||
@@ -548,6 +561,7 @@ impl MimeFactory {
|
||||
sync_ids_to_delete: None,
|
||||
attach_selfavatar: false,
|
||||
webxdc_topic: None,
|
||||
pre_message_mode: None,
|
||||
};
|
||||
|
||||
Ok(res)
|
||||
@@ -779,7 +793,10 @@ impl MimeFactory {
|
||||
headers.push(("Date", mail_builder::headers::raw::Raw::new(date).into()));
|
||||
|
||||
let rfc724_mid = match &self.loaded {
|
||||
Loaded::Message { msg, .. } => msg.rfc724_mid.clone(),
|
||||
Loaded::Message { msg, .. } => match &self.pre_message_mode {
|
||||
Some(PreMessageMode::PreMessage { .. }) => create_outgoing_rfc724_mid(),
|
||||
_ => msg.rfc724_mid.clone(),
|
||||
},
|
||||
Loaded::Mdn { .. } => create_outgoing_rfc724_mid(),
|
||||
};
|
||||
headers.push((
|
||||
@@ -893,7 +910,7 @@ impl MimeFactory {
|
||||
));
|
||||
}
|
||||
|
||||
let is_encrypted = self.encryption_pubkeys.is_some();
|
||||
let is_encrypted = self.will_be_encrypted();
|
||||
|
||||
// Add ephemeral timer for non-MDN messages.
|
||||
// For MDNs it does not matter because they are not visible
|
||||
@@ -978,6 +995,22 @@ impl MimeFactory {
|
||||
"MIME-Version",
|
||||
mail_builder::headers::raw::Raw::new("1.0").into(),
|
||||
));
|
||||
|
||||
if self.pre_message_mode == Some(PreMessageMode::FullMessage) {
|
||||
unprotected_headers.push((
|
||||
"Chat-Is-Full-Message",
|
||||
mail_builder::headers::raw::Raw::new("1").into(),
|
||||
));
|
||||
} else if let Some(PreMessageMode::PreMessage {
|
||||
full_msg_rfc724_mid,
|
||||
}) = self.pre_message_mode.clone()
|
||||
{
|
||||
protected_headers.push((
|
||||
"Chat-Full-Message-ID",
|
||||
mail_builder::headers::message_id::MessageId::new(full_msg_rfc724_mid).into(),
|
||||
));
|
||||
}
|
||||
|
||||
for header @ (original_header_name, _header_value) in &headers {
|
||||
let header_name = original_header_name.to_lowercase();
|
||||
if header_name == "message-id" {
|
||||
@@ -1119,6 +1152,10 @@ impl MimeFactory {
|
||||
for (addr, key) in &encryption_pubkeys {
|
||||
let fingerprint = key.dc_fingerprint().hex();
|
||||
let cmd = msg.param.get_cmd();
|
||||
if self.pre_message_mode == Some(PreMessageMode::FullMessage) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let should_do_gossip = cmd == SystemMessage::MemberAddedToGroup
|
||||
|| cmd == SystemMessage::SecurejoinMessage
|
||||
|| multiple_recipients && {
|
||||
@@ -1875,8 +1912,12 @@ impl MimeFactory {
|
||||
|
||||
// add attachment part
|
||||
if msg.viewtype.has_file() {
|
||||
let file_part = build_body_file(context, &msg).await?;
|
||||
parts.push(file_part);
|
||||
if let Some(PreMessageMode::PreMessage { .. }) = self.pre_message_mode {
|
||||
// TODO: generate thumbnail and attach it instead (if it makes sense)
|
||||
} else {
|
||||
let file_part = build_body_file(context, &msg).await?;
|
||||
parts.push(file_part);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(msg_kml_part) = self.get_message_kml_part() {
|
||||
@@ -1921,6 +1962,8 @@ impl MimeFactory {
|
||||
}
|
||||
}
|
||||
|
||||
self.attach_selfavatar =
|
||||
self.attach_selfavatar && self.pre_message_mode != Some(PreMessageMode::FullMessage);
|
||||
if self.attach_selfavatar {
|
||||
match context.get_config(Config::Selfavatar).await? {
|
||||
Some(path) => match build_avatar_file(context, &path).await {
|
||||
@@ -1990,6 +2033,20 @@ impl MimeFactory {
|
||||
|
||||
Ok(message)
|
||||
}
|
||||
|
||||
pub fn will_be_encrypted(&self) -> bool {
|
||||
self.encryption_pubkeys.is_some()
|
||||
}
|
||||
|
||||
pub fn set_as_full_message(&mut self) {
|
||||
self.pre_message_mode = Some(PreMessageMode::FullMessage);
|
||||
}
|
||||
|
||||
pub fn set_as_pre_message_for(&mut self, full_message: &RenderedEmail) {
|
||||
self.pre_message_mode = Some(PreMessageMode::PreMessage {
|
||||
full_msg_rfc724_mid: full_message.rfc724_mid.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn hidden_recipients() -> Address<'static> {
|
||||
|
||||
Reference in New Issue
Block a user