Complete.Org: Mailing Lists: Archives: offlineimap: September 2007:
Re: Assorted patches
Home

Re: Assorted patches

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: offlineimap@xxxxxxxxxxxx
Subject: Re: Assorted patches
From: Daniel Jacobowitz <drow@xxxxxxxxx>
Date: Sun, 30 Sep 2007 15:46:20 -0400

On Sun, Sep 30, 2007 at 01:54:56PM -0400, Daniel Jacobowitz wrote:
> -- Binary/unsupported file stripped by Ecartis --
> -- Type: text/x-diff

Oh thank you Ecartis.

diff -rN -u old-offlineimap/offlineimap/accounts.py 
new-offlineimap/offlineimap/accounts.py
--- old-offlineimap/offlineimap/accounts.py     2007-09-30 13:45:08.000000000 
-0400
+++ new-offlineimap/offlineimap/accounts.py     2007-09-30 13:45:08.000000000 
-0400
@@ -45,6 +45,7 @@
         self.localeval = config.getlocaleval()
         self.ui = UIBase.getglobalui()
         self.refreshperiod = self.getconffloat('autorefresh', 0.0)
+        self.quicknum = 0
         if self.refreshperiod == 0.0:
             self.refreshperiod = None
 
@@ -125,6 +126,20 @@
     def sync(self):
         # We don't need an account lock because syncitall() goes through
         # each account once, then waits for all to finish.
+
+        quickconfig = self.getconfint('quick', 0)
+        if quickconfig < 0:
+            quick = True
+        elif quickconfig > 0:
+            if self.quicknum == 0 or self.quicknum > quickconfig:
+                self.quicknum = 1
+                quick = False
+            else:
+                self.quicknum = self.quicknum + 1
+                quick = True
+        else:
+            quick = False
+
         try:
             remoterepos = self.remoterepos
             localrepos = self.localrepos
@@ -140,7 +155,7 @@
                     name = "Folder sync %s[%s]" % \
                     (self.name, remotefolder.getvisiblename()),
                     args = (self.name, remoterepos, remotefolder, localrepos,
-                            statusrepos))
+                            statusrepos, quick))
                 thread.setDaemon(1)
                 thread.start()
                 folderthreads.append(thread)
@@ -157,7 +172,7 @@
     pass
 
 def syncfolder(accountname, remoterepos, remotefolder, localrepos,
-               statusrepos):
+               statusrepos, quick):
     global mailboxes
     ui = UIBase.getglobalui()
     ui.registerthread(accountname)
@@ -167,12 +182,6 @@
                             replace(remoterepos.getsep(), localrepos.getsep()))
     # Write the mailboxes
     mbnames.add(accountname, localfolder.getvisiblename())
-    # Load local folder
-    ui.syncingfolder(remoterepos, remotefolder, localrepos, localfolder)
-    ui.loadmessagelist(localrepos, localfolder)
-    localfolder.cachemessagelist()
-    ui.messagelistloaded(localrepos, localfolder, 
len(localfolder.getmessagelist().keys()))
-
 
     # Load status folder.
     statusfolder = statusrepos.getfolder(remotefolder.getvisiblename().\
@@ -185,6 +194,19 @@
         
     statusfolder.cachemessagelist()
 
+    if quick:
+        if not localfolder.quickchanged(statusfolder) \
+               and not remotefolder.quickchanged(statusfolder):
+            ui.skippingfolder(remotefolder)
+            localrepos.restore_atime()
+            return
+
+    # Load local folder
+    ui.syncingfolder(remoterepos, remotefolder, localrepos, localfolder)
+    ui.loadmessagelist(localrepos, localfolder)
+    localfolder.cachemessagelist()
+    ui.messagelistloaded(localrepos, localfolder, 
len(localfolder.getmessagelist().keys()))
+
     # If either the local or the status folder has messages and there is a UID
     # validity problem, warn and abort.  If there are no messages, UW IMAPd
     # loses UIDVALIDITY.  But we don't really need it if both local folders are
diff -rN -u old-offlineimap/offlineimap/folder/IMAP.py 
new-offlineimap/offlineimap/folder/IMAP.py
--- old-offlineimap/offlineimap/folder/IMAP.py  2007-09-30 13:45:08.000000000 
-0400
+++ new-offlineimap/offlineimap/folder/IMAP.py  2007-09-30 13:45:08.000000000 
-0400
@@ -41,6 +41,16 @@
         self.randomgenerator = random.Random()
         BaseFolder.__init__(self)
 
+    def selectro(self, imapobj):
+        """Select this folder when we do not need write access.
+        Prefer SELECT to EXAMINE if we can, since some servers
+        (Courier) do not stabilize UID validity until the folder is
+        selected."""
+        try:
+            imapobj.select(self.getfullname())
+        except imapobj.readonly:
+            imapobj.select(self.getfullname(), readonly = 1)
+
     def getaccountname(self):
         return self.accountname
 
@@ -60,11 +70,52 @@
         imapobj = self.imapserver.acquireconnection()
         try:
             # Primes untagged_responses
-            imapobj.select(self.getfullname(), readonly = 1)
+            self.selectro(imapobj)
             return long(imapobj.untagged_responses['UIDVALIDITY'][0])
         finally:
             self.imapserver.releaseconnection(imapobj)
     
+    def quickchanged(self, statusfolder):
+        # An IMAP folder has definitely changed if the number of
+        # messages or the UID of the last message have changed.  Otherwise
+        # only flag changes could have occurred.
+        imapobj = self.imapserver.acquireconnection()
+        try:
+            # Primes untagged_responses
+            imapobj.select(self.getfullname(), readonly = 1, force = 1)
+            try:
+                # Some mail servers do not return an EXISTS response if
+                # the folder is empty.
+                maxmsgid = long(imapobj.untagged_responses['EXISTS'][0])
+            except KeyError:
+                return True
+
+            # Different number of messages than last time?
+            if maxmsgid != len(statusfolder.getmessagelist()):
+                return True
+
+            if maxmsgid < 1:
+                # No messages; return
+                return False
+
+            # Now, get the UID for the last message.
+            response = imapobj.fetch('%d' % maxmsgid, '(UID)')[1]
+        finally:
+            self.imapserver.releaseconnection(imapobj)
+
+        # Discard the message number.
+        messagestr = string.split(response[0], maxsplit = 1)[1]
+        options = imaputil.flags2hash(messagestr)
+        if not options.has_key('UID'):
+            return True
+        uid = long(options['UID'])
+        saveduids = statusfolder.getmessagelist().keys()
+        saveduids.sort()
+        if uid != saveduids[-1]:
+            return True
+
+        return False
+
     def cachemessagelist(self):
         imapobj = self.imapserver.acquireconnection()
         self.messagelist = {}
diff -rN -u old-offlineimap/offlineimap/folder/Maildir.py 
new-offlineimap/offlineimap/folder/Maildir.py
--- old-offlineimap/offlineimap/folder/Maildir.py       2007-09-30 
13:45:08.000000000 -0400
+++ new-offlineimap/offlineimap/folder/Maildir.py       2007-09-30 
13:45:08.000000000 -0400
@@ -22,7 +22,6 @@
 from threading import Lock
 import os.path, os, re, time, socket, md5
 
-foldermatchre = re.compile(',FMD5=([0-9a-f]{32})')
 uidmatchre = re.compile(',U=(\d+)')
 flagmatchre = re.compile(':.*2,([A-Z]+)')
 
@@ -78,16 +77,16 @@
         files = []
         nouidcounter = -1               # Messages without UIDs get
                                         # negative UID numbers.
+        foldermd5 = md5.new(self.getvisiblename()).hexdigest()
+        folderstr = ',FMD5=' + foldermd5
         for dirannex in ['new', 'cur']:
             fulldirname = os.path.join(self.getfullname(), dirannex)
             files.extend([os.path.join(fulldirname, filename) for
                           filename in os.listdir(fulldirname)])
         for file in files:
             messagename = os.path.basename(file)
-            foldermatch = foldermatchre.search(messagename)
-            if (not foldermatch) or \
-               md5.new(self.getvisiblename()).hexdigest() \
-               != foldermatch.group(1):
+            foldermatch = messagename.find(folderstr) != -1
+            if not foldermatch:
                 # If there is no folder MD5 specified, or if it mismatches,
                 # assume it is a foreign (new) message and generate a
                 # negative uid for it
@@ -111,8 +110,21 @@
                            'filename': file}
         return retval
 
+    def quickchanged(self, statusfolder):
+        self.cachemessagelist()
+        savedmessages = statusfolder.getmessagelist()
+        if len(self.messagelist) != len(savedmessages):
+            return True
+        for uid in self.messagelist.keys():
+            if uid not in savedmessages:
+                return True
+            if self.messagelist[uid]['flags'] != savedmessages[uid]['flags']:
+                return True
+        return False
+
     def cachemessagelist(self):
-        self.messagelist = self._scanfolder()
+        if self.messagelist is None:
+            self.messagelist = self._scanfolder()
             
     def getmessagelist(self):
         return self.messagelist
diff -rN -u old-offlineimap/offlineimap/init.py 
new-offlineimap/offlineimap/init.py
--- old-offlineimap/offlineimap/init.py 2007-09-30 13:45:08.000000000 -0400
+++ new-offlineimap/offlineimap/init.py 2007-09-30 13:45:08.000000000 -0400
@@ -53,7 +53,7 @@
         sys.stdout.write(version.getcmdhelp() + "\n")
         sys.exit(0)
 
-    for optlist in getopt(sys.argv[1:], 'P:1oa:c:d:l:u:h')[0]:
+    for optlist in getopt(sys.argv[1:], 'P:1oqa:c:d:l:u:h')[0]:
         options[optlist[0]] = optlist[1]
 
     if options.has_key('-h'):
@@ -100,6 +100,10 @@
         for section in accounts.getaccountlist(config):
             config.remove_option('Account ' + section, "autorefresh")
 
+    if options.has_key('-q'):
+        for section in accounts.getaccountlist(config):
+            config.set('Account ' + section, "quick", '-1')
+
     lock(config, ui)
 
     try:
diff -rN -u old-offlineimap/offlineimap/ui/Blinkenlights.py 
new-offlineimap/offlineimap/ui/Blinkenlights.py
--- old-offlineimap/offlineimap/ui/Blinkenlights.py     2007-09-30 
13:45:08.000000000 -0400
+++ new-offlineimap/offlineimap/ui/Blinkenlights.py     2007-09-30 
13:45:08.000000000 -0400
@@ -42,6 +42,10 @@
         s.gettf().setcolor('cyan')
         s.__class__.__bases__[-1].syncingfolder(s, srcrepos, srcfolder, 
destrepos, destfolder)
 
+    def skippingfolder(s, folder):
+        s.gettf().setcolor('cyan')
+        s.__class__.__bases__[-1].skippingfolder(s, folder)
+
     def loadmessagelist(s, repos, folder):
         s.gettf().setcolor('green')
         s._msg("Scanning folder [%s/%s]" % (s.getnicename(repos),
@@ -71,6 +75,13 @@
         s.gettf().setcolor('pink')
         s.__class__.__bases__[-1].deletingflags(s, uidlist, flags, destlist)
 
+    def warn(s, msg, minor = 0):
+        if minor:
+            s.gettf().setcolor('pink')
+        else:
+            s.gettf().setcolor('red')
+        s.__class__.__bases__[-1].warn(s, msg, minor)
+
     def init_banner(s):
         s.availablethreadframes = {}
         s.threadframes = {}
diff -rN -u old-offlineimap/offlineimap/ui/Curses.py 
new-offlineimap/offlineimap/ui/Curses.py
--- old-offlineimap/offlineimap/ui/Curses.py    2007-09-30 13:45:08.000000000 
-0400
+++ new-offlineimap/offlineimap/ui/Curses.py    2007-09-30 13:45:08.000000000 
-0400
@@ -509,6 +509,8 @@
                 return
             if color:
                 s.gettf().setcolor(color)
+            elif s.gettf().getcolor() == 'black':
+                s.gettf().setcolor('gray')
             s._addline(msg, s.gettf().getcolorpair())
             s.logwindow.refresh()
         finally:
diff -rN -u old-offlineimap/offlineimap/ui/UIBase.py 
new-offlineimap/offlineimap/ui/UIBase.py
--- old-offlineimap/offlineimap/ui/UIBase.py    2007-09-30 13:45:08.000000000 
-0400
+++ new-offlineimap/offlineimap/ui/UIBase.py    2007-09-30 13:45:08.000000000 
-0400
@@ -208,6 +208,11 @@
                                              s.getnicename(srcrepos),
                                              s.getnicename(destrepos)))
 
+    def skippingfolder(s, folder):
+        """Called when a folder sync operation is started."""
+        if s.verbose >= 0:
+            s._msg("Skipping %s (not changed)" % folder.getname())
+
     def validityproblem(s, folder):
         s.warn("UID validity problem for folder %s (repo %s) (saved %d; got 
%d); skipping it" % \
                (folder.getname(), folder.getrepository().getname(),
diff -rN -u old-offlineimap/offlineimap/version.py 
new-offlineimap/offlineimap/version.py
--- old-offlineimap/offlineimap/version.py      2007-09-30 13:45:08.000000000 
-0400
+++ new-offlineimap/offlineimap/version.py      2007-09-30 13:45:08.000000000 
-0400
@@ -43,7 +43,7 @@
     return """
        offlineimap [ -1 ] [ -P profiledir ] [ -a accountlist ]  [
        -c configfile  ] [ -d debugtype[,debugtype...]  ] [ -o ] [
-       -u interface ]
+       -u interface ] [ -q ]
 
        offlineimap -h | --help
 
@@ -97,6 +97,9 @@
        -o     Run  only once, ignoring any autorefresh setting in
               the config file.
 
+       -q     Run  only quick synchronizations.   Ignore any flag
+              updates on IMAP servers.
+
        -h, --help
               Show summary of options.
 
diff -rN -u old-offlineimap/offlineimap.conf new-offlineimap/offlineimap.conf
--- old-offlineimap/offlineimap.conf    2007-09-30 13:45:08.000000000 -0400
+++ new-offlineimap/offlineimap.conf    2007-09-30 13:45:08.000000000 -0400
@@ -154,6 +154,16 @@
 
 # autorefresh = 5
 
+# You can tell offlineimap to do a number of quicker synchronizations
+# between full updates.  A quick synchronization only synchronizes
+# if a Maildir folder has changed, or if an IMAP folder has received
+# new messages or had messages deleted.  It does not update if the
+# only changes were to IMAP flags.  Specify 0 to never do quick updates,
+# -1 to always do quick updates, or a positive integer to do that many
+# quick updates between each full synchronization (requires autorefresh).
+
+# quick = 10
+
 [Repository LocalExample]
 
 # This is one of the two repositories that you'll work with given the
diff -rN -u old-offlineimap/offlineimap.sgml new-offlineimap/offlineimap.sgml
--- old-offlineimap/offlineimap.sgml    2007-09-30 13:45:08.000000000 -0400
+++ new-offlineimap/offlineimap.sgml    2007-09-30 13:45:08.000000000 -0400
@@ -389,6 +389,11 @@
              file.</para>
            </listitem>
          </varlistentry>
+         <varlistentry><term>-q</term>
+           <listitem><para>Run only quick synchronizations.   Ignore any flag
+              updates on IMAP servers.</para>
+           </listitem>
+         </varlistentry>
          <varlistentry><term>-h</term> <term>--help</term>
            <listitem><para>Show summary of options.</para></listitem>
          </varlistentry>


-- 
Daniel Jacobowitz
CodeSourcery



[Prev in Thread] Current Thread [Next in Thread]