Error proof IMAP.APPEND against dropped connections
Make sure that when a connection is dropped during append, we really discard the broken connection and get a new one, retrying. We retry indefinitely on the specific abort() Exception, as this is what imaplib2 suggests us to do. Signed-off-by: Sebastian Spaeth <Sebastian@SSpaeth.de> Signed-off-by: Nicolas Sebrecht <nicolas.s-dev@laposte.net>
This commit is contained in:
parent
9c678c9d6b
commit
2cf6155282
@ -21,6 +21,7 @@ import random
|
|||||||
import binascii
|
import binascii
|
||||||
import re
|
import re
|
||||||
import time
|
import time
|
||||||
|
from sys import exc_info
|
||||||
from copy import copy
|
from copy import copy
|
||||||
from Base import BaseFolder
|
from Base import BaseFolder
|
||||||
from offlineimap import imaputil, imaplibutil, OfflineImapError
|
from offlineimap import imaputil, imaplibutil, OfflineImapError
|
||||||
@ -500,53 +501,62 @@ class IMAPFolder(BaseFolder):
|
|||||||
self.savemessageflags(uid, flags)
|
self.savemessageflags(uid, flags)
|
||||||
return uid
|
return uid
|
||||||
|
|
||||||
|
imapobj = self.imapserver.acquireconnection()
|
||||||
try:
|
try:
|
||||||
imapobj = self.imapserver.acquireconnection()
|
success = False # succeeded in APPENDING?
|
||||||
|
while not success:
|
||||||
|
|
||||||
try:
|
# UIDPLUS extension provides us with an APPENDUID response.
|
||||||
imapobj.select(self.getfullname()) # Needed for search and making the box READ-WRITE
|
use_uidplus = 'UIDPLUS' in imapobj.capabilities
|
||||||
except imapobj.readonly:
|
|
||||||
# readonly exception. Return original uid to notify that
|
|
||||||
# we did not save the message. (see savemessage in Base.py)
|
|
||||||
self.ui.msgtoreadonly(self, uid, content, flags)
|
|
||||||
return uid
|
|
||||||
|
|
||||||
# UIDPLUS extension provides us with an APPENDUID response to our append()
|
# get the date of the message, so we can pass it to the server.
|
||||||
use_uidplus = 'UIDPLUS' in imapobj.capabilities
|
date = self.getmessageinternaldate(content, rtime)
|
||||||
|
content = re.sub("(?<!\r)\n", "\r\n", content)
|
||||||
|
|
||||||
# get the date of the message file, so we can pass it to the server.
|
if not use_uidplus:
|
||||||
date = self.getmessageinternaldate(content, rtime)
|
# insert a random unique header that we can fetch later
|
||||||
content = re.sub("(?<!\r)\n", "\r\n", content)
|
(headername, headervalue) = self.generate_randomheader(
|
||||||
|
content)
|
||||||
|
self.ui.debug('imap', 'savemessage: header is: %s: %s' %\
|
||||||
|
(headername, headervalue))
|
||||||
|
content = self.savemessage_addheader(content, headername,
|
||||||
|
headervalue)
|
||||||
|
if len(content)>200:
|
||||||
|
dbg_output = "%s...%s" % (content[:150], content[-50:])
|
||||||
|
else:
|
||||||
|
dbg_output = content
|
||||||
|
self.ui.debug('imap', "savemessage: date: %s, content: '%s'" %
|
||||||
|
(date, dbg_output))
|
||||||
|
|
||||||
if not use_uidplus:
|
try:
|
||||||
# insert a random unique header that we can fetch later
|
# Select folder for append and make the box READ-WRITE
|
||||||
(headername, headervalue) = self.generate_randomheader(content)
|
imapobj.select(self.getfullname())
|
||||||
self.ui.debug('imap', 'savemessage: new header is: %s: %s' % \
|
except imapobj.readonly:
|
||||||
(headername, headervalue))
|
# readonly exception. Return original uid to notify that
|
||||||
content = self.savemessage_addheader(content, headername,
|
# we did not save the message. (see savemessage in Base.py)
|
||||||
headervalue)
|
self.ui.msgtoreadonly(self, uid, content, flags)
|
||||||
if len(content)>200:
|
return uid
|
||||||
dbg_output = "%s...%s" % (content[:150],
|
|
||||||
content[-50:])
|
|
||||||
else:
|
|
||||||
dbg_output = content
|
|
||||||
self.ui.debug('imap', "savemessage: date: %s, content: '%s'" %
|
|
||||||
(date, dbg_output))
|
|
||||||
|
|
||||||
#Do the APPEND
|
#Do the APPEND
|
||||||
try:
|
try:
|
||||||
(typ, dat) = imapobj.append(self.getfullname(),
|
(typ, dat) = imapobj.append(self.getfullname(),
|
||||||
imaputil.flagsmaildir2imap(flags),
|
imaputil.flagsmaildir2imap(flags),
|
||||||
date, content)
|
date, content)
|
||||||
except Exception, e:
|
success = True
|
||||||
# If the server responds with 'BAD', append() raise()s directly.
|
except imapobj.abort, e:
|
||||||
# So we need to prepare a response ourselves.
|
# connection has been reset, release connection and retry.
|
||||||
typ, dat = 'BAD', str(e)
|
self.ui.error(e, exc_info()[2])
|
||||||
if typ != 'OK': #APPEND failed
|
self.imapserver.releaseconnection(imapobj, True)
|
||||||
raise OfflineImapError("Saving msg in folder '%s', repository "
|
imapobj = self.imapserver.acquireconnection()
|
||||||
"'%s' failed. Server reponded; %s %s\nMessage content was:"
|
except imapobj.error, e:
|
||||||
" %s" % (self, self.getrepository(), typ, dat, dbg_output),
|
# If the server responds with 'BAD', append() raise()s directly.
|
||||||
OfflineImapError.ERROR.MESSAGE)
|
# So we need to prepare a response ourselves.
|
||||||
|
typ, dat = 'BAD', str(e)
|
||||||
|
if typ != 'OK': #APPEND failed
|
||||||
|
raise OfflineImapError("Saving msg in folder '%s', repository "
|
||||||
|
"'%s' failed. Server reponded; %s %s\nMessage content was:"
|
||||||
|
" %s" % (self, self.getrepository(), typ, dat, dbg_output),
|
||||||
|
OfflineImapError.ERROR.MESSAGE)
|
||||||
# Checkpoint. Let it write out stuff, etc. Eg searches for
|
# Checkpoint. Let it write out stuff, etc. Eg searches for
|
||||||
# just uploaded messages won't work if we don't do this.
|
# just uploaded messages won't work if we don't do this.
|
||||||
(typ,dat) = imapobj.check()
|
(typ,dat) = imapobj.check()
|
||||||
|
Loading…
Reference in New Issue
Block a user