sup

A curses threads-with-tags style email client

sup.git

git clone https://supmua.dev/git/sup/
commit a0a496fa0fd6cbda3c9768bf0b8ad18b8f9013ce
parent a2bd945dc883e8f65222e84c61a72bd3541fac70
Author: Dan Callaghan <djc@djc.id.au>
Date:   Sat,  3 May 2025 15:58:20 +1000

handle drafts with missing Date header

Diffstat:
M lib/sup/draft.rb | 4 ++++
M lib/sup/source.rb | 2 ++
M test/integration/test_draft.rb | 29 ++++++++++++++++++++++++++++-
3 files changed, 34 insertions(+), 1 deletion(-)
diff --git a/lib/sup/draft.rb b/lib/sup/draft.rb
@@ -83,6 +83,10 @@ class DraftLoader < Source
     end
   end
 
+  def fallback_date_for_message offset
+    File.mtime fn_for_offset(offset)
+  end
+
   def raw_header offset
     ret = ""
     File.open(fn_for_offset(offset), "r:UTF-8") do |f|
diff --git a/lib/sup/source.rb b/lib/sup/source.rb
@@ -90,6 +90,8 @@ class Source
   ## the location filename
   def labels? info; [] end
 
+  def fallback_date_for_message info; end
+
   ## Yields values of the form [Symbol, Hash]
   ## add: info, labels, progress
   ## delete: info, progress
diff --git a/test/integration/test_draft.rb b/test/integration/test_draft.rb
@@ -23,7 +23,8 @@ EOS
     Index.init @path
     Index.load
     SourceManager.instance.instance_eval "@sources = {}"
-    SourceManager.add_source DraftManager.new_source
+    @draft_source = DraftManager.new_source
+    SourceManager.add_source @draft_source
   end
 
   def teardown
@@ -67,4 +68,30 @@ EOS
     DraftManager.discard message_in_index
     refute File.exist? draft_filename
   end
+
+  def test_load_malformed_draft
+    ## Sup always writes drafts by serialising a Message, meaning the draft is
+    ## guaranteed to have certain headers like Date. But it's always possible
+    ## for the user to edit the draft directly on the filesystem and leave it
+    ## in some kind of malformed state. Sup should handle it without crashing.
+    draft_filename = File.join @draft_dir, "0"
+    fallback_date = Time.new 2025, 5, 3, 15, 47, 41
+    File.write draft_filename, <<EOS
+Some-Header: Value
+
+body
+EOS
+    File.utime fallback_date, fallback_date, draft_filename
+    PollManager.poll_from @draft_source
+    messages_in_index = Index.instance.enum_for(:each_message).to_a
+    assert_equal "", messages_in_index[0].subj
+    assert_equal fallback_date, messages_in_index[0].date
+
+    File.write (File.join @draft_dir, "1"), <<EOS
+missing a header!
+EOS
+    PollManager.poll_from @draft_source
+    messages_in_index = Index.instance.enum_for(:each_message).to_a
+    assert_equal "", messages_in_index[0].subj
+  end
 end