Class: Redwood::MBox::Loader

Inherits:
Source show all
Defined in:
lib/sup/mbox/loader.rb

Direct Known Subclasses

SentLoader

Instance Attribute Summary (collapse)

Attributes inherited from Source

#cur_offset, #id, #uri

Class Method Summary (collapse)

Instance Method Summary (collapse)

Methods inherited from Source

#==, #done?, #each, #reset!, #seek_to!, #to_s

Constructor Details

- (Loader) initialize(uri_or_fp, start_offset = nil, usual = true, archived = false, id = nil, labels = [])

uri_or_fp is horrific. need to refactor.



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/sup/mbox/loader.rb', line 12

def initialize uri_or_fp, start_offset=nil, usual=true, archived=false, id=nil, labels=[]
  @mutex = Mutex.new
  @labels = ((labels || []) - LabelManager::RESERVED_LABELS).uniq.freeze

  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
    @path = uri.path
  else
    @f = uri_or_fp
    @path = uri_or_fp.path
  end

  super uri_or_fp, start_offset, usual, archived, id
end

Instance Attribute Details

- (Object) labels

Returns the value of attribute labels



9
10
11
# File 'lib/sup/mbox/loader.rb', line 9

def labels
  @labels
end

Class Method Details

+ (Object) suggest_labels_for(path)



35
36
37
38
39
40
41
42
43
# File 'lib/sup/mbox/loader.rb', line 35

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) =~ /\b(var|usr|spool)\b/
    []
  else
    [File.basename(path).downcase.intern]
  end
end

Instance Method Details

- (Object) check



45
46
47
48
49
# File 'lib/sup/mbox/loader.rb', line 45

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

- (Object) each_raw_message_line(offset)

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.



107
108
109
110
111
112
113
114
115
# File 'lib/sup/mbox/loader.rb', line 107

def each_raw_message_line offset
  @mutex.synchronize do
    @f.seek offset
    yield @f.gets
    until @f.eof? || (l = @f.gets) =~ BREAK_RE
      yield l
    end
  end
end

- (Object) end_offset



52
# File 'lib/sup/mbox/loader.rb', line 52

def end_offset; File.size @f; end

- (Object) file_path



32
# File 'lib/sup/mbox/loader.rb', line 32

def file_path; @path end

- (Boolean) is_source_for?(uri)



33
# File 'lib/sup/mbox/loader.rb', line 33

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

- (Object) load_header(offset)



54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/sup/mbox/loader.rb', line 54

def load_header offset
  header = nil
  @mutex.synchronize do
    @f.seek offset
    l = @f.gets
    unless l =~ BREAK_RE
      raise OutOfSyncSourceError, "mismatch in mbox file offset #{offset.inspect}: #{l.inspect}." 
    end
    header = MBox::read_header @f
  end
  header
end

- (Object) load_message(offset)



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/sup/mbox/loader.rb', line 67

def load_message offset
  @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
    rescue RMail::Parser::Error => e
      raise FatalSourceError, "error parsing mbox file: #{e.message}"
    end
  end
end

- (Object) next



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# File 'lib/sup/mbox/loader.rb', line 117

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 raise "next while at EOF"
      if l =~ /^\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 line =~ BREAK_RE
        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, (self.labels + [:unread]).uniq]
end

- (Object) raw_header(offset)



84
85
86
87
88
89
90
91
92
93
# File 'lib/sup/mbox/loader.rb', line 84

def raw_header offset
  ret = ""
  @mutex.synchronize do
    @f.seek offset
    until @f.eof? || (l = @f.gets) =~ /^\r*$/
      ret += l
    end
  end
  ret
end

- (Object) raw_message(offset)



95
96
97
98
99
# File 'lib/sup/mbox/loader.rb', line 95

def raw_message offset
  ret = ""
  each_raw_message_line(offset) { |l| ret += l }
  ret
end

- (Object) start_offset



51
# File 'lib/sup/mbox/loader.rb', line 51

def start_offset; 0; end