10 def initialize uri, username, password, uid_validity=nil, last_uid=nil, usual=true, archived=false, id=nil
11 raise ArgumentError, "username and password must be specified" unless username && password
12 raise ArgumentError, "not an imap uri" unless uri =~ %r!imaps?://!
14 super uri, last_uid, usual, archived, id
16 @parsed_uri = URI(uri)
19 @uid_validity = uid_validity
22 @labels << :inbox unless archived?
23 @labels << mailbox.intern unless mailbox =~ /inbox/i || mailbox.nil?
27 return false if broken?
29 Redwood::log "connecting to #{@parsed_uri.host} port #{ssl? ? 993 : 143}, ssl=#{ssl?} ..."
31 ## ok, this is FUCKING ANNOYING.
33 ## what imap.rb likes to do is, if an exception occurs, catch it
34 ## and re-raise it on the calling thread. seems reasonable. but
35 ## what that REALLY means is that the only way to reasonably
36 ## initialize imap is in its own thread, because otherwise, you
37 ## will never be able to catch the exception it raises on the
38 ## calling thread, and the backtrace will not make any sense at
39 ## all, and you will waste HOURS of your life on this fucking
44 BufferManager.say "Connecting to IMAP server #{host}..." do
47 #raise Net::IMAP::ByeResponseError, "simulated imap failure"
48 @imap = Net::IMAP.new host, ssl? ? 993 : 143, ssl?
49 @imap.authenticate 'LOGIN', @username, @password
51 Redwood::log "successfully connected to #{@parsed_uri}, mailbox #{mailbox}"
52 @uid_validity ||= @imap.responses["UIDVALIDITY"][-1]
53 raise SourceError, "Your shitty IMAP server has kindly invalidated all 'unique' ids for the folder '#{mailbox}'. You will have to rescan this folder manually." if @imap.responses["UIDVALIDITY"][-1] != @uid_validity
55 self.broken_msg = e.message.chomp # fucking chomp! fuck!!!
57 Redwood::log "error connecting to IMAP server: #{self.broken_msg}"
66 def host; @parsed_uri.host; end
67 def mailbox; @parsed_uri.path[1..-1] end ##XXXX TODO handle nil
68 def ssl?; @parsed_uri.scheme == 'imaps' end
70 def load_header uid=nil
71 MBox::read_header StringIO.new(raw_header(uid))
75 RMail::Parser.read raw_full_message(uid)
78 ## load the full header text
80 connect or raise SourceError, broken_msg
81 get_imap_field(uid, 'RFC822.HEADER').gsub(/\r\n/, "\n")
84 def raw_full_message uid
85 connect or raise SourceError, broken_msg
86 get_imap_field(uid, 'RFC822').gsub(/\r\n/, "\n")
89 def get_imap_field uid, field
90 f = @imap.uid_fetch uid, field
91 raise SourceError, "null IMAP field '#{field}' for message with uid #{uid}" if f.nil?
94 private :get_imap_field
97 connect or raise SourceError, broken_msg
98 uids = @imap.uid_search ['UID', "#{cur_offset}:#{end_offset}"]
102 self.cur_offset = uid
107 def start_offset; 1; end
109 connect or return start_offset
110 @imap.uid_search(['ALL']).last
114 Redwood::register_yaml(IMAP, %w(uri username password uid_validity cur_offset usual archived id))