From 5ef69e95c02f69f0a13818d418e6a5768bd4be04 Mon Sep 17 00:00:00 2001 From: Sebastian Spaeth Date: Fri, 16 Sep 2011 11:44:50 +0200 Subject: [PATCH] Prevent modifications on a folder level to occur in dry-run Prevent savemessage(), and savemessageflags() to occur in dryrun mode in all backends. Still need to protect against deletemessage(). Signed-off-by: Sebastian Spaeth --- offlineimap/folder/Base.py | 37 +++++++++++++++++++++++-- offlineimap/folder/IMAP.py | 12 ++++++-- offlineimap/folder/LocalStatus.py | 5 ++++ offlineimap/folder/LocalStatusSQLite.py | 5 ++++ offlineimap/folder/Maildir.py | 14 ++++++++-- offlineimap/folder/UIDMaps.py | 10 +++++++ offlineimap/ui/UIBase.py | 5 ++++ 7 files changed, 81 insertions(+), 7 deletions(-) diff --git a/offlineimap/folder/Base.py b/offlineimap/folder/Base.py index fcea99d..01a6ab5 100644 --- a/offlineimap/folder/Base.py +++ b/offlineimap/folder/Base.py @@ -208,6 +208,10 @@ class BaseFolder(object): If the uid is > 0, the backend should set the uid to this, if it can. If it cannot set the uid to that, it will save it anyway. It will return the uid assigned in any case. + + Note that savemessage() does not check against dryrun settings, + so you need to ensure that savemessage is never called in a + dryrun mode. """ raise NotImplementedException @@ -220,27 +224,48 @@ class BaseFolder(object): raise NotImplementedException def savemessageflags(self, uid, flags): - """Sets the specified message's flags to the given set.""" + """Sets the specified message's flags to the given set. + + Note that this function does not check against dryrun settings, + so you need to ensure that it is never called in a + dryrun mode.""" raise NotImplementedException def addmessageflags(self, uid, flags): """Adds the specified flags to the message's flag set. If a given flag is already present, it will not be duplicated. + + Note that this function does not check against dryrun settings, + so you need to ensure that it is never called in a + dryrun mode. + :param flags: A set() of flags""" newflags = self.getmessageflags(uid) | flags self.savemessageflags(uid, newflags) def addmessagesflags(self, uidlist, flags): + """ + Note that this function does not check against dryrun settings, + so you need to ensure that it is never called in a + dryrun mode.""" for uid in uidlist: self.addmessageflags(uid, flags) def deletemessageflags(self, uid, flags): """Removes each flag given from the message's flag set. If a given - flag is already removed, no action will be taken for that flag.""" + flag is already removed, no action will be taken for that flag. + + Note that this function does not check against dryrun settings, + so you need to ensure that it is never called in a + dryrun mode.""" newflags = self.getmessageflags(uid) - flags self.savemessageflags(uid, newflags) def deletemessagesflags(self, uidlist, flags): + """ + Note that this function does not check against dryrun settings, + so you need to ensure that it is never called in a + dryrun mode.""" for uid in uidlist: self.deletemessageflags(uid, flags) @@ -345,6 +370,10 @@ class BaseFolder(object): statusfolder.uidexists(uid), self.getmessageuidlist()) num_to_copy = len(copylist) + if num_to_copy and self.repository.account.dryrun: + self.ui.info("[DRYRUN] Copy {} messages from {}[{}] to {}".format( + num_to_copy, self, self.repository, dstfolder.repository)) + return for num, uid in enumerate(copylist): # bail out on CTRL-C or SIGTERM if offlineimap.accounts.Account.abort_NOW_signal.is_set(): @@ -422,11 +451,15 @@ class BaseFolder(object): for flag, uids in addflaglist.items(): self.ui.addingflags(uids, flag, dstfolder) + if self.repository.account.dryrun: + continue #don't actually add in a dryrun dstfolder.addmessagesflags(uids, set(flag)) statusfolder.addmessagesflags(uids, set(flag)) for flag,uids in delflaglist.items(): self.ui.deletingflags(uids, flag, dstfolder) + if self.repository.account.dryrun: + continue #don't actually remove in a dryrun dstfolder.deletemessagesflags(uids, set(flag)) statusfolder.deletemessagesflags(uids, set(flag)) diff --git a/offlineimap/folder/IMAP.py b/offlineimap/folder/IMAP.py index 8b46996..f783d22 100644 --- a/offlineimap/folder/IMAP.py +++ b/offlineimap/folder/IMAP.py @@ -488,12 +488,16 @@ class IMAPFolder(BaseFolder): This function will update the self.messagelist dict to contain the new message after sucessfully saving it. + See folder/Base for details. Note that savemessage() does not + check against dryrun settings, so you need to ensure that + savemessage is never called in a dryrun mode. + :param rtime: A timestamp to be used as the mail date :returns: the UID of the new message as assigned by the server. If the message is saved, but it's UID can not be found, it will return 0. If the message can't be written (folder is read-only for example) it will return -1.""" - self.ui.debug('imap', 'savemessage: called') + self.ui.savemessage('imap', uid, flags, self) # already have it, just save modified flags if uid > 0 and self.uidexists(uid): @@ -611,7 +615,11 @@ class IMAPFolder(BaseFolder): return uid def savemessageflags(self, uid, flags): - """Change a message's flags to `flags`.""" + """Change a message's flags to `flags`. + + Note that this function does not check against dryrun settings, + so you need to ensure that it is never called in a + dryrun mode.""" imapobj = self.imapserver.acquireconnection() try: try: diff --git a/offlineimap/folder/LocalStatus.py b/offlineimap/folder/LocalStatus.py index 7f27768..b3779fd 100644 --- a/offlineimap/folder/LocalStatus.py +++ b/offlineimap/folder/LocalStatus.py @@ -111,6 +111,11 @@ class LocalStatusFolder(BaseFolder): return self.messagelist def savemessage(self, uid, content, flags, rtime): + """Writes a new message, with the specified uid. + + See folder/Base for detail. Note that savemessage() does not + check against dryrun settings, so you need to ensure that + savemessage is never called in a dryrun mode.""" if uid < 0: # We cannot assign a uid. return uid diff --git a/offlineimap/folder/LocalStatusSQLite.py b/offlineimap/folder/LocalStatusSQLite.py index dbe3e66..ac67c2f 100644 --- a/offlineimap/folder/LocalStatusSQLite.py +++ b/offlineimap/folder/LocalStatusSQLite.py @@ -216,6 +216,11 @@ class LocalStatusSQLiteFolder(LocalStatusFolder): # assert False,"getmessageflags() called on non-existing message" def savemessage(self, uid, content, flags, rtime): + """Writes a new message, with the specified uid. + + See folder/Base for detail. Note that savemessage() does not + check against dryrun settings, so you need to ensure that + savemessage is never called in a dryrun mode.""" if uid < 0: # We cannot assign a uid. return uid diff --git a/offlineimap/folder/Maildir.py b/offlineimap/folder/Maildir.py index 16745ab..24d943c 100644 --- a/offlineimap/folder/Maildir.py +++ b/offlineimap/folder/Maildir.py @@ -237,13 +237,18 @@ class MaildirFolder(BaseFolder): uid, self._foldermd5, self.infosep, ''.join(sorted(flags))) def savemessage(self, uid, content, flags, rtime): + """Writes a new message, with the specified uid. + + See folder/Base for detail. Note that savemessage() does not + check against dryrun settings, so you need to ensure that + savemessage is never called in a dryrun mode.""" # This function only ever saves to tmp/, # but it calls savemessageflags() to actually save to cur/ or new/. - self.ui.debug('maildir', 'savemessage: called to write with flags %s ' - 'and content %s' % (repr(flags), repr(content))) + self.ui.savemessage('maildir', uid, flags, self) if uid < 0: # We cannot assign a new uid. return uid + if uid in self.messagelist: # We already have it, just update flags. self.savemessageflags(uid, flags) @@ -291,8 +296,11 @@ class MaildirFolder(BaseFolder): """Sets the specified message's flags to the given set. This function moves the message to the cur or new subdir, - depending on the 'S'een flag.""" + depending on the 'S'een flag. + Note that this function does not check against dryrun settings, + so you need to ensure that it is never called in a + dryrun mode.""" oldfilename = self.messagelist[uid]['filename'] dir_prefix, filename = os.path.split(oldfilename) # If a message has been seen, it goes into 'cur' diff --git a/offlineimap/folder/UIDMaps.py b/offlineimap/folder/UIDMaps.py index 99ad2d3..f1c11e4 100644 --- a/offlineimap/folder/UIDMaps.py +++ b/offlineimap/folder/UIDMaps.py @@ -184,7 +184,12 @@ class MappedIMAPFolder(IMAPFolder): If the uid is > 0, the backend should set the uid to this, if it can. If it cannot set the uid to that, it will save it anyway. It will return the uid assigned in any case. + + See folder/Base for details. Note that savemessage() does not + check against dryrun settings, so you need to ensure that + savemessage is never called in a dryrun mode. """ + self.ui.savemessage('imap', uid, flags, self) # Mapped UID instances require the source to already have a # positive UID, so simply return here. if uid < 0: @@ -217,6 +222,11 @@ class MappedIMAPFolder(IMAPFolder): return None def savemessageflags(self, uid, flags): + """ + + Note that this function does not check against dryrun settings, + so you need to ensure that it is never called in a + dryrun mode.""" self._mb.savemessageflags(self.r2l[uid], flags) def addmessageflags(self, uid, flags): diff --git a/offlineimap/ui/UIBase.py b/offlineimap/ui/UIBase.py index 4ff98c3..32511a4 100644 --- a/offlineimap/ui/UIBase.py +++ b/offlineimap/ui/UIBase.py @@ -408,6 +408,11 @@ class UIBase(object): if conn: #release any existing IMAP connection repository.imapserver.close() + def savemessage(self, debugtype, uid, flags, folder): + """Output a log line stating that we save a msg""" + self.debug(debugtype, "Write mail '%s:%d' with flags %s" % + (folder, uid, repr(flags))) + ################################################## Threads def getThreadDebugLog(self, thread):