Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Add some commentry to the command sender

  • Loading branch information...
commit f8182e1ede48e506c6edb8ac07c9d782345dbb36 1 parent f585105
@ConradIrwin ConradIrwin authored
Showing with 92 additions and 35 deletions.
  1. +92 −35 lib/em-imap/command_sender.rb
View
127 lib/em-imap/command_sender.rb
@@ -1,13 +1,21 @@
module EventMachine
module IMAP
- # Provides a send_command_object method that serializes command objects
- # and uses send_data on them. This is the ugly sister to ResponseParser.
+ # 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.
module CommandSender
- # This is a method that synchronously converts the command into fragments
- # of string.
+ # 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.
#
- # If you pass something that cannot be serialized, an exception will be raised.
- # If however, something fails at the socket level, the command will be failed.
def send_command_object(command)
Formatter.format(command) do |to_send|
if to_send.is_a? Formatter::Literal
@@ -18,7 +26,71 @@ def send_command_object(command)
end
end
- # See Net::IMAP#authenticate
+ # 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.
+ #
+ def send_string(str, command)
+ when_not_awaiting_continuation do
+ begin
+ send_line_buffered str
+ rescue => e
+ command.fail e
+ end
+ end
+ end
+
+ # 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.
+ #
+ 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
+
+ # 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.
+ #
def send_authentication_data(auth_handler, command)
when_not_awaiting_continuation do
waiter = await_continuations do |response|
@@ -34,6 +106,14 @@ def send_authentication_data(auth_handler, command)
end
end
+ # 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.
+ #
def prepare_idle_continuation(command)
when_not_awaiting_continuation do
waiter = await_continuations
@@ -48,35 +128,12 @@ def prepare_idle_continuation(command)
end
end
- def send_string(str, command)
- when_not_awaiting_continuation do
- begin
- send_line_buffered str
- rescue => e
- command.fail e
- end
- end
- end
-
- 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
+ # Buffers out-going string sending by-line.
+ #
+ # This is safe to do for IMAP because the client always ends transmission
+ # on a CRLF (for awaiting continuation requests, and for ending commands)
+ #
module LineBuffer
def post_init
super
Please sign in to comment.
Something went wrong with that request. Please try again.