]> git.cworth.org Git - sup/blob - lib/sup/mbox/loader.rb
moved evertying to devel
[sup] / lib / sup / mbox / loader.rb
1 require 'thread'
2 require 'rmail'
3
4 module Redwood
5 module MBox
6
7 class Error < StandardError; end
8
9 class Loader
10   attr_reader :filename
11   bool_reader :usual, :archived, :read, :dirty
12   attr_accessor :id, :labels
13
14   ## end_offset is the last offsets within the file which we've read.
15   ## everything after that is considered new messages that haven't
16   ## been indexed.
17   def initialize filename, end_offset=0, usual=true, archived=false, id=nil
18     @filename = filename.gsub(%r(^mbox://), "")
19     @end_offset = end_offset
20     @dirty = false
21     @usual = usual
22     @archived = archived
23     @id = id
24     @mutex = Mutex.new
25     @f = File.open @filename
26     @labels = ([
27       :unread,
28       archived ? nil : :inbox,
29     ] +
30       if File.dirname(filename) =~ /\b(var|usr|spool)\b/
31         []
32       else
33         [File.basename(filename).intern] 
34       end).compact
35   end
36
37   def reset!; @end_offset = 0; @dirty = true; end
38   def == o; o.is_a?(Loader) && o.filename == filename; end
39   def to_s; "mbox://#{@filename}"; end
40
41   def is_source_for? s
42     @filename == s || self.to_s == s
43   end
44
45   def load_header offset=nil
46     header = nil
47     @mutex.synchronize do
48       @f.seek offset if offset
49       header = MBox::read_header @f
50     end
51     header
52   end
53
54   def load_message offset
55     ret = nil
56     @mutex.synchronize do
57       @f.seek offset
58       RMail::Mailbox::MBoxReader.new(@f).each_message do |input|
59         return RMail::Parser.read(input)
60       end
61     end
62   end
63
64   ## load the full header text
65   def load_header_text offset
66     ret = ""
67     @mutex.synchronize do
68       @f.seek offset
69       until @f.eof? || (l = @f.gets) =~ /^$/
70         ret += l
71       end
72     end
73     ret
74   end
75
76   def next
77     return nil if done?
78     @dirty = true
79     next_end_offset = @end_offset
80
81     @mutex.synchronize do
82       @f.seek @end_offset
83
84       @f.gets # skip the From separator
85       next_end_offset = @f.tell
86       while(line = @f.gets)
87         break if line =~ BREAK_RE
88         next_end_offset = @f.tell + 1
89       end
90     end
91
92     start_offset = @end_offset
93     @end_offset = next_end_offset
94
95     start_offset
96   end
97
98   def each
99     until @end_offset >= File.size(@f)
100       n = self.next
101       yield(n, labels) if n
102     end
103   end
104
105   def each_header
106     each { |offset, labels| yield offset, labels, load_header(offset) }
107   end
108
109   def done?; @end_offset >= File.size(@f); end 
110   def total; File.size @f; end
111 end
112
113 Redwood::register_yaml(Loader, %w(filename end_offset usual archived id))
114
115 end
116 end