@@ -66,8 +66,26 @@ pub struct MimeFactory {
66
66
67
67
selfstatus : String ,
68
68
69
- /// Vector of pairs of recipient name and address
70
- recipients : Vec < ( String , String ) > ,
69
+ /// Vector of actual recipient addresses.
70
+ ///
71
+ /// This is the list of addresses the message should be sent to.
72
+ /// It is not the same as the `To` header,
73
+ /// because in case of "member removed" message
74
+ /// removed member is in the recipient list,
75
+ /// but not in the `To` header.
76
+ /// In case of broadcast lists there are multiple recipients,
77
+ /// but the `To` header has no members.
78
+ ///
79
+ /// If `bcc_self` configuration is enabled,
80
+ /// this list will be extended with own address later,
81
+ /// but `MimeFactory` is not responsible for this.
82
+ recipients : Vec < String > ,
83
+
84
+ /// Vector of pairs of recipient name and address that goes into the `To` field.
85
+ ///
86
+ /// The list of actual message recipient addresses may be different,
87
+ /// e.g. if members are hidden for broadcast lists.
88
+ to : Vec < ( String , String ) > ,
71
89
72
90
/// Vector of pairs of past group member name and addresses.
73
91
past_members : Vec < ( String , String ) > ,
@@ -138,6 +156,7 @@ impl MimeFactory {
138
156
pub async fn from_msg ( context : & Context , msg : Message ) -> Result < MimeFactory > {
139
157
let chat = Chat :: load_from_db ( context, msg. chat_id ) . await ?;
140
158
let attach_profile_data = Self :: should_attach_profile_data ( & msg) ;
159
+ let undisclosed_recipients = chat. typ == Chattype :: Broadcast ;
141
160
142
161
let from_addr = context. get_primary_self_addr ( ) . await ?;
143
162
let config_displayname = context
@@ -155,23 +174,32 @@ impl MimeFactory {
155
174
( name, None )
156
175
} ;
157
176
158
- let mut recipients = Vec :: with_capacity ( 5 ) ;
177
+ let mut recipients = Vec :: new ( ) ;
178
+ let mut to = Vec :: new ( ) ;
159
179
let mut past_members = Vec :: new ( ) ;
160
180
let mut member_timestamps = Vec :: new ( ) ;
161
181
let mut recipient_ids = HashSet :: new ( ) ;
162
182
let mut req_mdn = false ;
163
183
164
184
if chat. is_self_talk ( ) {
165
185
if msg. param . get_cmd ( ) == SystemMessage :: AutocryptSetupMessage {
166
- recipients. push ( ( from_displayname. to_string ( ) , from_addr. to_string ( ) ) ) ;
186
+ recipients. push ( from_addr. to_string ( ) ) ;
187
+ to. push ( ( from_displayname. to_string ( ) , from_addr. to_string ( ) ) ) ;
167
188
}
168
189
} else if chat. is_mailing_list ( ) {
169
190
let list_post = chat
170
191
. param
171
192
. get ( Param :: ListPost )
172
193
. context ( "Can't write to mailinglist without ListPost param" ) ?;
173
- recipients. push ( ( "" . to_string ( ) , list_post. to_string ( ) ) ) ;
194
+ to. push ( ( "" . to_string ( ) , list_post. to_string ( ) ) ) ;
195
+ recipients. push ( list_post. to_string ( ) ) ;
174
196
} else {
197
+ let email_to_remove = if msg. param . get_cmd ( ) == SystemMessage :: MemberRemovedFromGroup {
198
+ msg. param . get ( Param :: Arg )
199
+ } else {
200
+ None
201
+ } ;
202
+
175
203
context
176
204
. sql
177
205
. query_map (
@@ -196,17 +224,37 @@ impl MimeFactory {
196
224
false => "" . to_string ( ) ,
197
225
} ;
198
226
if add_timestamp >= remove_timestamp {
199
- if !recipients_contain_addr ( & recipients, & addr) {
200
- recipients. push ( ( name, addr) ) ;
201
- member_timestamps. push ( add_timestamp) ;
227
+ if !recipients_contain_addr ( & to, & addr) {
228
+ recipients. push ( addr. clone ( ) ) ;
229
+ if !undisclosed_recipients {
230
+ if let Some ( email_to_remove) = email_to_remove {
231
+ if email_to_remove != addr {
232
+ to. push ( ( name, addr) ) ;
233
+ member_timestamps. push ( add_timestamp) ;
234
+ }
235
+ } else {
236
+ to. push ( ( name, addr) ) ;
237
+ member_timestamps. push ( add_timestamp) ;
238
+ }
239
+ }
202
240
}
203
241
recipient_ids. insert ( id) ;
204
242
} else {
205
243
// Row is a tombstone,
206
244
// member is not actually part of the group.
207
245
if !recipients_contain_addr ( & past_members, & addr) {
208
- past_members. push ( ( name, addr) ) ;
209
- member_timestamps. push ( remove_timestamp) ;
246
+ if let Some ( email_to_remove) = email_to_remove {
247
+ if email_to_remove == addr {
248
+ // This is a "member removed" message,
249
+ // we need to notify removed member
250
+ // that it was removed.
251
+ recipients. push ( addr. clone ( ) ) ;
252
+ }
253
+ }
254
+ if !undisclosed_recipients {
255
+ past_members. push ( ( name, addr) ) ;
256
+ member_timestamps. push ( remove_timestamp) ;
257
+ }
210
258
}
211
259
}
212
260
}
@@ -253,14 +301,15 @@ impl MimeFactory {
253
301
254
302
debug_assert ! (
255
303
member_timestamps. is_empty( )
256
- || recipients . len( ) + past_members. len( ) == member_timestamps. len( )
304
+ || to . len( ) + past_members. len( ) == member_timestamps. len( )
257
305
) ;
258
306
let factory = MimeFactory {
259
307
from_addr,
260
308
from_displayname,
261
309
sender_displayname,
262
310
selfstatus,
263
311
recipients,
312
+ to,
264
313
past_members,
265
314
member_timestamps,
266
315
timestamp : msg. timestamp_sort ,
@@ -290,7 +339,8 @@ impl MimeFactory {
290
339
from_displayname : "" . to_string ( ) ,
291
340
sender_displayname : None ,
292
341
selfstatus : "" . to_string ( ) ,
293
- recipients : vec ! [ ( "" . to_string( ) , contact. get_addr( ) . to_string( ) ) ] ,
342
+ recipients : vec ! [ contact. get_addr( ) . to_string( ) ] ,
343
+ to : vec ! [ ( "" . to_string( ) , contact. get_addr( ) . to_string( ) ) ] ,
294
344
past_members : vec ! [ ] ,
295
345
member_timestamps : vec ! [ ] ,
296
346
timestamp,
@@ -316,11 +366,7 @@ impl MimeFactory {
316
366
let self_addr = context. get_primary_self_addr ( ) . await ?;
317
367
318
368
let mut res = Vec :: new ( ) ;
319
- for ( _, addr) in self
320
- . recipients
321
- . iter ( )
322
- . filter ( |( _, addr) | addr != & self_addr)
323
- {
369
+ for addr in self . recipients . iter ( ) . filter ( |& addr| * addr != self_addr) {
324
370
res. push ( ( Peerstate :: from_addr ( context, addr) . await ?, addr. clone ( ) ) ) ;
325
371
}
326
372
@@ -508,10 +554,7 @@ impl MimeFactory {
508
554
}
509
555
510
556
pub fn recipients ( & self ) -> Vec < String > {
511
- self . recipients
512
- . iter ( )
513
- . map ( |( _, addr) | addr. clone ( ) )
514
- . collect ( )
557
+ self . recipients . clone ( )
515
558
}
516
559
517
560
/// Consumes a `MimeFactory` and renders it into a message which is then stored in
@@ -521,56 +564,26 @@ impl MimeFactory {
521
564
522
565
let from = new_address_with_name ( & self . from_displayname , self . from_addr . clone ( ) ) ;
523
566
524
- let undisclosed_recipients = match & self . loaded {
525
- Loaded :: Message { chat, .. } => chat. typ == Chattype :: Broadcast ,
526
- Loaded :: Mdn { .. } => false ,
527
- } ;
528
-
529
567
let mut to = Vec :: new ( ) ;
530
- let mut past_members = Vec :: new ( ) ; // Contents of `Chat-Group-Past-Members` header.
531
- if !undisclosed_recipients {
532
- let email_to_remove = match & self . loaded {
533
- Loaded :: Message { msg, .. } => {
534
- if msg. param . get_cmd ( ) == SystemMessage :: MemberRemovedFromGroup {
535
- msg. param . get ( Param :: Arg )
536
- } else {
537
- None
538
- }
539
- }
540
- Loaded :: Mdn { .. } => None ,
541
- } ;
542
-
543
- for ( name, addr) in & self . recipients {
544
- if let Some ( email_to_remove) = email_to_remove {
545
- if email_to_remove == addr {
546
- if name. is_empty ( ) {
547
- past_members. push ( Address :: new_mailbox ( addr. clone ( ) ) ) ;
548
- } else {
549
- past_members. push ( new_address_with_name ( name, addr. clone ( ) ) ) ;
550
- }
551
- continue ;
552
- }
553
- }
554
-
555
- if name. is_empty ( ) {
556
- to. push ( Address :: new_mailbox ( addr. clone ( ) ) ) ;
557
- } else {
558
- to. push ( new_address_with_name ( name, addr. clone ( ) ) ) ;
559
- }
568
+ for ( name, addr) in & self . to {
569
+ if name. is_empty ( ) {
570
+ to. push ( Address :: new_mailbox ( addr. clone ( ) ) ) ;
571
+ } else {
572
+ to. push ( new_address_with_name ( name, addr. clone ( ) ) ) ;
560
573
}
574
+ }
561
575
562
- for ( name , addr ) in & self . past_members {
563
- if name . is_empty ( ) {
564
- past_members . push ( Address :: new_mailbox ( addr . clone ( ) ) ) ;
565
- } else {
566
- past_members . push ( new_address_with_name ( name , addr . clone ( ) ) ) ;
567
- }
576
+ let mut past_members = Vec :: new ( ) ; // Contents of `Chat-Group-Past-Members` header.
577
+ for ( name , addr ) in & self . past_members {
578
+ if name . is_empty ( ) {
579
+ past_members . push ( Address :: new_mailbox ( addr . clone ( ) ) ) ;
580
+ } else {
581
+ past_members . push ( new_address_with_name ( name , addr . clone ( ) ) ) ;
568
582
}
569
583
}
570
584
571
585
debug_assert ! (
572
- undisclosed_recipients
573
- || self . member_timestamps. is_empty( )
586
+ self . member_timestamps. is_empty( )
574
587
|| to. len( ) + past_members. len( ) == self . member_timestamps. len( )
575
588
) ;
576
589
if to. is_empty ( ) {
@@ -597,7 +610,7 @@ impl MimeFactory {
597
610
) ;
598
611
}
599
612
600
- if !undisclosed_recipients && ! self . member_timestamps . is_empty ( ) {
613
+ if !self . member_timestamps . is_empty ( ) {
601
614
headers. push (
602
615
Header :: new_with_value (
603
616
"Chat-Group-Member-Timestamps" . into ( ) ,
0 commit comments