@@ -13,6 +13,7 @@ use mail_builder::headers::HeaderType;
13
13
use mail_builder:: mime:: MimePart ;
14
14
use tokio:: fs;
15
15
16
+ use crate :: aheader:: { Aheader , EncryptPreference } ;
16
17
use crate :: blob:: BlobObject ;
17
18
use crate :: chat:: { self , Chat } ;
18
19
use crate :: config:: Config ;
@@ -22,6 +23,7 @@ use crate::contact::{Contact, ContactId, Origin};
22
23
use crate :: context:: Context ;
23
24
use crate :: e2ee:: EncryptHelper ;
24
25
use crate :: ephemeral:: Timer as EphemeralTimer ;
26
+ use crate :: key:: DcKey ;
25
27
use crate :: location;
26
28
use crate :: message:: { self , Message , MsgId , Viewtype } ;
27
29
use crate :: mimeparser:: { is_hidden, SystemMessage } ;
@@ -131,7 +133,6 @@ pub struct RenderedEmail {
131
133
pub message : String ,
132
134
// pub envelope: Envelope,
133
135
pub is_encrypted : bool ,
134
- pub is_gossiped : bool ,
135
136
pub last_added_location_id : Option < u32 > ,
136
137
137
138
/// A comma-separated string of sync-IDs that are used by the rendered email and must be deleted
@@ -433,41 +434,6 @@ impl MimeFactory {
433
434
}
434
435
}
435
436
436
- async fn should_do_gossip ( & self , context : & Context , multiple_recipients : bool ) -> Result < bool > {
437
- match & self . loaded {
438
- Loaded :: Message { chat, msg } => {
439
- if chat. typ == Chattype :: Broadcast {
440
- // Never send Autocrypt-Gossip in broadcast lists
441
- // as it discloses recipient email addresses.
442
- return Ok ( false ) ;
443
- }
444
-
445
- let cmd = msg. param . get_cmd ( ) ;
446
- if cmd == SystemMessage :: MemberAddedToGroup
447
- || cmd == SystemMessage :: SecurejoinMessage
448
- {
449
- Ok ( true )
450
- } else if multiple_recipients {
451
- // beside key- and member-changes, force a periodic re-gossip.
452
- let gossiped_timestamp = chat. id . get_gossiped_timestamp ( context) . await ?;
453
- let gossip_period = context. get_config_i64 ( Config :: GossipPeriod ) . await ?;
454
- // `gossip_period == 0` is a special case for testing,
455
- // enabling gossip in every message.
456
- // Otherwise "smeared timestamps" may result in the condition
457
- // to fail even if the clock is monotonic.
458
- if gossip_period == 0 || time ( ) >= gossiped_timestamp + gossip_period {
459
- Ok ( true )
460
- } else {
461
- Ok ( false )
462
- }
463
- } else {
464
- Ok ( false )
465
- }
466
- }
467
- Loaded :: Mdn { .. } => Ok ( false ) ,
468
- }
469
- }
470
-
471
437
fn should_attach_profile_data ( msg : & Message ) -> bool {
472
438
msg. param . get_cmd ( ) != SystemMessage :: SecurejoinMessage || {
473
439
let step = msg. param . get ( Param :: Arg ) . unwrap_or_default ( ) ;
@@ -787,8 +753,6 @@ impl MimeFactory {
787
753
}
788
754
}
789
755
790
- let mut is_gossiped = false ;
791
-
792
756
let peerstates = self . peerstates_for_recipients ( context) . await ?;
793
757
let is_encrypted = !self . should_force_plaintext ( )
794
758
&& ( e2ee_guaranteed || encrypt_helper. should_encrypt ( context, & peerstates) . await ?) ;
@@ -956,16 +920,78 @@ impl MimeFactory {
956
920
// Add gossip headers in chats with multiple recipients
957
921
let multiple_recipients =
958
922
peerstates. len ( ) > 1 || context. get_config_bool ( Config :: BccSelf ) . await ?;
959
- if self . should_do_gossip ( context, multiple_recipients) . await ? {
960
- for peerstate in peerstates. iter ( ) . filter_map ( |( state, _) | state. as_ref ( ) ) {
961
- if let Some ( header) = peerstate. render_gossip_header ( verified) {
962
- message = message. header (
963
- "Autocrypt-Gossip" ,
964
- mail_builder:: headers:: raw:: Raw :: new ( header) ,
965
- ) ;
966
- is_gossiped = true ;
923
+
924
+ let gossip_period = context. get_config_i64 ( Config :: GossipPeriod ) . await ?;
925
+ let now = time ( ) ;
926
+
927
+ match & self . loaded {
928
+ Loaded :: Message { chat, msg } => {
929
+ if chat. typ != Chattype :: Broadcast {
930
+ for peerstate in peerstates. iter ( ) . filter_map ( |( state, _) | state. as_ref ( ) ) {
931
+ let Some ( key) = peerstate. peek_key ( verified) else {
932
+ continue ;
933
+ } ;
934
+
935
+ let fingerprint = key. dc_fingerprint ( ) . hex ( ) ;
936
+ let cmd = msg. param . get_cmd ( ) ;
937
+ let should_do_gossip = cmd == SystemMessage :: MemberAddedToGroup
938
+ || cmd == SystemMessage :: SecurejoinMessage
939
+ || multiple_recipients && {
940
+ let gossiped_timestamp: Option < i64 > = context
941
+ . sql
942
+ . query_get_value (
943
+ "SELECT timestamp
944
+ FROM gossip_timestamp
945
+ WHERE chat_id=? AND fingerprint=?" ,
946
+ ( chat. id , & fingerprint) ,
947
+ )
948
+ . await ?;
949
+
950
+ // `gossip_period == 0` is a special case for testing,
951
+ // enabling gossip in every message.
952
+ //
953
+ // If current time is in the past compared to
954
+ // `gossiped_timestamp`, we also gossip because
955
+ // either the `gossiped_timestamp` or clock is wrong.
956
+ gossip_period == 0
957
+ || gossiped_timestamp
958
+ . is_none_or ( |ts| now >= ts + gossip_period || now < ts)
959
+ } ;
960
+
961
+ if !should_do_gossip {
962
+ continue ;
963
+ }
964
+
965
+ let header = Aheader :: new (
966
+ peerstate. addr . clone ( ) ,
967
+ key. clone ( ) ,
968
+ // Autocrypt 1.1.0 specification says that
969
+ // `prefer-encrypt` attribute SHOULD NOT be included.
970
+ EncryptPreference :: NoPreference ,
971
+ )
972
+ . to_string ( ) ;
973
+
974
+ message = message. header (
975
+ "Autocrypt-Gossip" ,
976
+ mail_builder:: headers:: raw:: Raw :: new ( header) ,
977
+ ) ;
978
+
979
+ context
980
+ . sql
981
+ . execute (
982
+ "INSERT INTO gossip_timestamp (chat_id, fingerprint, timestamp)
983
+ VALUES (?, ?, ?)
984
+ ON CONFLICT (chat_id, fingerprint)
985
+ DO UPDATE SET timestamp=excluded.timestamp" ,
986
+ ( chat. id , & fingerprint, now) ,
987
+ )
988
+ . await ?;
989
+ }
967
990
}
968
991
}
992
+ Loaded :: Mdn { .. } => {
993
+ // Never gossip in MDNs.
994
+ }
969
995
}
970
996
971
997
// Set the appropriate Content-Type for the inner message.
@@ -1109,7 +1135,6 @@ impl MimeFactory {
1109
1135
message,
1110
1136
// envelope: Envelope::new,
1111
1137
is_encrypted,
1112
- is_gossiped,
1113
1138
last_added_location_id,
1114
1139
sync_ids_to_delete : self . sync_ids_to_delete ,
1115
1140
rfc724_mid,
0 commit comments