3 class SourceError < StandardError; end
4 class OutOfSyncSourceError < SourceError; end
5 class FatalSourceError < SourceError; end
8 ## Implementing a new source is typically quite easy, because Sup
9 ## only needs to be able to:
10 ## 1. See how many messages it contains
11 ## 2. Get an arbirtrary message
12 ## 3. (optional) see whether the source has marked it read or not
14 ## In particular, Sup doesn't need to move messages, mark them as
15 ## read, delete them, or anything else. (Well, at some point it will
16 ## need to delete them, but that will be an optional capability.)
18 ## On the other hand, Sup assumes that you can assign each message a
19 ## unique integer id, such that newer messages have higher ids than
20 ## earlier ones, and that those ids stay constant across sessions
21 ## (in the absence of some other client going in and fucking
22 ## everything up). For example, for mboxes I use the file offset of
23 ## the start of the message. If a source does NOT have that
24 ## capability, e.g. IMAP, then you have to do a little more work to
27 ## To write a new source, subclass this class, and implement:
30 ## - end_offset (exclusive!)
31 ## - load_header offset
32 ## - load_message offset
33 ## - raw_header offset
34 ## - raw_full_message offset
36 ## - next (or each, if you prefer)
38 ## ... where "offset" really means unique id. (You can tell I
39 ## started with mbox.)
41 ## All exceptions relating to accessing the source must be caught
42 ## and rethrown as FatalSourceErrors or OutOfSyncSourceErrors.
43 ## OutOfSyncSourceErrors should be used for problems that a call to
44 ## sup-sync will fix (namely someone's been playing with the source
45 ## from another client); FatalSourceErrors can be used for anything
46 ## else (e.g. the imap server is down or the maildir is missing.)
48 ## Finally, be sure the source is thread-safe, since it WILL be
49 ## pummeled from multiple threads at once.
51 ## Examples for you to look at: mbox/loader.rb, imap.rb, and
56 ## dirty? means cur_offset has changed, so the source info needs to
57 ## be re-saved to sources.yaml.
58 bool_reader :usual, :archived, :dirty
59 attr_reader :uri, :cur_offset
62 def initialize uri, initial_offset=nil, usual=true, archived=false, id=nil
64 @cur_offset = initial_offset || start_offset
71 def to_s; @uri.to_s; end
72 def seek_to! o; self.cur_offset = o; end
73 def reset!; seek_to! start_offset; end
74 def == o; o.to_s == to_s; end
75 def done?; (self.cur_offset ||= start_offset) >= end_offset; end
76 def is_source_for? uri; URI(self.uri) == URI(uri); end
78 ## check should throw a FatalSourceError or an OutOfSyncSourcError
79 ## if it can detect a problem. it is called when the sup starts up
80 ## to proactively notify the user of any source problems.
84 self.cur_offset ||= start_offset
87 raise "no message" unless n
100 Redwood::register_yaml(Source, %w(uri cur_offset usual archived id))