module EventMachine::IMAP::Connection

Public Class Methods

connect(host, port, ssl=false) click to toggle source

Create a new connection to an IMAP server.

@param host, The host name (warning DNS lookups are synchronous) @param port, The port to connect to. @param ssl=false, Whether or not to use TLS.

@return Connection, a deferrable that will succeed when the server

has replied with OK or PREAUTH, or fail if the
connection could not be established, or the
first response was BYE.
# File lib/em-imap/connection.rb, line 23
def self.connect(host, port, ssl=false)
  EventMachine.connect(host, port, self).tap do |conn|
    conn.start_tls if ssl
  end
end
debug!() click to toggle source
# File lib/em-imap/connection.rb, line 194
def self.debug!
  include IMAP::Connection::Debug
end

Public Instance Methods

add_response_handler(&block) click to toggle source

Create a new listener for responses from the IMAP server.

@param &block, a block to which all responses will be passed. @return Listener, an object with a .stop method that you can

use to unregister this block.

You may also want to listen on the Listener's errback
for when problems arise. The Listener's callbacks will
be called after you call its stop method.
# File lib/em-imap/connection.rb, line 98
def add_response_handler(&block)
  Listener.new(&block).tap do |listener|
    listener.stopback{ listener.succeed }
    add_to_listener_pool(listener)
  end
end
add_to_listener_pool(listener) click to toggle source
# File lib/em-imap/connection.rb, line 105
def add_to_listener_pool(listener)
  @listeners << listener.bothback{ @listeners.delete listener }
end
hello_listener() click to toggle source

Returns a Listener that is active during connection setup, and which is succeeded or failed as soon as we’ve received a greeting from the server.

# File lib/em-imap/connection.rb, line 57
def hello_listener
  @hello_listener ||= Listener.new.errback{ |e| fail e }.bothback{ hello_listener.stop }
end
listen_for_failure() click to toggle source

Attach life-long listeners on various conditions that we want to treat as connection errors. When such an error occurs, we want to fail all the currently pending commands so that the user of the library doesn’t have to subscribe to more than one stream of errors.

# File lib/em-imap/connection.rb, line 146
def listen_for_failure
  errback do |error|
    # NOTE: Take a shallow clone of the listeners here so that we get guaranteed
    # behaviour. We want to fail any listeners that may be added by the errbacks
    # of other listeners.
    @listeners.clone.each{ |listener| listener.fail error } while @listeners.size > 0
    close_connection unless @unbound
  end

  # If we receive a BYE response from the server, then we're not going
  # to hear any more, so we fail all our listeners.
  add_response_handler do |response|
    if response.is_a?(Net::IMAP::UntaggedResponse) && response.name == "BYE"
      fail Net::IMAP::ByeResponseError.new((RUBY_VERSION[0,3] == "1.8" ? response.raw_data : response))
    end
  end
end
listen_for_greeting() click to toggle source

This listens for the IMAP connection to have been set up. This should be shortly after the TCP connection is available, once we’ve received a greeting from the server.

# File lib/em-imap/connection.rb, line 39
def listen_for_greeting
  add_to_listener_pool(hello_listener)
  hello_listener.listen do |response|
    # TODO: Is this the right condition? I think it can be one of several
    # possible answers depending on how trusted the connection is, but probably
    # not *anything* except BYE.
    if response.is_a?(Net::IMAP::UntaggedResponse) && response.name != "BYE"
      hello_listener.succeed response
    else
      hello_listener.fail Net::IMAP::ResponseParseError.new((RUBY_VERSION[0,3] == "1.8" ? response.raw_data : response))
    end
  end.errback do |e|
    hello_listener.fail e
  end
end
listen_for_tagged_response(command) click to toggle source

Await the response that marks the completion of this command, and succeed or fail the command as appropriate.

# File lib/em-imap/connection.rb, line 120
def listen_for_tagged_response(command)
  command.listen do |response|
    if response.is_a?(Net::IMAP::TaggedResponse) && response.tag == command.tag
      case response.name
      when "NO"
        command.fail Net::IMAP::NoResponseError.new((RUBY_VERSION[0,3] == "1.8" ? response.data.text : response))
      when "BAD"
        command.fail Net::IMAP::BadResponseError.new((RUBY_VERSION[0,3] == "1.8" ? response.data.text : response))
      else
        command.succeed response
      end
    end
  end
end
post_init() click to toggle source
# File lib/em-imap/connection.rb, line 29
def post_init
  @listeners = []
  super
  listen_for_failure
  listen_for_greeting
end
receive_response(response) click to toggle source

receive_response is a higher-level receive_data provided by EM::IMAP::ResponseParser. Each response is a Net::IMAP response object. (FIXME)

# File lib/em-imap/connection.rb, line 112
def receive_response(response)
  # NOTE: Take a shallow clone of the listeners so that if receiving an
  # event causes a new listener to be added, it won't receive this response!
  @listeners.clone.each{ |listener| listener.receive_event response }
end
send_command(cmd, *args) click to toggle source

Send the command, with the given arguments, to the IMAP server.

@param cmd, the name of the command to send (a string) @param *args, the arguments for the command, serialized

by Net::IMAP. (FIXME)

@return Command, a listener and deferrable that will receive_event

with the responses from the IMAP server, and which
will succeed with a tagged response from the
server, or fail with a tagged error response, or
an exception.

NOTE: The responses it overhears may be intended
for other commands that are running in parallel.

Exceptions thrown during serialization will be thrown to the user, exceptions thrown while communicating to the socket will cause the returned command to fail.

# File lib/em-imap/connection.rb, line 80
def send_command(cmd, *args)
  Command.new(next_tag!, cmd, args).tap do |command|
    add_to_listener_pool(command)
    listen_for_tagged_response(command)
    send_command_object(command)
  end
end
unbind() click to toggle source

Called when the connection is closed. TODO: Figure out how to send a useful error…

# File lib/em-imap/connection.rb, line 137
def unbind
  @unbound = true
  fail EOFError.new("Connection to IMAP server was unbound")
end