@@ -277,7 +277,7 @@ impl<'a> MimeFactory<'a> {
277
277
async fn peerstates_for_recipients (
278
278
& self ,
279
279
context : & Context ,
280
- ) -> Result < Vec < ( Option < Peerstate > , & str ) > > {
280
+ ) -> Result < Vec < ( Option < Peerstate > , String ) > > {
281
281
let self_addr = context. get_primary_self_addr ( ) . await ?;
282
282
283
283
let mut res = Vec :: new ( ) ;
@@ -286,7 +286,7 @@ impl<'a> MimeFactory<'a> {
286
286
. iter ( )
287
287
. filter ( |( _, addr) | addr != & self_addr)
288
288
{
289
- res. push ( ( Peerstate :: from_addr ( context, addr) . await ?, addr. as_str ( ) ) ) ;
289
+ res. push ( ( Peerstate :: from_addr ( context, addr) . await ?, addr. clone ( ) ) ) ;
290
290
}
291
291
292
292
Ok ( res)
@@ -917,6 +917,16 @@ impl<'a> MimeFactory<'a> {
917
917
Ok ( Some ( part) )
918
918
}
919
919
920
+ fn add_message_text ( & self , part : PartBuilder , mut text : String ) -> PartBuilder {
921
+ // This is needed to protect from ESPs (such as gmx.at) doing their own Quoted-Printable
922
+ // encoding and thus breaking messages and signatures. It's unlikely that the reader uses a
923
+ // MUA not supporting Quoted-Printable encoding. And RFC 2646 "4.6" also recommends it for
924
+ // encrypted messages.
925
+ let part = part. header ( ( "Content-Transfer-Encoding" , "quoted-printable" ) ) ;
926
+ text = quoted_printable:: encode_to_str ( text) ;
927
+ part. body ( text)
928
+ }
929
+
920
930
#[ allow( clippy:: cognitive_complexity) ]
921
931
async fn render_message (
922
932
& mut self ,
@@ -1214,13 +1224,11 @@ impl<'a> MimeFactory<'a> {
1214
1224
footer
1215
1225
) ;
1216
1226
1217
- // Message is sent as text/plain, with charset = utf-8
1218
- let mut main_part = PartBuilder :: new ( )
1219
- . header ( (
1220
- "Content-Type" . to_string ( ) ,
1221
- "text/plain; charset=utf-8; format=flowed; delsp=no" . to_string ( ) ,
1222
- ) )
1223
- . body ( message_text) ;
1227
+ let mut main_part = PartBuilder :: new ( ) . header ( (
1228
+ "Content-Type" ,
1229
+ "text/plain; charset=utf-8; format=flowed; delsp=no" ,
1230
+ ) ) ;
1231
+ main_part = self . add_message_text ( main_part, message_text) ;
1224
1232
1225
1233
if is_reaction {
1226
1234
main_part = main_part. header ( ( "Content-Disposition" , "reaction" ) ) ;
@@ -1347,15 +1355,12 @@ impl<'a> MimeFactory<'a> {
1347
1355
} ;
1348
1356
let p2 = stock_str:: read_rcpt_mail_body ( context, & p1) . await ;
1349
1357
let message_text = format ! ( "{}\r \n " , format_flowed( & p2) ) ;
1350
- message = message. child (
1351
- PartBuilder :: new ( )
1352
- . header ( (
1353
- "Content-Type" . to_string ( ) ,
1354
- "text/plain; charset=utf-8; format=flowed; delsp=no" . to_string ( ) ,
1355
- ) )
1356
- . body ( message_text)
1357
- . build ( ) ,
1358
- ) ;
1358
+ let text_part = PartBuilder :: new ( ) . header ( (
1359
+ "Content-Type" . to_string ( ) ,
1360
+ "text/plain; charset=utf-8; format=flowed; delsp=no" . to_string ( ) ,
1361
+ ) ) ;
1362
+ let text_part = self . add_message_text ( text_part, message_text) ;
1363
+ message = message. child ( text_part. build ( ) ) ;
1359
1364
1360
1365
// second body part: machine-readable, always REQUIRED by RFC 6522
1361
1366
let message_text2 = format ! (
@@ -2198,6 +2203,7 @@ mod tests {
2198
2203
assert_eq ! ( inner. match_indices( "Message-ID:" ) . count( ) , 1 ) ;
2199
2204
assert_eq ! ( inner. match_indices( "Chat-User-Avatar:" ) . count( ) , 1 ) ;
2200
2205
assert_eq ! ( inner. match_indices( "Subject:" ) . count( ) , 0 ) ;
2206
+ assert_eq ! ( inner. match_indices( "quoted-printable" ) . count( ) , 1 ) ;
2201
2207
2202
2208
assert_eq ! ( body. match_indices( "this is the text!" ) . count( ) , 1 ) ;
2203
2209
@@ -2218,6 +2224,7 @@ mod tests {
2218
2224
assert_eq ! ( inner. match_indices( "Message-ID:" ) . count( ) , 1 ) ;
2219
2225
assert_eq ! ( inner. match_indices( "Chat-User-Avatar:" ) . count( ) , 0 ) ;
2220
2226
assert_eq ! ( inner. match_indices( "Subject:" ) . count( ) , 0 ) ;
2227
+ assert_eq ! ( inner. match_indices( "quoted-printable" ) . count( ) , 1 ) ;
2221
2228
2222
2229
assert_eq ! ( body. match_indices( "this is the text!" ) . count( ) , 1 ) ;
2223
2230
@@ -2274,6 +2281,7 @@ mod tests {
2274
2281
assert_eq ! ( part. match_indices( "Message-ID:" ) . count( ) , 1 ) ;
2275
2282
assert_eq ! ( part. match_indices( "Chat-User-Avatar:" ) . count( ) , 1 ) ;
2276
2283
assert_eq ! ( part. match_indices( "Subject:" ) . count( ) , 0 ) ;
2284
+ assert_eq ! ( part. match_indices( "quoted-printable" ) . count( ) , 1 ) ;
2277
2285
2278
2286
let body = payload. next ( ) . unwrap ( ) ;
2279
2287
assert_eq ! ( body. match_indices( "this is the text!" ) . count( ) , 1 ) ;
@@ -2321,6 +2329,7 @@ mod tests {
2321
2329
assert_eq ! ( part. match_indices( "Message-ID:" ) . count( ) , 1 ) ;
2322
2330
assert_eq ! ( part. match_indices( "Chat-User-Avatar:" ) . count( ) , 0 ) ;
2323
2331
assert_eq ! ( part. match_indices( "Subject:" ) . count( ) , 0 ) ;
2332
+ assert_eq ! ( part. match_indices( "quoted-printable" ) . count( ) , 1 ) ;
2324
2333
2325
2334
let body = payload. next ( ) . unwrap ( ) ;
2326
2335
assert_eq ! ( body. match_indices( "this is the text!" ) . count( ) , 1 ) ;
0 commit comments