diff --git a/offlineimap/head/debian/changelog b/offlineimap/head/debian/changelog index 80a0c1e..6182782 100644 --- a/offlineimap/head/debian/changelog +++ b/offlineimap/head/debian/changelog @@ -3,6 +3,10 @@ offlineimap (3.2.2) unstable; urgency=low * Updated manual to show new Gray color. * Scrolling behavior is better now; sometimes, with fast-scrolling text, the log would stop scrolling. + * Better handling of read-only folders. We will now warn if there is + a change, but not propogate it. New config variable ignore-readonly + can suppress the warnings. This fixes [complete.org #10] and, + for Debian, Closes: #154769. -- John Goerzen Thu, 25 Jul 2002 08:22:25 -0500 diff --git a/offlineimap/head/offlineimap.conf b/offlineimap/head/offlineimap.conf index 9f49227..845d83b 100644 --- a/offlineimap/head/offlineimap.conf +++ b/offlineimap/head/offlineimap.conf @@ -66,6 +66,14 @@ maxsyncaccounts = 1 ui = Tk.Blinkenlights, Tk.VerboseUI, TTY.TTYUI, Noninteractive.Basic, Noninteractive.Quiet +# If you try to synchronize messages to a read-only folder, +# OfflineIMAP will generate a warning. If you want to suppress these +# warnings, set ignore-readonly to yes. Read-only IMAP folders allow +# reading but not modification, so if you try to change messages in +# the local copy of such a folder, the IMAP server will prevent +# OfflineIMAP from propogating those changes to the IMAP server. + +ignore-readonly = no ################################################## # Mailbox name recorder diff --git a/offlineimap/head/offlineimap/folder/IMAP.py b/offlineimap/head/offlineimap/folder/IMAP.py index ed0dfdd..d4843cb 100644 --- a/offlineimap/head/offlineimap/folder/IMAP.py +++ b/offlineimap/head/offlineimap/folder/IMAP.py @@ -98,7 +98,13 @@ class IMAPFolder(BaseFolder): def savemessage(self, uid, content, flags): imapobj = self.imapserver.acquireconnection() try: - imapobj.select(self.getfullname()) # Needed for search + try: + imapobj.select(self.getfullname()) # Needed for search + except imapobj.readonly: + __main__.ui.msgtoreadonly(self, uid, content, flags) + # Return indicating message taken, but no UID assigned. + # Fudge it. + return 0 # This backend always assigns a new uid, so the uid arg is ignored. # In order to get the new uid, we need to save off the message ID. @@ -147,7 +153,11 @@ class IMAPFolder(BaseFolder): def savemessageflags(self, uid, flags): imapobj = self.imapserver.acquireconnection() try: - imapobj.select(self.getfullname()) + try: + imapobj.select(self.getfullname()) + except imapobj.readonly: + __main__.ui.flagstoreadonly(self, [uid], flags) + return result = imapobj.uid('store', '%d' % uid, 'FLAGS', imaputil.flagsmaildir2imap(flags)) assert result[0] == 'OK', 'Error with store: ' + r[1] @@ -166,7 +176,11 @@ class IMAPFolder(BaseFolder): def addmessagesflags(self, uidlist, flags): imapobj = self.imapserver.acquireconnection() try: - imapobj.select(self.getfullname()) + try: + imapobj.select(self.getfullname()) + except imapobj.readonly: + __main__.ui.flagstoreadonly(self, uidlist, flags) + return r = imapobj.uid('store', imaputil.listjoin(uidlist), '+FLAGS', @@ -213,7 +227,11 @@ class IMAPFolder(BaseFolder): self.addmessagesflags(uidlist, ['T']) imapobj = self.imapserver.acquireconnection() try: - imapobj.select(self.getfullname()) + try: + imapobj.select(self.getfullname()) + except imapobj.readonly: + __main__.ui.deletereadonly(self, uidlist) + return assert(imapobj.expunge()[0] == 'OK') finally: self.imapserver.releaseconnection(imapobj) diff --git a/offlineimap/head/offlineimap/ui/UIBase.py b/offlineimap/head/offlineimap/ui/UIBase.py index e7f91bb..2fd665b 100644 --- a/offlineimap/head/offlineimap/ui/UIBase.py +++ b/offlineimap/head/offlineimap/ui/UIBase.py @@ -53,6 +53,22 @@ class UIBase: def folderlist(s, list): return ', '.join(["%s[%s]" % (s.getnicename(x), x.getname()) for x in list]) + ################################################## WARNINGS + def msgtoreadonly(s, destfolder, uid, content, flags): + if not (config.has_option('general', 'ignore-readonly') and config.getboolean("general", "ignore-readonly")): + s.warn("Attempted to synchronize message %d to folder %s[%s], but that folder is read-only. The message will not be copied to that folder." % \ + (uid, s.getnicename(destfolder), destfolder.getname())) + + def flagstoreadonly(s, destfolder, uidlist, flags): + if not (config.has_option('general', 'ignore-readonly') and config.getboolean("general", "ignore-readonly")): + s.warn("Attempted to modify flags for messages %s in folder %s[%s], but that folder is read-only. No flags have been modified for that message." % \ + (str(uidlist), s.getnicename(destfolder), destfolder.getname())) + + def deletereadonly(s, destfolder, uidlist): + if not (config.has_option('general', 'ignore-readonly') and config.getboolean("general", "ignore-readonly")): + s.warn("Attempted to delete messages %s in folder %s[%s], but that folder is read-only. No messages have been deleted in that folder." % \ + (str(uidlist), s.getnicename(destfolder), destfolder.getname())) + ################################################## MESSAGES def init_banner(s):