[PATCH v4] Re: make maxage use UIDs to avoid timezone issues
Janna Martl
janna.martl109 at gmail.com
Mon Apr 6 08:31:51 BST 2015
On Fri, Mar 27, 2015 at 02:38:02AM -0400, Janna Martl wrote:
>Thanks to UIDMaps magic, it turns out that this works without
>modification for the case when the local folder has type IMAP. The mess
>I noticed before is because I was using type Gmail, and Gmail-IMAP
>sync isn't supported (yet). In the IMAP case, UIDMaps.py defines a
>MappedIMAPFolder class, so I made a MappedGmailFolder case that inherits
>from GmailFolder and MappedIMAPFolder. I tried to check this in some
>basic cases (copying to/from empty folder, copying/ deleting messages,
>with/without maxsize) but this all seems too good to be true and I can't
>shake the feeling that I missed something.
>
>
>In order to do IMAP-IMAP sync, the local folder needs to inherit from
>MappedIMAPFolder. Make this work for Gmail as the local folder.
My previous attempt at this was very wrong. Try #2.
The one thing that's still not done with this is the unceremoniously
commented out bit about mtimes.
def syncmessagesto_labels(self, dstfolder, statusfolder):
<...>
for i, uid in enumerate(uidlist):
<...>
# mtime = dstfolder.getmessagemtime(uid)
# mtimes[uid] = mtime
labels[uid] = selflabels
# statusfolder.savemessagesmtimebulk(mtimes)
If dstfolder is another IMAP folder, then getmessagemtime isn't
implemented, so this throws an error. What should this be, if anything?
Add MappedGmailFolder class extending MappedIMAPFolder and Gmail to
allow Gmail to be used as the local folder in an IMAP-IMAP sync.
---
offlineimap/folder/Gmail.py | 45 +++++++++++++++++++++++++++++++++-----
offlineimap/folder/UIDMaps.py | 3 ++-
offlineimap/repository/Gmail.py | 5 +++++
offlineimap/repository/__init__.py | 3 ++-
4 files changed, 49 insertions(+), 7 deletions(-)
diff --git a/offlineimap/folder/Gmail.py b/offlineimap/folder/Gmail.py
index 354d544..56c5bd4 100644
--- a/offlineimap/folder/Gmail.py
+++ b/offlineimap/folder/Gmail.py
@@ -23,6 +23,7 @@ from offlineimap import imaputil, OfflineImapError
from offlineimap import imaplibutil
import offlineimap.accounts
from .IMAP import IMAPFolder
+from offlineimap.folder.UIDMaps import MappedIMAPFolder
"""Folder implementation to support features of the Gmail IMAP server."""
@@ -229,7 +230,7 @@ class GmailFolder(IMAPFolder):
return retlabels
return None
- def savemessagelabels(self, uid, labels):
+ def savemessagelabels(self, uid, labels, ignorelabels=set()):
"""Change a message's labels to `labels`.
Note that this function does not check against dryrun settings,
@@ -358,15 +359,49 @@ class GmailFolder(IMAPFolder):
self.ui.settinglabels(uid, i+1, len(uidlist), sorted(selflabels), dstfolder)
if self.repository.account.dryrun:
continue #don't actually add in a dryrun
- dstfolder.savemessagelabels(uid, selflabels, ignorelabels = self.ignorelabels)
- mtime = dstfolder.getmessagemtime(uid)
- mtimes[uid] = mtime
+ dstfolder.savemessagelabels(uid, selflabels, ignorelabels=self.ignorelabels)
+# mtime = dstfolder.getmessagemtime(uid)
+# mtimes[uid] = mtime
labels[uid] = selflabels
# Update statusfolder in a single DB transaction. It is safe, as if something fails,
# statusfolder will be updated on the next run.
statusfolder.savemessageslabelsbulk(labels)
- statusfolder.savemessagesmtimebulk(mtimes)
+# statusfolder.savemessagesmtimebulk(mtimes)
except NotImplementedError:
self.ui.warn("Can't sync labels. You need to configure a local repository of type GmailMaildir")
+
+class MappedGmailFolder(MappedIMAPFolder, GmailFolder):
+ def __init__(self, *args, **kwargs):
+ MappedIMAPFolder.__init__(self, *args, **kwargs)
+ GmailFolder.__init__(self, *args, **kwargs)
+
+ def savemessagelabels(self, uid, labels, ignorelabels=set()):
+ self.messagelist = self._mb.messagelist
+ super(MappedGmailFolder, self).savemessagelabels(self.r2l[uid],
+ labels, ignorelabels)
+
+ def getmessage(self, uid):
+ self.messagelist = self._mb.messagelist
+ return super(MappedGmailFolder, self).getmessage(uid)
+
+ def getmessagelabels(self, uid):
+ self.messagelist = self._mb.messagelist
+ return super(MappedGmailFolder, self).getmessagelabels(self.r2l[uid])
+
+ def cachemessagelist(self, min_date=None, min_uid=None):
+ # min_uid is stored as the real local value, not the remote counterpart,
+ # so this can be passed as is
+ super(MappedGmailFolder, self).cachemessagelist(min_date=min_date,
+ min_uid=min_uid)
+ self.messagelist = self._mb.messagelist
+
+ def deletemessageslabels(self, uidlist, labels):
+ uidlistl = map(lambda uid : self.r2l[uid])
+ super(MappedGmailFolder, self).deletemessageslabels(uidlistl, labels)
+
+ def addmessageslabels(self, uidlist, labels):
+ uidlistl = map(lambda uid : self.r2l[uid])
+ super(MappedGmailFolder, self).addmessageslabels(uidlistl, labels)
+
diff --git a/offlineimap/folder/UIDMaps.py b/offlineimap/folder/UIDMaps.py
index 95acbe5..167bfc3 100644
--- a/offlineimap/folder/UIDMaps.py
+++ b/offlineimap/folder/UIDMaps.py
@@ -95,7 +95,8 @@ class MappedIMAPFolder(IMAPFolder):
# Interface from BaseFolder
def cachemessagelist(self, min_date=None, min_uid=None):
- self._mb.cachemessagelist(min_date=min_date)
+ self._mb.cachemessagelist(min_date=min_date, min_uid=min_uid)
+ self.messagelist = self._mb.messagelist
reallist = self._mb.getmessagelist()
self.maplock.acquire()
diff --git a/offlineimap/repository/Gmail.py b/offlineimap/repository/Gmail.py
index 2e23e62..f85f306 100644
--- a/offlineimap/repository/Gmail.py
+++ b/offlineimap/repository/Gmail.py
@@ -16,6 +16,7 @@
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
from offlineimap.repository.IMAP import IMAPRepository
+from offlineimap.folder.Gmail import MappedGmailFolder
from offlineimap import folder, OfflineImapError
class GmailRepository(IMAPRepository):
@@ -72,3 +73,7 @@ class GmailRepository(IMAPRepository):
def getspamfolder(self):
#: Gmail also deletes messages upon EXPUNGE in the Spam folder
return self.getconf('spamfolder','[Gmail]/Spam')
+
+class MappedGmailRepository(GmailRepository):
+ def getfoldertype(self):
+ return MappedGmailFolder
diff --git a/offlineimap/repository/__init__.py b/offlineimap/repository/__init__.py
index 0fbbc13..4b9ded4 100644
--- a/offlineimap/repository/__init__.py
+++ b/offlineimap/repository/__init__.py
@@ -23,7 +23,7 @@ except ImportError: #python2
from ConfigParser import NoSectionError
from offlineimap.repository.IMAP import IMAPRepository, MappedIMAPRepository
-from offlineimap.repository.Gmail import GmailRepository
+from offlineimap.repository.Gmail import GmailRepository, MappedGmailRepository
from offlineimap.repository.Maildir import MaildirRepository
from offlineimap.repository.GmailMaildir import GmailMaildirRepository
from offlineimap.repository.LocalStatus import LocalStatusRepository
@@ -49,6 +49,7 @@ class Repository(object):
elif reqtype == 'local':
name = account.getconf('localrepository')
typemap = {'IMAP': MappedIMAPRepository,
+ 'Gmail': MappedGmailRepository,
'Maildir': MaildirRepository,
'GmailMaildir': GmailMaildirRepository}
--
2.3.5
More information about the OfflineIMAP-project
mailing list