diff --git a/offlineimap/error.py b/offlineimap/error.py index 9e55162..aa7f535 100644 --- a/offlineimap/error.py +++ b/offlineimap/error.py @@ -5,11 +5,12 @@ class OfflineImapError(Exception): """Severity level of an Exception * **MESSAGE**: Abort the current message, but continue with folder + * **FOLDER_RETRY**: Error syncing folder, but do retry * **FOLDER**: Abort folder sync, but continue with next folder * **REPO**: Abort repository sync, continue with next account * **CRITICAL**: Immediately exit offlineimap """ - MESSAGE, FOLDER, REPO, CRITICAL = 0, 10, 20, 30 + MESSAGE, FOLDER_RETRY, FOLDER, REPO, CRITICAL = 0, 10, 15, 20, 30 def __init__(self, reason, severity, errcode=None): """ diff --git a/offlineimap/imaplibutil.py b/offlineimap/imaplibutil.py index fa3a303..529af6f 100644 --- a/offlineimap/imaplibutil.py +++ b/offlineimap/imaplibutil.py @@ -49,7 +49,14 @@ class UsefulIMAPMixIn: return # Wipe out all old responses, to maintain semantics with old imaplib2 del self.untagged_responses[:] - result = self.__class__.__bases__[1].select(self, mailbox, readonly) + try: + result = self.__class__.__bases__[1].select(self, mailbox, readonly) + except self.abort, e: + # self.abort is raised when we are supposed to retry + errstr = "Server '%s' closed connection, error on SELECT '%s'. Ser"\ + "ver said: %s" % (self.host, mailbox, e.args[0]) + severity = OfflineImapError.ERROR.FOLDER_RETRY + raise OfflineImapError(errstr, severity) if result[0] != 'OK': #in case of error, bail out with OfflineImapError errstr = "Error SELECTing mailbox '%s', server reply:\n%s" %\ diff --git a/offlineimap/imapserver.py b/offlineimap/imapserver.py index 3ce751c..e630f83 100644 --- a/offlineimap/imapserver.py +++ b/offlineimap/imapserver.py @@ -26,7 +26,7 @@ import socket import base64 import time import errno - +from sys import exc_info from socket import gaierror try: from ssl import SSLError, cert_time_to_seconds @@ -456,6 +456,7 @@ class IdleThread(object): self.parent = parent self.folder = folder self.event = Event() + self.ui = getglobalui() if folder is None: self.thread = Thread(target=self.noop) else: @@ -505,13 +506,24 @@ class IdleThread(object): self.imapaborted = True self.stop() - imapobj = self.parent.acquireconnection() - imapobj.select(self.folder) + success = False # successfully selected FOLDER? + while not success: + imapobj = self.parent.acquireconnection() + try: + imapobj.select(self.folder) + except OfflineImapError, e: + if e.severity == OfflineImapError.ERROR.FOLDER_RETRY: + # Connection closed, release connection and retry + self.ui.error(e, exc_info()[2]) + self.parent.releaseconnection(imapobj) + else: + raise e + else: + success = True if "IDLE" in imapobj.capabilities: imapobj.idle(callback=callback) else: - ui = getglobalui() - ui.warn("IMAP IDLE not supported on connection to %s." + self.ui.warn("IMAP IDLE not supported on connection to %s." "Falling back to old behavior: sleeping until next" "refresh cycle." %(imapobj.identifier,))