]> git.cworth.org Git - sup/blobdiff - lib/sup/maildir.rb
from:me patch from Grant Hollingworth
[sup] / lib / sup / maildir.rb
index 012663d85eb7739173184c09009de42e9f08e106..ba9da001bc60cfbb9537578378e380d7999ea7d4 100644 (file)
@@ -11,24 +11,43 @@ module Redwood
 class Maildir < Source
   SCAN_INTERVAL = 30 # seconds
 
-  def initialize uri, last_date=nil, usual=true, archived=false, id=nil
-    super
-    uri = URI(uri)
+  ## remind me never to use inheritance again.
+  yaml_properties :uri, :cur_offset, :usual, :archived, :id, :labels
+  def initialize uri, last_date=nil, usual=true, archived=false, id=nil, labels=[]
+    super uri, last_date, usual, archived, id
+    uri = URI(Source.expand_filesystem_uri(uri))
 
     raise ArgumentError, "not a maildir URI" unless uri.scheme == "maildir"
     raise ArgumentError, "maildir URI cannot have a host: #{uri.host}" if uri.host
+    raise ArgumentError, "mbox URI must have a path component" unless uri.path
 
     @dir = uri.path
+    @labels = (labels || []).freeze
     @ids = []
     @ids_to_fns = {}
     @last_scan = nil
     @mutex = Mutex.new
   end
 
+  def file_path; @dir end
+  def self.suggest_labels_for path; [] end
+  def is_source_for? uri; super || (URI(Source.expand_filesystem_uri(uri)) == URI(self.uri)); end
+
   def check
     scan_mailbox
+    return unless start_offset
+
     start = @ids.index(cur_offset || start_offset) or raise OutOfSyncSourceError, "Unknown message id #{cur_offset || start_offset}." # couldn't find the most recent email
   end
+  
+  def each_raw_message_line id
+    scan_mailbox
+    with_file_for(id) do |f|
+      until f.eof?
+        yield f.gets
+      end
+    end
+  end
 
   def load_header id
     scan_mailbox
@@ -51,7 +70,7 @@ class Maildir < Source
     ret
   end
 
-  def raw_full_message id
+  def raw_message id
     scan_mailbox
     with_file_for(id) { |f| f.readlines.join }
   end
@@ -84,12 +103,14 @@ class Maildir < Source
 
   def each
     scan_mailbox
+    return unless start_offset
+
     start = @ids.index(cur_offset || start_offset) or raise OutOfSyncSourceError, "Unknown message id #{cur_offset || start_offset}." # couldn't find the most recent email
 
     start.upto(@ids.length - 1) do |i|         
       id = @ids[i]
       self.cur_offset = id
-      yield id, (@ids_to_fns[id] =~ /,.*R.*$/ ? [] : [:unread])
+      yield id, @labels + (seen?(id) ? [] : [:unread]) + (trashed?(id) ? [:deleted] : []) + (flagged?(id) ? [:starred] : [])
     end
   end
 
@@ -105,6 +126,20 @@ class Maildir < Source
 
   def pct_done; 100.0 * (@ids.index(cur_offset) || 0).to_f / (@ids.length - 1).to_f; end
 
+  def draft? msg; maildir_data(msg)[2].include? "D"; end
+  def flagged? msg; maildir_data(msg)[2].include? "F"; end
+  def passed? msg; maildir_data(msg)[2].include? "P"; end
+  def replied? msg; maildir_data(msg)[2].include? "R"; end
+  def seen? msg; maildir_data(msg)[2].include? "S"; end
+  def trashed? msg; maildir_data(msg)[2].include? "T"; end
+
+  def mark_draft msg; maildir_mark_file msg, "D" unless draft? msg; end
+  def mark_flagged msg; maildir_mark_file msg, "F" unless flagged? msg; end
+  def mark_passed msg; maildir_mark_file msg, "P" unless passed? msg; end
+  def mark_replied msg; maildir_mark_file msg, "R" unless replied? msg; end
+  def mark_seen msg; maildir_mark_file msg, "S" unless seen? msg; end
+  def mark_trashed msg; maildir_mark_file msg, "T" unless trashed? msg; end
+
 private
 
   def make_id fn
@@ -120,8 +155,29 @@ private
       raise FatalSourceError, "Problem reading file for id #{id.inspect}: #{fn.inspect}: #{e.message}."
     end
   end
-end
 
-Redwood::register_yaml(Maildir, %w(uri cur_offset usual archived id))
+  def maildir_data msg
+    fn = File.basename @ids_to_fns[msg]
+    fn =~ %r{^([^:,]+):([12]),([DFPRST]*)$}
+    [($1 || fn), ($2 || "2"), ($3 || "")]
+  end
+
+  ## not thread-safe on msg
+  def maildir_mark_file msg, flag
+    orig_path = @ids_to_fns[msg]
+    orig_base, orig_fn = File.split(orig_path)
+    new_base = orig_base.slice(0..-4) + 'cur'
+    tmp_base = orig_base.slice(0..-4) + 'tmp'
+    md_base, md_ver, md_flags = maildir_data msg
+    md_flags += flag; md_flags = md_flags.split(//).sort.join.squeeze
+    new_path = File.join new_base, "#{md_base}:#{md_ver},#{md_flags}"
+    tmp_path = File.join tmp_base, "#{md_base}:#{md_ver},#{md_flags}"
+    File.link orig_path, tmp_path
+    File.unlink orig_path
+    File.link tmp_path, new_path
+    File.unlink tmp_path
+    @ids_to_fns[msg] = new_path
+  end
+end
 
 end