@@ -57,6 +57,10 @@ pub(crate) struct MimeMessage {
57
57
/// Message headers.
58
58
headers : HashMap < String , String > ,
59
59
60
+ #[ cfg( test) ]
61
+ /// Names of removed (ignored) headers. Used by `header_exists()` needed for tests.
62
+ headers_removed : HashSet < String > ,
63
+
60
64
/// List of addresses from the `To` and `Cc` headers.
61
65
///
62
66
/// Addresses are normalized and lowercase.
@@ -236,6 +240,7 @@ impl MimeMessage {
236
240
let mut hop_info = parse_receive_headers ( & mail. get_headers ( ) ) ;
237
241
238
242
let mut headers = Default :: default ( ) ;
243
+ let mut headers_removed = HashSet :: < String > :: new ( ) ;
239
244
let mut recipients = Default :: default ( ) ;
240
245
let mut past_members = Default :: default ( ) ;
241
246
let mut from = Default :: default ( ) ;
@@ -253,7 +258,12 @@ impl MimeMessage {
253
258
& mut chat_disposition_notification_to,
254
259
& mail. headers ,
255
260
) ;
256
- headers. retain ( |k, _| !is_hidden ( k) ) ;
261
+ headers. retain ( |k, _| {
262
+ !is_hidden ( k) || {
263
+ headers_removed. insert ( k. clone ( ) ) ;
264
+ false
265
+ }
266
+ } ) ;
257
267
258
268
// Parse hidden headers.
259
269
let mimetype = mail. ctype . mimetype . parse :: < Mime > ( ) ?;
@@ -298,9 +308,11 @@ impl MimeMessage {
298
308
// Overwrite Message-ID with X-Microsoft-Original-Message-ID.
299
309
// However if we later find Message-ID in the protected part,
300
310
// it will overwrite both.
301
- if let Some ( microsoft_message_id) =
302
- headers. remove ( HeaderDef :: XMicrosoftOriginalMessageId . get_headername ( ) )
303
- {
311
+ if let Some ( microsoft_message_id) = remove_header (
312
+ & mut headers,
313
+ HeaderDef :: XMicrosoftOriginalMessageId . get_headername ( ) ,
314
+ & mut headers_removed,
315
+ ) {
304
316
headers. insert (
305
317
HeaderDef :: MessageId . get_headername ( ) . to_string ( ) ,
306
318
microsoft_message_id,
@@ -309,7 +321,7 @@ impl MimeMessage {
309
321
310
322
// Remove headers that are allowed _only_ in the encrypted+signed part. It's ok to leave
311
323
// them in signed-only emails, but has no value currently.
312
- Self :: remove_secured_headers ( & mut headers) ;
324
+ Self :: remove_secured_headers ( & mut headers, & mut headers_removed ) ;
313
325
314
326
let mut from = from. context ( "No from in message" ) ?;
315
327
let private_keyring = load_self_secret_keyring ( context) . await ?;
@@ -442,7 +454,7 @@ impl MimeMessage {
442
454
HeaderDef :: ChatEdit ,
443
455
HeaderDef :: ChatUserAvatar ,
444
456
] {
445
- headers . remove ( h. get_headername ( ) ) ;
457
+ remove_header ( & mut headers , h. get_headername ( ) , & mut headers_removed ) ;
446
458
}
447
459
}
448
460
@@ -506,7 +518,7 @@ impl MimeMessage {
506
518
}
507
519
}
508
520
if signatures. is_empty ( ) {
509
- Self :: remove_secured_headers ( & mut headers) ;
521
+ Self :: remove_secured_headers ( & mut headers, & mut headers_removed ) ;
510
522
511
523
// If it is not a read receipt, degrade encryption.
512
524
if let ( Some ( peerstate) , Ok ( mail) ) = ( & mut peerstate, mail) {
@@ -530,6 +542,9 @@ impl MimeMessage {
530
542
let mut parser = MimeMessage {
531
543
parts : Vec :: new ( ) ,
532
544
headers,
545
+ #[ cfg( test) ]
546
+ headers_removed,
547
+
533
548
recipients,
534
549
past_members,
535
550
list_post,
@@ -931,6 +946,16 @@ impl MimeMessage {
931
946
. map ( |s| s. as_str ( ) )
932
947
}
933
948
949
+ #[ cfg( test) ]
950
+ /// Returns whether the header exists in any part of the parsed message.
951
+ ///
952
+ /// Use this to check for header absense. Header presense should be checked using
953
+ /// `get_header(...).is_some()` as it also checks that the header isn't ignored.
954
+ pub ( crate ) fn header_exists ( & self , headerdef : HeaderDef ) -> bool {
955
+ let hname = headerdef. get_headername ( ) ;
956
+ self . headers . contains_key ( hname) || self . headers_removed . contains ( hname)
957
+ }
958
+
934
959
/// Returns `Chat-Group-ID` header value if it is a valid group ID.
935
960
pub fn get_chat_group_id ( & self ) -> Option < & str > {
936
961
self . get_header ( HeaderDef :: ChatGroupId )
@@ -1526,14 +1551,17 @@ impl MimeMessage {
1526
1551
. and_then ( |msgid| parse_message_id ( msgid) . ok ( ) )
1527
1552
}
1528
1553
1529
- fn remove_secured_headers ( headers : & mut HashMap < String , String > ) {
1530
- headers. remove ( "secure-join-fingerprint" ) ;
1531
- headers. remove ( "secure-join-auth" ) ;
1532
- headers. remove ( "chat-verified" ) ;
1533
- headers. remove ( "autocrypt-gossip" ) ;
1554
+ fn remove_secured_headers (
1555
+ headers : & mut HashMap < String , String > ,
1556
+ removed : & mut HashSet < String > ,
1557
+ ) {
1558
+ remove_header ( headers, "secure-join-fingerprint" , removed) ;
1559
+ remove_header ( headers, "secure-join-auth" , removed) ;
1560
+ remove_header ( headers, "chat-verified" , removed) ;
1561
+ remove_header ( headers, "autocrypt-gossip" , removed) ;
1534
1562
1535
1563
// Secure-Join is secured unless it is an initial "vc-request"/"vg-request".
1536
- if let Some ( secure_join) = headers . remove ( "secure-join" ) {
1564
+ if let Some ( secure_join) = remove_header ( headers , "secure-join" , removed ) {
1537
1565
if secure_join == "vc-request" || secure_join == "vg-request" {
1538
1566
headers. insert ( "secure-join" . to_string ( ) , secure_join) ;
1539
1567
}
@@ -1861,6 +1889,19 @@ impl MimeMessage {
1861
1889
}
1862
1890
}
1863
1891
1892
+ fn remove_header (
1893
+ headers : & mut HashMap < String , String > ,
1894
+ key : & str ,
1895
+ removed : & mut HashSet < String > ,
1896
+ ) -> Option < String > {
1897
+ if let Some ( ( k, v) ) = headers. remove_entry ( key) {
1898
+ removed. insert ( k) ;
1899
+ Some ( v)
1900
+ } else {
1901
+ None
1902
+ }
1903
+ }
1904
+
1864
1905
/// Parses `Autocrypt-Gossip` headers from the email and applies them to peerstates.
1865
1906
/// Params:
1866
1907
/// from: The address which sent the message currently being parsed
0 commit comments