]> git.cworth.org Git - sup/blob - lib/sup/draft.rb
Merge branch 'master' into next
[sup] / lib / sup / draft.rb
1 module Redwood
2
3 class DraftManager
4   include Singleton
5
6   attr_accessor :source
7   def initialize dir
8     @dir = dir
9     @source = nil
10     self.class.i_am_the_instance self
11   end
12
13   def self.source_name; "sup://drafts"; end
14   def self.source_id; 9999; end
15   def new_source; @source = Recoverable.new DraftLoader.new; end
16
17   def write_draft
18     offset = @source.gen_offset
19     fn = @source.fn_for_offset offset
20     File.open(fn, "w") { |f| yield f }
21
22     my_message = nil
23     @source.each do |thisoffset, theselabels|
24       m = Message.new :source => @source, :source_info => thisoffset, :labels => theselabels
25       Index.sync_message m
26       UpdateManager.relay self, :added, m
27       my_message = m if thisoffset == offset
28     end
29
30     my_message
31   end
32
33   def discard m
34     docid, entry = Index.load_entry_for_id m.id
35     unless entry
36       Redwood::log "can't find entry for draft: #{m.id.inspect}. You probably already discarded it."
37       return
38     end
39     raise ArgumentError, "not a draft: source id #{entry[:source_id].inspect}, should be #{DraftManager.source_id.inspect} for #{m.id.inspect} / docno #{docid}" unless entry[:source_id].to_i == DraftManager.source_id
40     Index.drop_entry docid
41     File.delete @source.fn_for_offset(entry[:source_info])
42     UpdateManager.relay self, :single_message_deleted, m
43   end
44 end
45
46 class DraftLoader < Source
47   attr_accessor :dir
48   yaml_properties :cur_offset
49
50   def initialize cur_offset=0
51     dir = Redwood::DRAFT_DIR
52     Dir.mkdir dir unless File.exists? dir
53     super DraftManager.source_name, cur_offset, true, false
54     @dir = dir
55   end
56
57   def id; DraftManager.source_id; end
58   def to_s; DraftManager.source_name; end
59   def uri; DraftManager.source_name; end
60
61   def each
62     ids = get_ids
63     ids.each do |id|
64       if id >= cur_offset
65         self.cur_offset = id + 1
66         yield [id, [:draft, :inbox]]
67       end
68     end
69   end
70
71   def gen_offset
72     i = cur_offset
73     while File.exists? fn_for_offset(i)
74       i += 1
75     end
76     i
77   end
78
79   def fn_for_offset o; File.join(@dir, o.to_s); end
80
81   def load_header offset
82     File.open(fn_for_offset(offset)) { |f| parse_raw_email_header f }
83   end
84   
85   def load_message offset
86     File.open fn_for_offset(offset) do |f|
87       RMail::Mailbox::MBoxReader.new(f).each_message do |input|
88         return RMail::Parser.read(input)
89       end
90     end
91   end
92
93   def raw_header offset
94     ret = ""
95     File.open fn_for_offset(offset) do |f|
96       until f.eof? || (l = f.gets) =~ /^$/
97         ret += l
98       end
99     end
100     ret
101   end
102
103   def each_raw_message_line offset
104     File.open(fn_for_offset(offset)) do |f|
105       yield f.gets until f.eof?
106     end
107   end
108
109   def raw_message offset
110     IO.read(fn_for_offset(offset))
111   end
112
113   def start_offset; 0; end
114   def end_offset
115     ids = get_ids
116     ids.empty? ? 0 : (ids.last + 1)
117   end
118
119 private
120
121   def get_ids
122     Dir.entries(@dir).select { |x| x =~ /^\d+$/ }.map { |x| x.to_i }.sort
123   end
124 end
125
126 end