Class: Redwood::Maildir
Overview
Maildir doesn’t provide an ordered unique id, which is what Sup requires to be really useful. So we must maintain, in memory, a mapping between Sup “ids” (timestamps, essentially) and the pathnames on disk.
Constant Summary
collapse
- SCAN_INTERVAL =
30
Instance Attribute Summary
Attributes inherited from Source
#cur_offset, #id
Class Method Summary
collapse
Instance Method Summary
collapse
Methods inherited from Source
#==, #done?, #reset!, #seek_to!, #to_s, #usual
Constructor Details
#initialize(uri, last_date = nil, usual = true, archived = false, id = nil, labels = []) ⇒ Maildir
Returns a new instance of Maildir.
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
# File 'lib/sup/maildir.rb', line 16
def initialize uri, last_date=nil, usual=true, archived=false, id=nil, labels=[]
super uri, last_date, usual, archived, id
uri = URI(Source.expand_filesystem_uri(uri))
raise ArgumentError, "not a maildir URI" unless uri.scheme == "maildir"
raise ArgumentError, "maildir URI cannot have a host: #{uri.host}" if uri.host
raise ArgumentError, "mbox URI must have a path component" unless uri.path
@dir = uri.path
@labels = (labels || []).freeze
@ids = []
@ids_to_fns = {}
@last_scan = nil
@mutex = Mutex.new
end
|
Class Method Details
.suggest_labels_for(path) ⇒ Object
33
|
# File 'lib/sup/maildir.rb', line 33
def self.suggest_labels_for path; [] end
|
Instance Method Details
36
37
38
39
40
41
|
# File 'lib/sup/maildir.rb', line 36
def check
scan_mailbox
return unless start_offset
start = @ids.index(cur_offset || start_offset) or raise OutOfSyncSourceError, "Unknown message id #{cur_offset || start_offset}." end
|
#draft?(msg) ⇒ Boolean
129
|
# File 'lib/sup/maildir.rb', line 129
def draft? msg; maildir_data(msg)[2].include? "D"; end
|
104
105
106
107
108
109
110
111
112
113
114
115
|
# File 'lib/sup/maildir.rb', line 104
def each
scan_mailbox
return unless start_offset
start = @ids.index(cur_offset || start_offset) or raise OutOfSyncSourceError, "Unknown message id #{cur_offset || start_offset}."
start.upto(@ids.length - 1) do |i|
id = @ids[i]
self.cur_offset = id
yield id, @labels + (seen?(id) ? [] : [:unread]) + (trashed?(id) ? [:deleted] : []) + (flagged?(id) ? [:starred] : [])
end
end
|
#each_raw_message_line(id) ⇒ Object
43
44
45
46
47
48
49
50
|
# File 'lib/sup/maildir.rb', line 43
def each_raw_message_line id
scan_mailbox
with_file_for(id) do |f|
until f.eof?
yield f.gets
end
end
end
|
#end_offset ⇒ Object
122
123
124
125
|
# File 'lib/sup/maildir.rb', line 122
def end_offset
scan_mailbox
@ids.last
end
|
#file_path ⇒ Object
32
|
# File 'lib/sup/maildir.rb', line 32
def file_path; @dir end
|
#flagged?(msg) ⇒ Boolean
130
|
# File 'lib/sup/maildir.rb', line 130
def flagged? msg; maildir_data(msg)[2].include? "F"; end
|
#is_source_for?(uri) ⇒ Boolean
34
|
# File 'lib/sup/maildir.rb', line 34
def is_source_for? uri; super || (URI(Source.expand_filesystem_uri(uri)) == URI(self.uri)); end
|
52
53
54
55
|
# File 'lib/sup/maildir.rb', line 52
def id
scan_mailbox
with_file_for(id) { |f| MBox:: f }
end
|
#load_message(id) ⇒ Object
57
58
59
60
|
# File 'lib/sup/maildir.rb', line 57
def load_message id
scan_mailbox
with_file_for(id) { |f| RMail::Parser.read f }
end
|
#mark_draft(msg) ⇒ Object
136
|
# File 'lib/sup/maildir.rb', line 136
def mark_draft msg; maildir_mark_file msg, "D" unless draft? msg; end
|
#mark_flagged(msg) ⇒ Object
137
|
# File 'lib/sup/maildir.rb', line 137
def mark_flagged msg; maildir_mark_file msg, "F" unless flagged? msg; end
|
#mark_passed(msg) ⇒ Object
138
|
# File 'lib/sup/maildir.rb', line 138
def mark_passed msg; maildir_mark_file msg, "P" unless passed? msg; end
|
#mark_replied(msg) ⇒ Object
139
|
# File 'lib/sup/maildir.rb', line 139
def mark_replied msg; maildir_mark_file msg, "R" unless replied? msg; end
|
#mark_seen(msg) ⇒ Object
140
|
# File 'lib/sup/maildir.rb', line 140
def mark_seen msg; maildir_mark_file msg, "S" unless seen? msg; end
|
#mark_trashed(msg) ⇒ Object
141
|
# File 'lib/sup/maildir.rb', line 141
def mark_trashed msg; maildir_mark_file msg, "T" unless trashed? msg; end
|
#passed?(msg) ⇒ Boolean
131
|
# File 'lib/sup/maildir.rb', line 131
def passed? msg; maildir_data(msg)[2].include? "P"; end
|
127
|
# File 'lib/sup/maildir.rb', line 127
def pct_done; 100.0 * (@ids.index(cur_offset) || 0).to_f / (@ids.length - 1).to_f; end
|
62
63
64
65
66
67
68
69
70
71
|
# File 'lib/sup/maildir.rb', line 62
def id
scan_mailbox
ret = ""
with_file_for(id) do |f|
until f.eof? || (l = f.gets) =~ /^$/
ret += l
end
end
ret
end
|
#raw_message(id) ⇒ Object
73
74
75
76
|
# File 'lib/sup/maildir.rb', line 73
def raw_message id
scan_mailbox
with_file_for(id) { |f| f.readlines.join }
end
|
#replied?(msg) ⇒ Boolean
132
|
# File 'lib/sup/maildir.rb', line 132
def replied? msg; maildir_data(msg)[2].include? "R"; end
|
#scan_mailbox ⇒ Object
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
|
# File 'lib/sup/maildir.rb', line 78
def scan_mailbox
return if @last_scan && (Time.now - @last_scan) < SCAN_INTERVAL
cdir = File.join(@dir, 'cur')
ndir = File.join(@dir, 'new')
raise FatalSourceError, "#{cdir} not a directory" unless File.directory? cdir
raise FatalSourceError, "#{ndir} not a directory" unless File.directory? ndir
begin
@ids, @ids_to_fns = @mutex.synchronize do
ids, ids_to_fns = [], {}
(Dir[File.join(cdir, "*")] + Dir[File.join(ndir, "*")]).map do |fn|
id = make_id fn
ids << id
ids_to_fns[id] = fn
end
[ids.sort, ids_to_fns]
end
rescue SystemCallError, IOError => e
raise FatalSourceError, "Problem scanning Maildir directories: #{e.message}."
end
@last_scan = Time.now
end
|
#seen?(msg) ⇒ Boolean
133
|
# File 'lib/sup/maildir.rb', line 133
def seen? msg; maildir_data(msg)[2].include? "S"; end
|
#start_offset ⇒ Object
117
118
119
120
|
# File 'lib/sup/maildir.rb', line 117
def start_offset
scan_mailbox
@ids.first
end
|
#trashed?(msg) ⇒ Boolean
134
|
# File 'lib/sup/maildir.rb', line 134
def trashed? msg; maildir_data(msg)[2].include? "T"; end
|
remind me never to use inheritance again.
15
|
# File 'lib/sup/maildir.rb', line 15
yaml_properties :uri, :cur_offset, :usual, :archived, :id, :labels
|