class Redwood::MBox::Loader

Attributes

labels[R]

Public Class Methods

new(uri_or_fp, start_offset=nil, usual=true, archived=false, id=nil, labels=nil) click to toggle source

uri_or_fp is horrific. need to refactor.

# File lib/sup/mbox/loader.rb, line 15
def initialize uri_or_fp, start_offset=nil, usual=true, archived=false, id=nil, labels=nil
  @mutex = Mutex.new
  @labels = Set.new((labels || []) - LabelManager::RESERVED_LABELS)

  case uri_or_fp
  when String
    uri = URI(Source.expand_filesystem_uri(uri_or_fp))
    raise ArgumentError, "not an mbox uri" unless uri.scheme == "mbox"
    raise ArgumentError, "mbox URI ('#{uri}') cannot have a host: #{uri.host}" if uri.host
    raise ArgumentError, "mbox URI must have a path component" unless uri.path
    @f = File.open uri.path, 'rb'
    @path = uri.path
  else
    @f = uri_or_fp
    @path = uri_or_fp.path
  end

  start_offset ||= 0
  super uri_or_fp, start_offset, usual, archived, id
end
suggest_labels_for(path) click to toggle source
# File lib/sup/mbox/loader.rb, line 39
def self.suggest_labels_for path
  ## heuristic: use the filename as a label, unless the file
  ## has a path that probably represents an inbox.
  if File.dirname(path) =~ %r\b(var|usr|spool)\b/
    []
  else
    [File.basename(path).downcase.intern]
  end
end

Public Instance Methods

check() click to toggle source
# File lib/sup/mbox/loader.rb, line 49
def check
  if (cur_offset ||= start_offset) > end_offset
    raise OutOfSyncSourceError, "mbox file is smaller than last recorded message offset. Messages have probably been deleted by another client."
  end
end
correct_offset!() click to toggle source

scan forward until we're at the valid start of a message

# File lib/sup/mbox/loader.rb, line 88
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
each_raw_message_line(offset) { |gets| ... } click to toggle source

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.

i hoped never to have to move shit around on disk but sup-sync-back has to do it.

# File lib/sup/mbox/loader.rb, line 131
def each_raw_message_line offset
  @mutex.synchronize do
    @f.seek offset
    yield @f.gets
    until @f.eof? || MBox::is_break_line?(l = @f.gets)
      yield l
    end
  end
end
end_offset() click to toggle source
# File lib/sup/mbox/loader.rb, line 56
def end_offset; File.size @f; end
file_path() click to toggle source
# File lib/sup/mbox/loader.rb, line 36
def file_path; @path end
is_source_for?(uri;) click to toggle source
# File lib/sup/mbox/loader.rb, line 37
def is_source_for? uri; super || (self.uri.is_a?(String) && (URI(Source.expand_filesystem_uri(uri)) == URI(Source.expand_filesystem_uri(self.uri)))) end
load_header(offset) click to toggle source
# File lib/sup/mbox/loader.rb, line 58
def load_header offset
  header = nil
  @mutex.synchronize do
    @f.seek offset
    l = @f.gets
    unless MBox::is_break_line? l
      raise OutOfSyncSourceError, "mismatch in mbox file offset #{offset.inspect}: #{l.inspect}." 
    end
    header = parse_raw_email_header @f
  end
  header
end
load_message(offset) click to toggle source
# File lib/sup/mbox/loader.rb, line 71
def load_message offset
  @mutex.synchronize do
    @f.seek offset
    begin
      ## 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
next() click to toggle source
# File lib/sup/mbox/loader.rb, line 141
def next
  returned_offset = nil
  next_offset = cur_offset

  begin
    @mutex.synchronize do
      @f.seek cur_offset

      ## cur_offset could be at one of two places here:

      ## 1. before a \n and a mbox separator, if it was previously at
      ##    EOF and a new message was added; or,
      ## 2. at the beginning of an mbox separator (in all other
      ##    cases).

      l = @f.gets or return nil
      if l =~ %r^\s*$/ # case 1
        returned_offset = @f.tell
        @f.gets # now we're at a BREAK_RE, so skip past it
      else # case 2
        returned_offset = cur_offset
        ## we've already skipped past the BREAK_RE, so just go
      end

      while(line = @f.gets)
        break if MBox::is_break_line? line
        next_offset = @f.tell
      end
    end
  rescue SystemCallError, IOError => e
    raise FatalSourceError, "Error reading #{@f.path}: #{e.message}"
  end

  self.cur_offset = next_offset
  [returned_offset, (labels + [:unread])]
end
raw_header(offset) click to toggle source
# File lib/sup/mbox/loader.rb, line 99
def raw_header offset
  ret = ""
  @mutex.synchronize do
    @f.seek offset
    until @f.eof? || (l = @f.gets) =~ %r^\r*$/
      ret << l
    end
  end
  ret
end
raw_message(offset) click to toggle source
# File lib/sup/mbox/loader.rb, line 110
def raw_message offset
  ret = ""
  each_raw_message_line(offset) { |l| ret << l }
  ret
end
start_offset() click to toggle source
# File lib/sup/mbox/loader.rb, line 55
def start_offset; 0; end
store_message(date, from_email) { |f| ... } click to toggle source
# File lib/sup/mbox/loader.rb, line 116
def store_message date, from_email, &block
  need_blank = File.exists?(@filename) && !File.zero?(@filename)
  File.open(@filename, "ab") do |f|
    f.puts if need_blank
    f.puts "From #{from_email} #{date.rfc2822}"
    yield f
  end
end