sup

A curses threads-with-tags style email client

sup.git

git clone https://supmua.dev/git/sup/
commit 973d04f29b429bb81e3d9107f89311adf2d3fffd
parent d6d6c3f9d471e77c8abb3a249eca137e9174a7d2
Author: wmorgan <wmorgan@5c8cc53c-5e98-4d25-b20a-d8db53a31250>
Date:   Fri,  1 Dec 2006 19:39:28 +0000

added saving of message and attachments to disk (and some bugfixes in buffer
in support of this).


git-svn-id: svn://rubyforge.org/var/svn/sup/trunk@56 5c8cc53c-5e98-4d25-b20a-d8db53a31250

Diffstat:
M lib/sup/buffer.rb | 6 +++---
M lib/sup/draft.rb | 11 +++++++++--
M lib/sup/mbox/loader.rb | 21 ++++++++++++++++++---
M lib/sup/message.rb | 15 +++++++++++----
M lib/sup/modes/thread-view-mode.rb | 29 ++++++++++++++++++++++++++++-
M lib/sup/thread.rb | 2 ++
6 files changed, 71 insertions(+), 13 deletions(-)
diff --git a/lib/sup/buffer.rb b/lib/sup/buffer.rb
@@ -352,7 +352,7 @@ class BufferManager
     id ||= @minibuf_stack.length
     @minibuf_stack[id] = s
     unless @freeze
-      draw_minibuf
+      draw_screen
       Ncurses.refresh
     end
     id
@@ -363,7 +363,7 @@ class BufferManager
   def flash s
     @flash = s
     unless @freeze
-      draw_minibuf
+      draw_screen
       Ncurses.refresh
     end
   end
@@ -377,7 +377,7 @@ class BufferManager
       end
     end
     unless @freeze
-      draw_minibuf
+      draw_screen
       Ncurses.refresh
     end
   end
diff --git a/lib/sup/draft.rb b/lib/sup/draft.rb
@@ -77,8 +77,7 @@ class DraftLoader
     end
   end
 
-  ## load the full header text
-  def load_header_text offset
+  def raw_header offset
     ret = ""
     File.open fn_for_offset(offset) do |f|
       until f.eof? || (l = f.gets) =~ /^$/
@@ -88,6 +87,14 @@ class DraftLoader
     ret
   end
 
+  def raw_full_message offset
+    ret = ""
+    File.open fn_for_offset(offset) do |f|
+      ret += l until f.eof?
+    end
+    ret
+  end
+
   def each
     while File.exists?(fn = File.join(@dir, @end_offset.to_s))
       yield @end_offset, [:draft, :inbox]
diff --git a/lib/sup/mbox/loader.rb b/lib/sup/mbox/loader.rb
@@ -34,7 +34,11 @@ class Loader
       end).compact
   end
 
-  def reset!; @end_offset = 0; @dirty = true; end
+  def seek_to! offset
+    @end_offset = [offset, File.size(@f) - 1].min;
+    @dirty = true
+  end
+  def reset!; seek_to! 0; end
   def == o; o.is_a?(Loader) && o.filename == filename; end
   def to_s; "mbox://#{@filename}"; end
 
@@ -61,8 +65,7 @@ class Loader
     end
   end
 
-  ## load the full header text
-  def load_header_text offset
+  def raw_header offset
     ret = ""
     @mutex.synchronize do
       @f.seek offset
@@ -73,6 +76,18 @@ class Loader
     ret
   end
 
+  def raw_full_message offset
+    ret = ""
+    @mutex.synchronize do
+      @f.seek offset
+      @f.gets # skip mbox header
+      until @f.eof? || (l = @f.gets) =~ BREAK_RE
+        ret += l
+      end
+    end
+    ret
+  end
+
   def next
     return nil if done?
     @dirty = true
diff --git a/lib/sup/message.rb b/lib/sup/message.rb
@@ -27,24 +27,27 @@ class Message
   end
 
   class Attachment
-    attr_reader :content_type, :desc
+    attr_reader :content_type, :desc, :filename
     def initialize content_type, desc, part
       @content_type = content_type
       @desc = desc
       @part = part
       @file = nil
+      desc =~ /filename="(.*?)"/ && @filename = $1
     end
 
     def view!
       unless @file
         @file = Tempfile.new "redwood.attachment"
-        @file.print @part.decode
+        @file.print self
         @file.close
       end
 
       ## TODO: handle unknown mime-types
       system "/usr/bin/run-mailcap --action=view #{@content_type}:#{@file.path}"
     end
+
+    def to_s; @part.decode; end
   end
 
   class Text
@@ -171,8 +174,12 @@ class Message
     message_to_chunks m
   end
 
-  def header_text
-    @source.load_header_text @source_info
+  def raw_header
+    @source.raw_header @source_info
+  end
+
+  def raw_full_message
+    @source.raw_full_message @source_info
   end
 
   def content
diff --git a/lib/sup/modes/thread-view-mode.rb b/lib/sup/modes/thread-view-mode.rb
@@ -16,6 +16,7 @@ class ThreadViewMode < LineCursorMode
     k.add :collapse_non_new_messages, "Collapse all but new messages", 'N'
     k.add :reply, "Reply to a message", 'r'
     k.add :forward, "Forward a message", 'f'
+    k.add :save_to_disk, "Save message/attachment to disk", 's'
   end
 
   def initialize thread, hidden_labels=[]
@@ -62,7 +63,7 @@ class ThreadViewMode < LineCursorMode
   def show_header
     return unless(m = @message_lines[curpos])
     BufferManager.spawn_unless_exists("Full header") do
-      TextMode.new m.header_text
+      TextMode.new m.raw_header
     end
   end
 
@@ -109,6 +110,32 @@ class ThreadViewMode < LineCursorMode
     update
   end
 
+  def save fn
+    if File.exists? fn
+      return unless BufferManager.ask_yes_or_no "File exists. Overwrite?"
+    end
+    begin
+      File.open(fn, "w") { |f| yield f }
+      BufferManager.flash "Successfully wrote #{fn}."
+    rescue SystemCallError => e
+      BufferManager.flash "Error writing to file: #{e.message}"
+    end
+  end
+  private :save
+
+  def save_to_disk
+    return unless(chunk = @chunk_lines[curpos])
+    case chunk
+    when Message::Attachment
+      fn = BufferManager.ask :filename, "save attachment to file: ", chunk.filename
+      save(fn) { |f| f.print chunk } if fn
+    else
+      m = @message_lines[curpos]
+      fn = BufferManager.ask :filename, "save message to file: "
+      save(fn) { |f| f.print m.raw_full_message } if fn
+    end
+  end
+
   def edit_message
     return unless(m = @message_lines[curpos])
     if m.is_draft?
diff --git a/lib/sup/thread.rb b/lib/sup/thread.rb
@@ -321,6 +321,7 @@ class ThreadSet
       else
         ## to disable subject grouping, use the next line instead
         ## (and the same for below)
+        Redwood::log "[1] normalized subject for #{id} is #{Message.normalize_subj(root.subj)}"
         thread = (@subj_thread[Message.normalize_subj(root.subj)] ||= Thread.new)
         #thread = (@subj_thread[root.id] ||= Thread.new)
 
@@ -341,6 +342,7 @@ class ThreadSet
       else
         ## to disable subject grouping, use the next line instead
         ## (and the same above)
+        Redwood::log "[2] normalized subject for #{id} is #{Message.normalize_subj(root.subj)}"
         thread = (@subj_thread[Message.normalize_subj(root.subj)] ||= Thread.new)
         #thread = (@subj_thread[root.id] ||= Thread.new)