3 class SourceError < StandardError; end
4 class OutOfSyncSourceError < SourceError; end
5 class FatalSourceError < SourceError; end
8 ## Implementing a new source should be easy, because Sup only needs
10 ## 1. See how many messages it contains
11 ## 2. Get an arbitrary 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, it's nice to be able
16 ## to delete them, but that is optional.)
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): should return a message and an
39 ## ... where "offset" really means unique id. (You can tell I
40 ## started with mbox.)
42 ## All exceptions relating to accessing the source must be caught
43 ## and rethrown as FatalSourceErrors or OutOfSyncSourceErrors.
44 ## OutOfSyncSourceErrors should be used for problems that a call to
45 ## sup-sync will fix (namely someone's been playing with the source
46 ## from another client); FatalSourceErrors can be used for anything
47 ## else (e.g. the imap server is down or the maildir is missing.)
49 ## Finally, be sure the source is thread-safe, since it WILL be
50 ## pummelled from multiple threads at once.
52 ## Examples for you to look at: mbox/loader.rb, imap.rb, and
57 ## dirty? means cur_offset has changed, so the source info needs to
58 ## be re-saved to sources.yaml.
59 bool_reader :usual, :archived, :dirty
60 attr_reader :uri, :cur_offset
63 def initialize uri, initial_offset=nil, usual=true, archived=false, id=nil
64 raise ArgumentError, "id must be an integer: #{id.inspect}" unless id.is_a? Fixnum if id
67 @cur_offset = initial_offset
74 def to_s; @uri.to_s; end
75 def seek_to! o; self.cur_offset = o; end
76 def reset!; seek_to! start_offset; end
77 def == o; o.uri == uri; end
78 def done?; (self.cur_offset ||= start_offset) >= end_offset; end
79 def is_source_for? uri; URI(self.uri) == URI(uri); end
81 ## check should throw a FatalSourceError or an OutOfSyncSourcError
82 ## if it can detect a problem. it is called when the sup starts up
83 ## to proactively notify the user of any source problems.
87 self.cur_offset ||= start_offset
90 raise "no message" unless n