Prevent reconnect loop from occurring

I noticed recently that when composing a draft message, if the
connection to the Drafts folder was dropped by the server, Geary
would enter a fast reconnect loop.  The problem was that, even if
Imap.Folder signals "disconnect", it's close_async() must be called.
This adds that logic to the background reestablishment code.
This commit is contained in:
Jim Nelson 2014-01-29 12:08:39 -08:00
parent c7b56db19a
commit 86f1854edf

View file

@ -643,25 +643,26 @@ private class Geary.ImapEngine.GenericFolder : Geary.AbstractFolder, Geary.Folde
if (closing_remote_folder != null) { if (closing_remote_folder != null) {
// to avoid keeping the caller waiting while the remote end closes (i.e. drops the // to avoid keeping the caller waiting while the remote end closes (i.e. drops the
// connection or performs an IMAP CLOSE operation), close it in the background // connection or performs an IMAP CLOSE operation), close it in the background and
// reestablish connection there, if necessary
// //
// TODO: Problem with this is that we cannot effectively signal or report a close error, // TODO: Problem with this is that we cannot effectively signal or report a close error,
// because by the time this operation completes the folder is considered closed. That // because by the time this operation completes the folder is considered closed. That
// may not be important to most callers, however. // may not be important to most callers, however.
closing_remote_folder.close_async.begin(cancellable); //
// It also means the reference to the Folder must be maintained until completely
// closed. Also not a problem, as GenericAccount does that internally. However, this
// might be an issue if GenericAccount removes this folder due to a user command or
// detection on the server, so this background op keeps a reference to the Folder
close_remote_folder_async.begin(this, closing_remote_folder, remote_reason);
} }
remote_opened = false; remote_opened = false;
// reestablish connection (which requires renormalizing the remote with the local) if // if remote reason is an error, then close_remote_folder_async() will be performing
// close was in error // reestablishment, so go no further
if (remote_reason.is_error()) { if (remote_reason.is_error())
debug("Reestablishing broken connect to %s", to_string());
open_internal(OpenFlags.NO_DELAY, null);
return; return;
}
// forced closed one way or another // forced closed one way or another
open_count = 0; open_count = 0;
@ -703,6 +704,27 @@ private class Geary.ImapEngine.GenericFolder : Geary.AbstractFolder, Geary.Folde
return old_remote_folder; return old_remote_folder;
} }
// See note in close_async() for why this method is static and uses an owned ref
private static async void close_remote_folder_async(owned GenericFolder folder,
owned Imap.Folder remote_folder, Folder.CloseReason remote_reason) {
// force the remote closed; if due to a remote disconnect and plan on reopening, *still*
// need to do this
try {
yield remote_folder.close_async(null);
} catch (Error err) {
debug("Unable to close remote %s: %s", remote_folder.to_string(), err.message);
// fallthrough
}
// reestablish connection (which requires renormalizing the remote with the local) if
// close was in error
if (remote_reason.is_error()) {
debug("Reestablishing broken connection to %s", folder.to_string());
folder.open_internal(OpenFlags.NO_DELAY, null);
}
}
public override async void find_boundaries_async(Gee.Collection<Geary.EmailIdentifier> ids, public override async void find_boundaries_async(Gee.Collection<Geary.EmailIdentifier> ids,
out Geary.EmailIdentifier? low, out Geary.EmailIdentifier? high, out Geary.EmailIdentifier? low, out Geary.EmailIdentifier? high,
Cancellable? cancellable = null) throws Error { Cancellable? cancellable = null) throws Error {