From ac12be507b1473e12004f552bf34e8b4d8209532 Mon Sep 17 00:00:00 2001 From: Dan Callaghan Date: Sun, 7 Jul 2024 22:21:57 +1000 Subject: [PATCH] encode attachments if they have lines longer than 998 chars As per: https://datatracker.ietf.org/doc/html/rfc5322#section-2.1.1 Fixes #489. --- Manifest.txt | 1 + lib/sup/util.rb | 9 ++++++++- test/unit/test_rmail_message.rb | 36 +++++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 test/unit/test_rmail_message.rb diff --git a/Manifest.txt b/Manifest.txt index ae9e19c0..481497d7 100644 --- a/Manifest.txt +++ b/Manifest.txt @@ -169,6 +169,7 @@ test/unit/test_edit_message_mode.rb test/unit/test_horizontal_selector.rb test/unit/test_locale_fiddler.rb test/unit/test_person.rb +test/unit/test_rmail_message.rb test/unit/util/test_query.rb test/unit/util/test_string.rb test/unit/util/test_uri.rb diff --git a/lib/sup/util.rb b/lib/sup/util.rb index a58d89df..b1e6a161 100644 --- a/lib/sup/util.rb +++ b/lib/sup/util.rb @@ -80,7 +80,14 @@ class Message def self.make_file_attachment fn bfn = File.basename fn t = MIME::Types.type_for(bfn).first || MIME::Types.type_for("exe").first - make_attachment IO.read(fn), t.content_type, t.encoding, bfn.to_s + payload = IO.read fn + ## Need to encode as base64 or quoted-printable if any lines are longer than 998 chars. + encoding = if t.encoding != t.default_encoding and payload.each_line.any? { |l| l.length > 998 } + t.default_encoding + else + t.encoding + end + make_attachment payload, t.content_type, encoding, bfn.to_s end def charset diff --git a/test/unit/test_rmail_message.rb b/test/unit/test_rmail_message.rb new file mode 100644 index 00000000..d0ef48f1 --- /dev/null +++ b/test/unit/test_rmail_message.rb @@ -0,0 +1,36 @@ +require "test_helper" + +require "sup" + +class TestRMailMessage < Minitest::Test + def setup + @path = Dir.mktmpdir + end + + def teardown + FileUtils.rm_r @path + end + + def test_make_file_attachment + filename = File.join @path, "test.html" + File.write filename, "" + + a = RMail::Message.make_file_attachment(filename) + assert_equal "text/html; name=\"test.html\"", a.header["Content-Type"] + assert_equal "attachment; filename=\"test.html\"", a.header["Content-Disposition"] + assert_equal "8bit", a.header["Content-Transfer-Encoding"] + end + + def test_make_file_attachment_text_with_long_lines + filename = File.join @path, "test.html" + File.write filename, "a" * 1023 + + a = RMail::Message.make_file_attachment(filename) + assert_equal "text/html; name=\"test.html\"", a.header["Content-Type"] + assert_equal "attachment; filename=\"test.html\"", a.header["Content-Disposition"] + assert_equal "quoted-printable", a.header["Content-Transfer-Encoding"] + + qp_encoded = ("a" * 73 + "=\n") * 14 + "a=\n" + assert_equal qp_encoded, a.body + end +end