From dc103ab9ce26a6d2ef4d7585e430804b65156e27 Mon Sep 17 00:00:00 2001 From: Sebastian Spaeth Date: Mon, 5 Sep 2011 10:27:47 +0200 Subject: [PATCH] Protect IMAP.getmessage() against dropped connections If a connection is dropped for some reason while fetching a message, the imapobj.uid command throws an imapbj.abort() Exception which means we are supposed to retry. Implement a fail loop that drops the connection, gets a new one and attempts the command another time. Remove obsolete comment that we need to catch nonexisting messages. We do now. GMail seems to drop connections left and right. This patch is a response to the reported mail "4E5F8D8C.1020005@gmail.com" by zeek . Signed-off-by: Sebastian Spaeth Signed-off-by: Nicolas Sebrecht --- offlineimap/folder/IMAP.py | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/offlineimap/folder/IMAP.py b/offlineimap/folder/IMAP.py index dec14ae..ac18d69 100644 --- a/offlineimap/folder/IMAP.py +++ b/offlineimap/folder/IMAP.py @@ -207,8 +207,21 @@ class IMAPFolder(BaseFolder): """ imapobj = self.imapserver.acquireconnection() try: - imapobj.select(self.getfullname(), readonly = 1) - res_type, data = imapobj.uid('fetch', str(uid), '(BODY.PEEK[])') + fails_left = 2 # retry on dropped connection + while fails_left: + try: + imapobj.select(self.getfullname(), readonly = 1) + res_type, data = imapobj.uid('fetch', str(uid), + '(BODY.PEEK[])') + fails_left = 0 + except imapobj.abort(), e: + # Release dropped connection, and get a new one + self.imapserver.releaseconnection(imapobj) + imapobj = self.imapserver.acquireconnection() + self.ui.error(e, exc_info()[2]) + fails_left -= 1 + if not fails_left: + raise e if data == [None] or res_type != 'OK': #IMAP server says bad request or UID does not exist severity = OfflineImapError.ERROR.MESSAGE @@ -223,16 +236,6 @@ class IMAPFolder(BaseFolder): # data looks now e.g. [('320 (UID 17061 BODY[] # {2565}','msgbody....')] we only asked for one message, # and that msg is in data[0]. msbody is in [0][1] - - #NB & TODO: When the message on the IMAP server has been - #deleted in the mean time, it will respond with an 'OK' - #res_type, but it will simply not send any data. This will - #lead to a crash in the below line. We need urgently to - #detect this, protect from this and need to think about what - #to return in this case. Probably returning `None` in this - #case would be good. But we need to make sure that all - #Backends behave the same, and that we actually check the - #return value and behave accordingly. data = data[0][1].replace("\r\n", "\n") if len(data)>200: