Module: EventMachine::IMAP::ContinuationSynchronisation

Included in:
CommandSender
Defined in:
lib/em-imap/continuation_synchronisation.rb

Overview

The basic IMAP protocol is an unsynchronised exchange of lines, however under some circumstances it is necessary to synchronise so that the server acknowledges each item sent by the client.

For example, this happens during authentication:

C: A0001 AUTHENTICATE LOGIN
S: + 
C: USERNAME
S: +
C: PASSWORD
S: A0001 OK authenticated as USERNAME.

And during the sending of literals:

C: A0002 SELECT {8}
S: + continue
C: All Mail
S: A0002 OK

In order to make this work this module allows part of the client to block the outbound link while waiting for the continuation responses that it is expecting.

Instance Method Summary collapse

Instance Method Details

#await_continuations(&block) ⇒ Object

Await further continuation responses from the server, and pass them to the given block.

As a side-effect causes when_not_awaiting_continuations to queue further blocks instead of executing them immediately.

NOTE: If there's currently a different block awaiting continuation responses, this block will be added to its queue.


47
48
49
50
51
52
53
54
55
56
# File 'lib/em-imap/continuation_synchronisation.rb', line 47

def await_continuations(&block)
  Listener.new(&block).tap do |waiter|
    when_not_awaiting_continuation do
      @awaiting_continuation = waiter.stopback do
        @awaiting_continuation = nil
        waiter.succeed
      end
    end
  end
end

#awaiting_continuation?Boolean

Returns:

  • (Boolean)

35
36
37
# File 'lib/em-imap/continuation_synchronisation.rb', line 35

def awaiting_continuation?
  !!@awaiting_continuation
end

#listen_for_continuationObject

Add a single, permanent listener to the connection that forwards continuation responses onto the currently awaiting block.


60
61
62
63
64
65
66
67
68
69
70
# File 'lib/em-imap/continuation_synchronisation.rb', line 60

def listen_for_continuation
  add_response_handler do |response|
    if response.is_a?(Net::IMAP::ContinuationRequest)
      if awaiting_continuation?
        @awaiting_continuation.receive_event response
      else
        fail Net::IMAP::ResponseError.new("Unexpected continuation response from server")
      end
    end
  end
end

#post_initObject


29
30
31
32
33
# File 'lib/em-imap/continuation_synchronisation.rb', line 29

def post_init
  super
  @awaiting_continuation = nil
  listen_for_continuation
end

#when_not_awaiting_continuation(&block) ⇒ Object

If nothing is listening for continuations from the server, execute the block immediately.

Otherwise add the block to the queue.

When we have replied to the server's continuation response, the queue will be emptied in-order.


80
81
82
83
84
85
86
# File 'lib/em-imap/continuation_synchronisation.rb', line 80

def when_not_awaiting_continuation(&block)
  if awaiting_continuation?
    @awaiting_continuation.bothback{ when_not_awaiting_continuation(&block) }
  else
    yield
  end
end