1
0
mirror of https://github.com/OfflineIMAP/offlineimap.git synced 2024-07-05 08:51:00 +02:00

Fix error handling in folder.Base.copymessageto()

This is a bug fix on several levels. 1) We were lacking the import of
OfflineImapError. 2) OfflineImap.ERROR.MESSAGE was misspelled as ERROR.Message.
3) COntinuing with the next message only worked in single-thread mode
(using debug) and not in multi-thread mode. The reason is that we were
invoking a new thread and catching Exceptions in the main thread. But
python immediately aborts if an Exception bubbles up to a thread start.
This was fixed by catching exceptions directly in copymessageto() which
is the new thread, rather than catching them in the main thread.

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-08-15 11:00:06 +02:00 committed by Nicolas Sebrecht
parent 634b6cd49e
commit 9f23fea74e

View File

@ -17,6 +17,7 @@
from offlineimap import threadutil from offlineimap import threadutil
from offlineimap.ui import getglobalui from offlineimap.ui import getglobalui
from offlineimap.error import OfflineImapError
import os.path import os.path
import re import re
from sys import exc_info from sys import exc_info
@ -233,52 +234,63 @@ class BaseFolder(object):
if register: # output that we start a new thread if register: # output that we start a new thread
self.ui.registerthread(self.getaccountname()) self.ui.registerthread(self.getaccountname())
message = None try:
flags = self.getmessageflags(uid) message = None
rtime = self.getmessagetime(uid) flags = self.getmessageflags(uid)
rtime = self.getmessagetime(uid)
if uid > 0 and dstfolder.uidexists(uid): if uid > 0 and dstfolder.uidexists(uid):
# dst has message with that UID already, only update status # dst has message with that UID already, only update status
statusfolder.savemessage(uid, None, flags, rtime) statusfolder.savemessage(uid, None, flags, rtime)
return return
self.ui.copyingmessage(uid, self, [dstfolder]) self.ui.copyingmessage(uid, self, [dstfolder])
# If any of the destinations actually stores the message body, # If any of the destinations actually stores the message body,
# load it up. # load it up.
if dstfolder.storesmessages(): if dstfolder.storesmessages():
message = self.getmessage(uid) message = self.getmessage(uid)
#Succeeded? -> IMAP actually assigned a UID. If newid #Succeeded? -> IMAP actually assigned a UID. If newid
#remained negative, no server was willing to assign us an #remained negative, no server was willing to assign us an
#UID. If newid is 0, saving succeeded, but we could not #UID. If newid is 0, saving succeeded, but we could not
#retrieve the new UID. Ignore message in this case. #retrieve the new UID. Ignore message in this case.
newuid = dstfolder.savemessage(uid, message, flags, rtime) newuid = dstfolder.savemessage(uid, message, flags, rtime)
if newuid > 0: if newuid > 0:
if newuid != uid: if newuid != uid:
# Got new UID, change the local uid. # Got new UID, change the local uid.
#TODO: Maildir could do this with a rename rather than #TODO: Maildir could do this with a rename rather than
#load/save/del operation, IMPLEMENT a changeuid() #load/save/del operation, IMPLEMENT a changeuid()
#function or so. #function or so.
self.savemessage(newuid, message, flags, rtime) self.savemessage(newuid, message, flags, rtime)
self.deletemessage(uid)
uid = newuid
# Save uploaded status in the statusfolder
statusfolder.savemessage(uid, message, flags, rtime)
elif newuid == 0:
# Message was stored to dstfolder, but we can't find it's UID
# This means we can't link current message to the one created
# in IMAP. So we just delete local message and on next run
# we'll sync it back
# XXX This could cause infinite loop on syncing between two
# IMAP servers ...
self.deletemessage(uid) self.deletemessage(uid)
uid = newuid else:
# Save uploaded status in the statusfolder raise OfflineImapError("Trying to save msg (uid %d) on folder "
statusfolder.savemessage(uid, message, flags, rtime) "%s returned invalid uid %d" % \
(uid,
dstfolder.getvisiblename(),
newuid),
OfflineImapError.ERROR.MESSAGE)
except OfflineImapError, e:
if e.severity > OfflineImapError.ERROR.MESSAGE:
raise # buble severe errors up
self.ui.error(e, exc_info()[2])
except Exception, e:
self.ui.error(e, "Copying message %s [acc: %s]:\n %s" %\
(uid, self.getaccountname(),
traceback.format_exc()))
raise #raise on unknown errors, so we can fix those
elif newuid == 0:
# Message was stored to dstfolder, but we can't find it's UID
# This means we can't link current message to the one created
# in IMAP. So we just delete local message and on next run
# we'll sync it back
# XXX This could cause infinite loop on syncing between two
# IMAP servers ...
self.deletemessage(uid)
else:
raise OfflineImapError("Trying to save msg (uid %d) on folder "
"%s returned invalid uid %d" % \
(uid,
dstfolder.getvisiblename(),
newuid),
OfflineImapError.ERROR.MESSAGE)
def syncmessagesto_copy(self, dstfolder, statusfolder): def syncmessagesto_copy(self, dstfolder, statusfolder):
"""Pass1: Copy locally existing messages not on the other side """Pass1: Copy locally existing messages not on the other side
@ -297,30 +309,21 @@ class BaseFolder(object):
statusfolder.uidexists(uid), statusfolder.uidexists(uid),
self.getmessageuidlist()) self.getmessageuidlist())
for uid in copylist: for uid in copylist:
try: # exceptions are caught in copymessageto()
if self.suggeststhreads(): if self.suggeststhreads():
self.waitforthread() self.waitforthread()
thread = threadutil.InstanceLimitedThread(\ thread = threadutil.InstanceLimitedThread(\
self.getcopyinstancelimit(), self.getcopyinstancelimit(),
target = self.copymessageto, target = self.copymessageto,
name = "Copy message %d from %s" % (uid, name = "Copy message %d from %s" % (uid,
self.getvisiblename()), self.getvisiblename()),
args = (uid, dstfolder, statusfolder)) args = (uid, dstfolder, statusfolder))
thread.setDaemon(1) thread.setDaemon(1)
thread.start() thread.start()
threads.append(thread) threads.append(thread)
else: else:
self.copymessageto(uid, dstfolder, statusfolder, self.copymessageto(uid, dstfolder, statusfolder,
register = 0) register = 0)
except OfflineImapError, e:
if e.severity > OfflineImapError.ERROR.Message:
raise # buble severe errors up
self.ui.error(e, exc_info()[2])
except Exception, e:
self.ui.error(e, "Copying message %s [acc: %s]:\n %s" %\
(uid, self.getaccountname(),
traceback.format_exc()))
raise #raise on unknown errors, so we can fix those
for thread in threads: for thread in threads:
thread.join() thread.join()