]> git.cworth.org Git - sup/blob - lib/sup/imap.rb
whoopsie! new message should be new. 0.0.2a
[sup] / lib / sup / imap.rb
1 require 'uri'
2 require 'net/imap'
3 require 'stringio'
4
5 module Redwood
6
7 class IMAP < Source
8   attr_reader :labels
9   
10   def initialize uri, username, password, last_uid=nil, usual=true, archived=false, id=nil
11     raise ArgumentError, "username and password must be specified" unless username && password
12
13     super uri, last_uid, usual, archived, id
14
15     @parsed_uri = URI(uri)
16     @username = username
17     @password = password
18     @imap = nil
19     @labels = [:unread]
20     @labels << mailbox.intern unless mailbox =~ /inbox/i || mailbox.empty?
21     @labels << :inbox unless archived?
22
23     connect
24   end
25
26   def connect
27     return false if broken?
28     return true if @imap
29     Redwood::log "connecting to #{@parsed_uri.host} port #{ssl? ? 993 : 143}, ssl=#{ssl?} ..."
30
31     ## ok, this is FUCKING ANNOYING.
32     ##
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
40     ## problem.
41     ##
42     ## FUCK!!!!!!!!!
43     ::Thread.new do
44       begin
45         #raise Net::IMAP::ByeResponseError, "simulated imap failure"
46         @imap = Net::IMAP.new @parsed_uri.host, ssl? ? 993 : 143, ssl?
47         @imap.authenticate 'LOGIN', @username, @password
48         @imap.examine mailbox
49         Redwood::log "successfully connected to #{@parsed_uri}, mailbox #{mailbox}"
50       rescue Exception => e
51         self.broken_msg = e.message.chomp # fucking chomp! fuck!!!
52         @imap = nil
53         Redwood::log "error connecting to IMAP server: #{self.broken_msg}"
54       end
55     end.join
56
57     !!@imap
58   end
59   private :connect
60
61   def mailbox; @parsed_uri.path[1..-1] end ##XXXX TODO handle nil
62   def ssl?; @parsed_uri.scheme == 'imaps' end
63
64   def load_header uid=nil
65     MBox::read_header StringIO.new(raw_header(uid))
66   end
67
68   def load_message uid
69     RMail::Parser.read raw_full_message(uid)
70   end
71
72   ## load the full header text
73   def raw_header uid
74     connect or return broken_msg
75     begin
76       connect or return broken_msg
77     rescue Exception => e
78       raise "wtf: #{e.inspect}"
79     end
80     @imap.uid_fetch(uid, 'RFC822.HEADER')[0].attr['RFC822.HEADER'].gsub(/\r\n/, "\n")
81   end
82
83   def raw_full_message uid
84     connect or return broken_msg
85     @imap.uid_fetch(uid, 'RFC822')[0].attr['RFC822'].gsub(/\r\n/, "\n")
86   end
87   
88   def each
89     connect or return broken_msg
90     uids = @imap.uid_search ['UID', "#{cur_offset}:#{end_offset}"]
91     uids.each do |uid|
92       @last_uid = uid
93       @dirty = true
94       yield uid, labels
95     end
96   end
97
98   def start_offset; 1; end
99   def end_offset
100     connect or return start_offset
101     @imap.uid_search(['ALL']).last
102   end
103 end
104
105 Redwood::register_yaml(IMAP, %w(uri username password offset usual archived id))
106
107 end