Since the idle timer was not being cancelled, when idle_when_quiet was
set to false the connection would still send IDLE. This also removes the
need to send a NOOP to get in/out of IDLE.
Issue #26 underscored Geary's buggy behaviour in sending commands while
an IDLE command was active - when a new command was queued, DONE would be
sent but then the new command would also be sent without waiting for the
status response for the IDLE command from the server, in violation of
RFC 3501 sections 2.2.1 and 5.5.
A quick fix was to ensure that the new command was held while DEIDLING,
but because of the way the synchronization process between
ClientConnection and the Serialiser works, there is a race that allows
any further commands added to be sent while the IDLE DONE had not yet
been flushed: DONE gets queued, additional command gets queued, then
both get flushed.
Fixing this required re-working how ClientConnection and Serializer
interacted, which was a major re-write. Serializer no longer buffers
any data - it simply writes it out to its underlying stream.
ClientConnection now queues commands and writes them out one by one,
requiring Command implementations to manage stalling the queue until
their expected completions have been received. Literals are hence
written by their command's serialisation process, which gets prompted
by an event from ClientConnection. The two commands that require
non-literal continuations, IDLE and AUTHENTICATE, now manage that
themselves.
As a result, only one command can be serialised at a time, and no
additional commands can be serialised while another is still waiting for
a continuation. Also, command-specific details can be implemented by
command itself, without needing workarounds in the serialiser,
connection, or session.
Instead, make the args property a parameter list, and add params to that.
This means Command's serialize method have a different signature compared
to Parameter's, letting us do some more interesting things with it.
The ListParameter.parent property only existed to make the deserialier's
life easier, but is also why sketchy code was needed for appending search
criteria from a ServerSearchEmail replay op to the actual IMAP search
command sent to the server.
This removes the property altogether, and replaces its only use in
Deserialier with a stack, as nature intended. This means lists can be
added to more than one other list, and e.g. when a search is executed,
the search critera can be used for multiple requests.
I.e. Don't modify the list being appended from, so that when the
ServerSearchEmail replay op is re-executed after a network error, the
search criteria have not disappeared.
Don't silently fail to parse Date headers that are actually longs, since
that will throw an error when the message is being loaded by the
conversation monitor. Handle cases where that error might be thrown
gracefully so we can attempt to save/load/display the message anyway.
This breaks sending mail via Yahoo since it doesn't like it if the SMTP
return path local part is quoted.
We can't use GMime.utils_quote_string since it's currently broken, so
implement our own quoter.