sup

A curses threads-with-tags style email client

sup.git

git clone https://supmua.dev/git/sup/
commit ac12be507b1473e12004f552bf34e8b4d8209532
parent f3b63120aa7c7610cf691f31e5998988ff813586
Author: Dan Callaghan <djc@djc.id.au>
Date:   Sun,  7 Jul 2024 22:21:57 +1000

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.

Diffstat:
M Manifest.txt | 1 +
M lib/sup/util.rb | 9 ++++++++-
A test/unit/test_rmail_message.rb | 36 ++++++++++++++++++++++++++++++++++++
3 files changed, 45 insertions(+), 1 deletion(-)
diff --git 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
@@ -80,7 +80,14 @@ module RMail
     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
@@ -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, "<html></html>"
+
+    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