Class: Redwood::MBox
Defined Under Namespace
Classes: Loader
Constant Summary
collapse
- BREAK_RE =
/^From \S+ (.+)$/
Instance Attribute Summary collapse
Attributes inherited from Source
#id, #uri, #usual
Class Method Summary
collapse
Instance Method Summary
collapse
#after_unmarshal!, #before_marshal
Methods inherited from Source
#==, #labels?, parse_raw_email_header, #read?, #supported_labels?, #synchronize, #to_s, #try_lock, #unlock, #valid?
Constructor Details
#initialize(uri_or_fp, usual = true, archived = false, id = nil, labels = nil) ⇒ MBox
uri_or_fp is horrific. need to refactor.
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
# File 'lib/sup/mbox.rb', line 15
def initialize uri_or_fp, usual=true, archived=false, id=nil, labels=nil
@mutex = Mutex.new
@labels = Set.new((labels || []) - LabelManager::RESERVED_LABELS)
case uri_or_fp
when String
@expanded_uri = Source.expand_filesystem_uri(uri_or_fp)
parts = /^([a-zA-Z0-9]*:(\/\/)?)(.*)/.match @expanded_uri
if parts
prefix = parts[1]
@path = parts[3]
uri = URI(prefix + Source.encode_path_for_uri(@path))
else
uri = URI(Source.encode_path_for_uri @expanded_uri)
@path = uri.path
end
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 = nil
else
@f = uri_or_fp
@path = uri_or_fp.path
@expanded_uri = "mbox://#{Source.encode_path_for_uri @path}"
end
super uri_or_fp, usual, archived, id
end
|
Instance Attribute Details
Returns the value of attribute labels.
12
13
14
|
# File 'lib/sup/mbox.rb', line 12
def labels
@labels
end
|
Class Method Details
.is_break_line?(l) ⇒ Boolean
178
179
180
181
182
183
184
185
186
187
188
189
|
# File 'lib/sup/mbox.rb', line 178
def self.is_break_line? l
l =~ BREAK_RE or return false
time = $1
begin
Time.parse time, Time.at(0)
true
rescue NoMethodError, ArgumentError
warn "found invalid date in potential mbox split line, not splitting: #{l.inspect}"
false
end
end
|
.suggest_labels_for(path) ⇒ Object
48
49
50
51
52
53
54
55
56
|
# File 'lib/sup/mbox.rb', line 48
def self.suggest_labels_for path
if File.dirname(path) =~ /\b(var|usr|spool)\b/
[]
else
[File.basename(path).downcase.intern]
end
end
|
Instance Method Details
#default_labels ⇒ Object
140
141
142
|
# File 'lib/sup/mbox.rb', line 140
def default_labels
[:inbox, :unread]
end
|
#each_raw_message_line(offset) ⇒ Object
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.
130
131
132
133
134
135
136
137
138
|
# File 'lib/sup/mbox.rb', line 130
def each_raw_message_line offset
@mutex.synchronize do
ensure_open
@f.seek offset
until @f.eof? || MBox::is_break_line?(l = @f.gets)
yield l
end
end
end
|
#file_path ⇒ Object
45
|
# File 'lib/sup/mbox.rb', line 45
def file_path; @path end
|
#first_new_message ⇒ Object
offset of first new message or nil
174
175
176
|
# File 'lib/sup/mbox.rb', line 174
def first_new_message
next_offset(last_indexed_message || 0)
end
|
63
64
65
66
67
68
69
|
# File 'lib/sup/mbox.rb', line 63
def go_idle
@mutex.synchronize do
return if @f.nil? or @path.nil?
@f.close
@f = nil
end
end
|
#is_source_for?(uri) ⇒ Boolean
46
|
# File 'lib/sup/mbox.rb', line 46
def is_source_for? uri; super || (uri == @expanded_uri) end
|
#last_indexed_message ⇒ Object
TODO optimize this by iterating over allterms list backwards or storing source_info negated
169
170
171
|
# File 'lib/sup/mbox.rb', line 169
def last_indexed_message
benchmark(:mbox_read_index) { Index.instance.enum_for(:each_source_info, self.id).map(&:to_i).max }
end
|
71
72
73
74
75
76
77
78
79
|
# File 'lib/sup/mbox.rb', line 71
def offset
= nil
@mutex.synchronize do
ensure_open
@f.seek offset
= @f
end
end
|
#load_message(offset) ⇒ Object
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
|
# File 'lib/sup/mbox.rb', line 81
def load_message offset
@mutex.synchronize do
ensure_open
@f.seek offset
begin
string = ""
until @f.eof? || MBox::is_break_line?(l = @f.gets)
string << l
end
RMail::Parser.read string
rescue RMail::Parser::Error => e
raise FatalSourceError, "error parsing mbox file: #{e.message}"
end
end
end
|
#next_offset(offset) ⇒ Object
157
158
159
160
161
162
163
164
165
|
# File 'lib/sup/mbox.rb', line 157
def next_offset offset
@mutex.synchronize do
ensure_open
@f.seek offset
nil while line = @f.gets and not MBox::is_break_line? line
offset = @f.tell
offset != File.size(@f) ? offset : nil
end
end
|
144
145
146
147
148
149
150
151
152
153
154
155
|
# File 'lib/sup/mbox.rb', line 144
def poll
first_offset = first_new_message
offset = first_offset
end_offset = File.size @f
while offset and offset < end_offset
yield :add,
:info => offset,
:labels => (labels + default_labels),
:progress => (offset - first_offset).to_f/end_offset
offset = next_offset offset
end
end
|
99
100
101
102
103
104
105
106
107
108
109
|
# File 'lib/sup/mbox.rb', line 99
def offset
ret = ""
@mutex.synchronize do
ensure_open
@f.seek offset
until @f.eof? || (l = @f.gets) =~ /^\r*$/
ret << l
end
end
ret
end
|
#raw_message(offset) ⇒ Object
111
112
113
114
115
|
# File 'lib/sup/mbox.rb', line 111
def raw_message offset
ret = ""
each_raw_message_line(offset) { |l| ret << l }
ret
end
|
#store_message(date, from_email, &block) ⇒ Object
117
118
119
120
121
122
123
124
|
# File 'lib/sup/mbox.rb', line 117
def store_message date, from_email, &block
need_blank = File.exist?(@path) && !File.zero?(@path)
File.open(@path, "ab") do |f|
f.puts if need_blank
f.puts "From #{from_email} #{date.asctime}"
yield f
end
end
|