]> git.cworth.org Git - sup/blobdiff - lib/sup/mbox/loader.rb
bugfix: :sent label not being applied to sent messages
[sup] / lib / sup / mbox / loader.rb
index 7fe912900e16d477fc7d690873d92e9c623f48c2..a11bf9541e6efed049754cf85442c6cdbd714c8b 100644 (file)
@@ -1,17 +1,20 @@
 require 'rmail'
 require 'uri'
 require 'rmail'
 require 'uri'
+require 'set'
 
 module Redwood
 module MBox
 
 class Loader < Source
 
 module Redwood
 module MBox
 
 class Loader < Source
+  include SerializeLabelsNicely
   yaml_properties :uri, :cur_offset, :usual, :archived, :id, :labels
   yaml_properties :uri, :cur_offset, :usual, :archived, :id, :labels
-  attr_accessor :labels
+
+  attr_reader :labels
 
   ## uri_or_fp is horrific. need to refactor.
 
   ## uri_or_fp is horrific. need to refactor.
-  def initialize uri_or_fp, start_offset=nil, usual=true, archived=false, id=nil, labels=[]
+  def initialize uri_or_fp, start_offset=0, usual=true, archived=false, id=nil, labels=nil
     @mutex = Mutex.new
     @mutex = Mutex.new
-    @labels = ((labels || []) - LabelManager::RESERVED_LABELS).uniq.freeze
+    @labels = Set.new((labels || []) - LabelManager::RESERVED_LABELS)
 
     case uri_or_fp
     when String
 
     case uri_or_fp
     when String
@@ -47,7 +50,7 @@ class Loader < Source
       raise OutOfSyncSourceError, "mbox file is smaller than last recorded message offset. Messages have probably been deleted by another client."
     end
   end
       raise OutOfSyncSourceError, "mbox file is smaller than last recorded message offset. Messages have probably been deleted by another client."
     end
   end
-    
+
   def start_offset; 0; end
   def end_offset; File.size @f; end
 
   def start_offset; 0; end
   def end_offset; File.size @f; end
 
@@ -56,10 +59,10 @@ class Loader < Source
     @mutex.synchronize do
       @f.seek offset
       l = @f.gets
     @mutex.synchronize do
       @f.seek offset
       l = @f.gets
-      unless l =~ BREAK_RE
+      unless MBox::is_break_line? l
         raise OutOfSyncSourceError, "mismatch in mbox file offset #{offset.inspect}: #{l.inspect}." 
       end
         raise OutOfSyncSourceError, "mismatch in mbox file offset #{offset.inspect}: #{l.inspect}." 
       end
-      header = MBox::read_header @f
+      header = parse_raw_email_header @f
     end
     header
   end
     end
     header
   end
@@ -68,25 +71,36 @@ class Loader < Source
     @mutex.synchronize do
       @f.seek offset
       begin
     @mutex.synchronize do
       @f.seek offset
       begin
-        RMail::Mailbox::MBoxReader.new(@f).each_message do |input|
-          m = RMail::Parser.read(input)
-          if m.body && m.body.is_a?(String)
-            m.body.gsub!(/^>From /, "From ")
-          end
-          return m
-        end
+        ## don't use RMail::Mailbox::MBoxReader because it doesn't properly ignore
+        ## "From" at the start of a message body line.
+        string = ""
+        l = @f.gets
+        string << l until @f.eof? || MBox::is_break_line?(l = @f.gets)
+        RMail::Parser.read string
       rescue RMail::Parser::Error => e
         raise FatalSourceError, "error parsing mbox file: #{e.message}"
       end
     end
   end
 
       rescue RMail::Parser::Error => e
         raise FatalSourceError, "error parsing mbox file: #{e.message}"
       end
     end
   end
 
+  ## scan forward until we're at the valid start of a message
+  def correct_offset!
+    @mutex.synchronize do
+      @f.seek cur_offset
+      string = ""
+      until @f.eof? || MBox::is_break_line?(l = @f.gets)
+        string << l
+      end
+      self.cur_offset += string.length
+    end
+  end
+
   def raw_header offset
     ret = ""
     @mutex.synchronize do
       @f.seek offset
       until @f.eof? || (l = @f.gets) =~ /^\r*$/
   def raw_header offset
     ret = ""
     @mutex.synchronize do
       @f.seek offset
       until @f.eof? || (l = @f.gets) =~ /^\r*$/
-        ret += l
+        ret << l
       end
     end
     ret
       end
     end
     ret
@@ -94,10 +108,19 @@ class Loader < Source
 
   def raw_message offset
     ret = ""
 
   def raw_message offset
     ret = ""
-    each_raw_message_line(offset) { |l| ret += l }
+    each_raw_message_line(offset) { |l| ret << l }
     ret
   end
 
     ret
   end
 
+  def store_message date, from_email, &block
+    need_blank = File.exists?(@filename) && !File.zero?(@filename)
+    File.open(@filename, "a") do |f|
+      f.puts if need_blank
+      f.puts "From #{from_email} #{date.utc}"
+      yield f
+    end
+  end
+
   ## apparently it's a million times faster to call this directly if
   ## we're just moving messages around on disk, than reading things
   ## into memory with raw_message.
   ## apparently it's a million times faster to call this directly if
   ## we're just moving messages around on disk, than reading things
   ## into memory with raw_message.
@@ -108,7 +131,7 @@ class Loader < Source
     @mutex.synchronize do
       @f.seek offset
       yield @f.gets
     @mutex.synchronize do
       @f.seek offset
       yield @f.gets
-      until @f.eof? || (l = @f.gets) =~ BREAK_RE
+      until @f.eof? || MBox::is_break_line?(l = @f.gets)
         yield l
       end
     end
         yield l
       end
     end
@@ -129,7 +152,7 @@ class Loader < Source
         ## 2. at the beginning of an mbox separator (in all other
         ##    cases).
 
         ## 2. at the beginning of an mbox separator (in all other
         ##    cases).
 
-        l = @f.gets or raise "next while at EOF"
+        l = @f.gets or return nil
         if l =~ /^\s*$/ # case 1
           returned_offset = @f.tell
           @f.gets # now we're at a BREAK_RE, so skip past it
         if l =~ /^\s*$/ # case 1
           returned_offset = @f.tell
           @f.gets # now we're at a BREAK_RE, so skip past it
@@ -139,7 +162,7 @@ class Loader < Source
         end
 
         while(line = @f.gets)
         end
 
         while(line = @f.gets)
-          break if line =~ BREAK_RE
+          break if MBox::is_break_line? line
           next_offset = @f.tell
         end
       end
           next_offset = @f.tell
         end
       end
@@ -148,7 +171,7 @@ class Loader < Source
     end
 
     self.cur_offset = next_offset
     end
 
     self.cur_offset = next_offset
-    [returned_offset, (self.labels + [:unread]).uniq]
+    [returned_offset, (labels + [:unread])]
   end
 end
 
   end
 end