module EventMachine::IMAP::CommandSender

Used to send commands, and various other pieces of data, to the IMAP server as they are needed. Plugs in the ContinuationSynchronisation module so that the outgoing channel is free of racey-behaviour.

Public Instance Methods

prepare_idle_continuation(command) click to toggle source

Register a stopback on the IDLE command that sends the DONE continuation that the server is waiting for.

@param command, The IDLE command.

This blocks the outgoing connection until the IDLE command is stopped, as required by RFC 2177.

# File lib/em-imap/command_sender.rb, line 117
def prepare_idle_continuation(command)
  when_not_awaiting_continuation do
    waiter = await_continuations
    command.stopback do
      waiter.stop
      begin
        send_data "DONE\r\n"
      rescue => e
        command.fail e
      end
    end
  end
end
send_authentication_data(auth_handler, command) click to toggle source

Pass a challenge/response between the server and the auth_handler.

@param auth_handler, an authorization handler. @param command, the associated AUTHORIZE command.

This can be called several times in one authorization handshake depending on how many messages the server wishes to see from the auth_handler.

If the auth_handler raises an exception, or the network connection dies for some reason, the command will be failed.

# File lib/em-imap/command_sender.rb, line 94
def send_authentication_data(auth_handler, command)
  when_not_awaiting_continuation do
    waiter = await_continuations do |response|
      begin
        data = auth_handler.process(response.data.text.unpack("m")[0])
        s = [data].pack("m").gsub(/\n/, "")
        send_data(s + CRLF)
      rescue => e
        command.fail e
      end
    end
    command.bothback{ |*args| waiter.stop }
  end
end
send_command_object(command) click to toggle source

Send a command to the IMAP server.

@param command, The command to send.

This method has two phases, the first of which is to convert your command into tokens for sending over the network, and the second is to actually send those fragments.

If the conversion fails, a Net::IMAP::DataFormatError will be raised which you should handle synchronously. If the sending fails, then the command will be failed asynchronously.

# File lib/em-imap/command_sender.rb, line 19
def send_command_object(command)
  Formatter.format(command) do |to_send|
    if to_send.is_a? Formatter::Literal
      send_literal to_send.str, command
    else
      send_string  to_send, command
    end
  end
end
send_literal(literal, command) click to toggle source

Send an IMAP literal to the server.

@param literal, the string to send. @param command, the command associated with this string.

Sending literals is a somewhat complicated process:

Step 1. Client tells the server how big the literal will be.

(and at the same time shows the server the contents of the command so
far)

Step 2. The server either accepts (with a ContinuationResponse) or

rejects (with a BadResponse) the continuation based on the size of the
literal, and the validity of the line so far.

Step 3. The client sends the literal, followed by a linefeed, and then continues with sending the rest of the command.

# File lib/em-imap/command_sender.rb, line 63
def send_literal(literal, command)
  when_not_awaiting_continuation do
    begin
      send_line_buffered "{" + literal.size.to_s + "}" + CRLF
    rescue => e
      command.fail e
    end
    waiter = await_continuations do
      begin
        send_data literal
      rescue => e
        command.fail e
      end
      waiter.stop
    end
    command.errback{ waiter.stop }
  end
end
send_string(str, command) click to toggle source

Send some normal (binary/string) data to the server.

@param str, the data to send @param command, the command for which the data is being sent.

This uses the LineBuffer, and fails the command if the network connection has died for some reason.

# File lib/em-imap/command_sender.rb, line 37
def send_string(str, command)
  when_not_awaiting_continuation do
    begin
      send_line_buffered str
    rescue => e
      command.fail e
    end
  end
end