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
<ezekiel.das@gmail.com>.

Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de>
Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
This commit is contained in:
Sebastian Spaeth 2011-09-05 10:27:47 +02:00 committed by Nicolas Sebrecht
parent 7aa4c49ba4
commit dc103ab9ce

View File

@ -206,9 +206,22 @@ class IMAPFolder(BaseFolder):
this UID could be found.
"""
imapobj = self.imapserver.acquireconnection()
try:
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[])')
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: