Object
Manages a connection to an IMAP server and all the glorious fun that entails.
This class borrows heavily from Sup, the source code of which should be required reading if you're doing anything with IMAP in Ruby: sup.rubyforge.org
Larch::IMAP::Message represents a transferable IMAP message which can be passed between Larch::IMAP instances.
URI format validation regex.
Initializes a new Larch::IMAP instance that will connect to the specified IMAP URI.
In addition to the URI, the following options may be specified:
If true, mailboxes that don't already exist will be created if necessary.
If true, read-only operations will be performed as usual and all change operations will be simulated, but no changes will actually be made. Note that it's not actually possible to simulate mailbox creation, so :dry_run mode always behaves as if :create_mailbox is false.
Label to use for this connection in log output. If not specified, the default label is "[username@host]".
After a recoverable error occurs, retry the operation up to this many times. Default is 3.
Path to a trusted certificate bundle to use to verify server SSL certificates. You can download a bundle of certificate authority root certs at curl.haxx.se/ca/cacert.pem (it's up to you to verify that this bundle hasn't been tampered with, however; don't trust it blindly).
If true, server SSL certificates will be verified against the trusted certificate bundle specified in ssl_certs. By default, server SSL certificates are not verified.
# File lib/larch/imap.rb, line 52 def initialize(uri, options = {}) raise ArgumentError, "not an IMAP URI: #{uri}" unless uri.is_a?(URI) || uri =~ REGEX_URI raise ArgumentError, "options must be a Hash" unless options.is_a?(Hash) @uri = uri.is_a?(URI) ? uri : URI(uri) @options = { :log_label => "[#{username}@#{host}]", :max_retries => 3, :ssl_verify => false }.merge(options) raise ArgumentError, "must provide a username and password" unless @uri.user && @uri.password @conn = nil @mailboxes = {} @quirks = { :gmail => false, :yahoo => false } @db_account = Database::Account.find_or_create( :hostname => host, :username => username ) @db_account.touch # Create private convenience methods (debug, info, warn, etc.) to make # logging easier. Logger::LEVELS.each_key do |level| next if IMAP.private_method_defined?(level) IMAP.class_eval do define_method(level) do |msg| Larch.log.log(level, "#{@options[:log_label]} #{msg}") end private level end end end
Connects to the IMAP server and logs in if a connection hasn't already been established.
# File lib/larch/imap.rb, line 97 def connect return if @conn safely {} # connect, but do nothing else end
Gets the server's mailbox hierarchy delimiter.
# File lib/larch/imap.rb, line 103 def delim @delim ||= safely { @conn.list('', '')[0].delim || '.'} end
Closes the IMAP connection if one is currently open.
# File lib/larch/imap.rb, line 108 def disconnect return unless @conn begin @conn.disconnect rescue Errno::ENOTCONN => e debug "#{e.class.name}: #{e.message}" end reset info "disconnected" end
Iterates through all mailboxes in the account, yielding each one as a Larch::IMAP::Mailbox instance to the given block.
# File lib/larch/imap.rb, line 124 def each_mailbox update_mailboxes @mailboxes.each_value {|mailbox| yield mailbox } end
Gets the IMAP hostname.
# File lib/larch/imap.rb, line 130 def host @uri.host end
Gets a Larch::IMAP::Mailbox instance representing the specified mailbox. If the mailbox doesn't exist and the :create_mailbox option is false, or if :create_mailbox is true and mailbox creation fails, a Larch::IMAP::MailboxNotFoundError will be raised.
# File lib/larch/imap.rb, line 138 def mailbox(name, delim = '/') retries = 0 name.gsub!(/^(inbox\/?)/){ $1.upcase } name.gsub!(delim, self.delim) # Gmail doesn't allow folders with leading or trailing whitespace. name.strip! if @quirks[:gmail] begin @mailboxes.fetch(name) do update_mailboxes return @mailboxes[name] if @mailboxes.has_key?(name) raise MailboxNotFoundError, "mailbox not found: #{name}" end rescue MailboxNotFoundError => e raise unless @options[:create_mailbox] && retries == 0 info "creating mailbox: #{name}" safely { @conn.create(Net::IMAP.encode_utf7(name)) } unless @options[:dry_run] retries += 1 retry end end
Sends an IMAP NOOP command.
# File lib/larch/imap.rb, line 166 def noop safely { @conn.noop } end
Gets the IMAP password.
# File lib/larch/imap.rb, line 171 def password CGI.unescape(@uri.password) end
Gets the IMAP port number.
# File lib/larch/imap.rb, line 176 def port @uri.port || (ssl? ? 993 : 143) end
Connect if necessary, execute the given block, retry if a recoverable error occurs, die if an unrecoverable error occurs.
# File lib/larch/imap.rb, line 182 def safely safe_connect retries = 0 begin yield rescue Errno::ECONNABORTED, Errno::ECONNRESET, Errno::ENOTCONN, Errno::EPIPE, Errno::ETIMEDOUT, IOError, Net::IMAP::ByeResponseError, OpenSSL::SSL::SSLError => e raise unless (retries += 1) <= @options[:max_retries] warning "#{e.class.name}: #{e.message} (reconnecting)" reset sleep 1 * retries safe_connect retry rescue Net::IMAP::BadResponseError, Net::IMAP::NoResponseError, Net::IMAP::ResponseParseError => e raise unless (retries += 1) <= @options[:max_retries] warning "#{e.class.name}: #{e.message} (will retry)" sleep 1 * retries retry end rescue Larch::Error => e raise rescue Net::IMAP::Error => e raise Error, "#{e.class.name}: #{e.message} (giving up)" rescue => e raise FatalError, "#{e.class.name}: #{e.message} (cannot recover)" end
Gets the SSL status.
# File lib/larch/imap.rb, line 231 def ssl? @uri.scheme == 'imaps' end
Gets the IMAP URI.
# File lib/larch/imap.rb, line 236 def uri @uri.to_s end
Gets the IMAP mailbox specified in the URI, or nil if none.
# File lib/larch/imap.rb, line 241 def uri_mailbox mb = @uri.path[1..-1] mb.nil? || mb.empty? ? nil : CGI.unescape(mb) end
Gets the IMAP username.
# File lib/larch/imap.rb, line 247 def username CGI.unescape(@uri.user) end
Generated with the Darkfish Rdoc Generator 2.