add multi-device sync (#2669)

* add basic multi-device-sync functions

* generate json

* add context.parse_sync_items()

* add context.execute_sync_items()

* piggyback sync-commands message, add body for human-readable part

* avoid double json renderings

* mimeparser parses incoming .json sync-files

* do not piggyback sync-files

* execute sync items

* return status of send_sync_msg()

* send sync messages as multipart/report

* add a per-item-timestamp and also allow adding other per-item-fields in the future

* if the self-chat does not exist, create it blocked/hidden

* create tokens closer to real qr-code needs

* respect bcc_self setting, add test for that

* sync qr code tokens after promoting groups

* send sync-messages only if an experimental switch is set

* trigger send_sync_msg() after sending messages and after creating/redraw/revive qr-code

* add DC_STR_* constants to deltachat.h

* adapt to refactored qr module as of #2729

* tweak test

* use SendSyncMsgs config name instead of SendExperimentalSyncMsgs - we can remove or rename the config nevertheless, but have the option to keep it without renaming

* tweak docs

* remove currently unused effective timestamp calculation

* clarify when send_sync_msg() is called

* make sure, sync-messages are encrypted and are sent by SELF

* tweak docs, fix typos
This commit is contained in:
bjoern
2021-10-25 12:40:32 +02:00
committed by GitHub
parent bb97d842df
commit 65f09c238b
16 changed files with 719 additions and 16 deletions

View File

@@ -68,6 +68,13 @@ pub struct MimeFactory<'a> {
references: String,
req_mdn: bool,
last_added_location_id: u32,
/// If the created mime-structure contains sync-items,
/// the IDs of these items are listed here.
/// The IDs are returned via `RenderedEmail`
/// and must be deleted if the message is actually queued for sending.
sync_ids_to_delete: Option<String>,
attach_selfavatar: bool,
}
@@ -80,6 +87,12 @@ pub struct RenderedEmail {
pub is_gossiped: bool,
pub last_added_location_id: u32,
/// A comma-separated string of sync-IDs that are used by the rendered email
/// and must be deleted once the message is actually queued for sending
/// (deletion must be done by `delete_sync_ids()`).
/// If the rendered email is not queued for sending, the IDs must not be deleted.
pub sync_ids_to_delete: Option<String>,
/// Message ID (Message in the sense of Email)
pub rfc724_mid: String,
pub subject: String,
@@ -205,6 +218,7 @@ impl<'a> MimeFactory<'a> {
references,
req_mdn,
last_added_location_id: 0,
sync_ids_to_delete: None,
attach_selfavatar,
};
Ok(factory)
@@ -249,6 +263,7 @@ impl<'a> MimeFactory<'a> {
references: String::default(),
req_mdn: false,
last_added_location_id: 0,
sync_ids_to_delete: None,
attach_selfavatar: false,
};
@@ -603,12 +618,20 @@ impl<'a> MimeFactory<'a> {
main_part
} else {
// Multiple parts, render as multipart.
parts.into_iter().fold(
PartBuilder::new()
.message_type(MimeMultipartType::Mixed)
.child(main_part.build()),
|message, part| message.child(part.build()),
)
let part_holder = if self.msg.param.get_cmd() == SystemMessage::MultiDeviceSync {
PartBuilder::new().header((
"Content-Type".to_string(),
"multipart/report; report-type=multi-device-sync".to_string(),
))
} else {
PartBuilder::new().message_type(MimeMultipartType::Mixed)
};
parts
.into_iter()
.fold(part_holder.child(main_part.build()), |message, part| {
message.child(part.build())
})
};
let outer_message = if is_encrypted {
@@ -729,6 +752,7 @@ impl<'a> MimeFactory<'a> {
is_encrypted,
is_gossiped,
last_added_location_id,
sync_ids_to_delete: self.sync_ids_to_delete,
rfc724_mid,
subject: subject_str,
})
@@ -873,7 +897,7 @@ impl<'a> MimeFactory<'a> {
"ephemeral-timer-changed".to_string(),
));
}
SystemMessage::LocationOnly => {
SystemMessage::LocationOnly | SystemMessage::MultiDeviceSync => {
// This should prevent automatic replies,
// such as non-delivery reports.
//
@@ -1103,6 +1127,15 @@ impl<'a> MimeFactory<'a> {
}
}
// we do not piggyback sync-files to other self-sent-messages
// to not risk files becoming too larger and being skipped by download-on-demand.
if command == SystemMessage::MultiDeviceSync && self.is_e2ee_guaranteed() {
let json = self.msg.param.get(Param::Arg).unwrap_or_default();
let ids = self.msg.param.get(Param::Arg2).unwrap_or_default();
parts.push(context.build_sync_part(json.to_string()).await);
self.sync_ids_to_delete = Some(ids.to_string());
}
if self.attach_selfavatar {
match context.get_config(Config::Selfavatar).await? {
Some(path) => match build_selfavatar_file(context, &path) {