From e45ee0eb81f79de0757eaa0ff0ccde6d3b7448a8 Mon Sep 17 00:00:00 2001 From: holger krekel Date: Thu, 5 Dec 2019 14:24:05 +0100 Subject: [PATCH] try fix filename encoding bug -- fails in one test --- python/tests/test_account.py | 2 +- src/mimefactory.rs | 11 ++++------- src/mimeparser.rs | 13 +++++++++++-- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/python/tests/test_account.py b/python/tests/test_account.py index 98dd30bc2..86ac12896 100644 --- a/python/tests/test_account.py +++ b/python/tests/test_account.py @@ -448,7 +448,7 @@ class TestOnlineAccount: lp.sec("ac1: prepare and send attachment + text to ac2") blobdir = ac1.get_blobdir() - basename = "somedata.txt" # XXX try unicode + basename = "somedäüta.txt" p = os.path.join(blobdir, basename) with open(p, "w") as f: f.write("some data") diff --git a/src/mimefactory.rs b/src/mimefactory.rs index 56cc392e6..6c38f3615 100644 --- a/src/mimefactory.rs +++ b/src/mimefactory.rs @@ -980,21 +980,18 @@ fn build_body_file( } }; - let needs_ext = dc_needs_ext_header(&filename_to_send); - // create mime part, for Content-Disposition, see RFC 2183. // `Content-Disposition: attachment` seems not to make a difference to `Content-Disposition: inline` // at least on tested Thunderbird and Gma'l in 2017. // But I've heard about problems with inline and outl'k, so we just use the attachment-type until we // run into other problems ... - let cd_value = if needs_ext { - format!("attachment; filename=\"{}\"", &filename_to_send) - } else { - // XXX do we need to encode filenames? + let cd_value = if needs_encoding(&filename_to_send) { format!( "attachment; filename*=\"{}\"", quoted_printable::encode_to_str(&filename_to_send) ) + } else { + format!("attachment; filename=\"{}\"", &filename_to_send) }; let body = std::fs::read(blob.to_abs_path())?; @@ -1033,7 +1030,7 @@ fn is_file_size_okay(context: &Context, msg: &Message) -> bool { * Encode/decode header words, RFC 2047 ******************************************************************************/ -pub fn dc_needs_ext_header(to_check: impl AsRef) -> bool { +pub fn needs_encoding(to_check: impl AsRef) -> bool { let to_check = to_check.as_ref(); if to_check.is_empty() { diff --git a/src/mimeparser.rs b/src/mimeparser.rs index a345f8900..08d95ded7 100644 --- a/src/mimeparser.rs +++ b/src/mimeparser.rs @@ -579,14 +579,23 @@ impl<'a> MimeParser<'a> { // `Content-Disposition: ... filename*=...` // or `Content-Disposition: ... filename*0*=... filename*1*=... filename*2*=...` // or `Content-Disposition: ... filename=...` + use quoted_printable::ParseMode::Robust; let ct = mail.get_content_disposition()?; let mut desired_filename = ct .params .iter() .filter(|(key, _value)| key.starts_with("filename")) - .fold(String::new(), |mut acc, (_key, value)| { - acc += value; + .fold(String::new(), |mut acc, (key, value)| { + if key.starts_with("filename*") { + quoted_printable::decode(&value, Robust) + .map(|ref res| { + acc += &String::from_utf8_lossy(res); + }) + .ok(); + } else { + acc += value; + }; acc });