]> code.delx.au - offlineimap/commitdiff
Merge branch 'master' of http://git.complete.org/offlineimap master
authorJames Bunton <James Bunton jamesbunton@fastmail.fm>
Mon, 13 Jul 2009 12:29:43 +0000 (22:29 +1000)
committerJames Bunton <James Bunton jamesbunton@fastmail.fm>
Mon, 13 Jul 2009 12:29:43 +0000 (22:29 +1000)
16 files changed:
.gitignore
Makefile
README [deleted file]
bin/offlineimap
debian/changelog
debian/docs
debian/pyversions
offlineimap.conf
offlineimap.py
offlineimap/accounts.py
offlineimap/folder/Maildir.py
offlineimap/imaplib2.py
offlineimap/imaplibutil.py
offlineimap/imapserver.py
offlineimap/init.py
offlineimap/version.py

index 905ced6d761b176575acade9f931e39aa68ce44a..1b6dcc514a5f8b96ccb6da1c1c5b02e8a34f99df 100644 (file)
@@ -1,4 +1,10 @@
+# Generated files
 *.pyc
+manpage.*
+manual.html
+manual.ps
+offlineimap.1
+# backups
 .*.swp
 .*.swo
 *~
index 3fcf4253494801815c3de2e5ab7079012f683715..3e5e537d15e8bd74be781d35eb85f04967ef3b44 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -31,7 +31,7 @@ clean:
        -rm -f `find . -name ".cache*"`
        -rm -f manpage.links manpage.refs
        -find . -name auth -exec rm -vf {}/password {}/username \;
-       -rm -f manual.html manual.pdf manual.txt offlineimap.1
+       -rm -f manual.html manual.pdf manual.txt manual.ps offlineimap.1
 
 doc: 
        docbook2man offlineimap.sgml
diff --git a/README b/README
deleted file mode 100644 (file)
index 0f35366..0000000
--- a/README
+++ /dev/null
@@ -1,11 +0,0 @@
-OfflineIMAP
-Copyright (C) 2002 - 2006 John Goerzen <jgoerzen@complete.org>
-This software comes with ABSOLUTELY NO WARRANTY; see the file
-COPYING for details.  This is free software, and you are welcome
-to distribute it under the conditions laid out in COPYING.
-
-http://software.complete.org/offlineimap/
-
-Please see manual.txt; the information previously in README has been moved
-there.
-
index 7f877803ec2699dfa6f29089583a44581cd1a97d..94d6ff1c0182e4472c3a50972a8b894330f1d52f 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 # Startup from system-wide installation
-# Copyright (C) 2002 - 2008 John Goerzen
+# Copyright (C) 2002 - 2009 John Goerzen
 # <jgoerzen@complete.org>
 #
 #    This program is free software; you can redistribute it and/or modify
@@ -18,4 +18,4 @@
 #    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
 
 from offlineimap import init
-init.startup('6.0.3')
+init.startup('6.1.1')
index f09617922f0877c7caf111e3860717af4ec61e24..f2eccdd3fd75d8751b703c1921164c6febde896f 100644 (file)
@@ -1,8 +1,47 @@
-offlineimap (6.0.4) UNRELEASED; urgency=low
+offlineimap (6.1.1) unstable; urgency=low
 
-  * FIXME: ensure patch from Jim Prior has had docs for signals
+  * Fix minimum Python version.  Closes: #535481.
+
+ -- John Goerzen <jgoerzen@complete.org>  Thu, 02 Jul 2009 00:03:21 -0500
 
- -- John Goerzen <jgoerzen@complete.org>  Mon, 01 Dec 2008 16:15:20 -0600
+offlineimap (6.1.0) unstable; urgency=low
+
+  * FIXME: ensure patch from Jim Prior has had docs for signals
+  * FEATURE: Applied patch from Jonny Lamb to specify order of syncing.
+    Closes: #502779.
+  * FEATURE: Support pre/post-sync hooks.  Patch from Sylvain FORET.
+    Apply fix for missing imports in this patch; fix from Graham D.
+  * FEATURE: Documented pre/post-sync hooks.  Patch from Sias Mey.
+  * FEATURE: New configuration option to limit folders worked with
+    to the IMAP subscribed folders.  Patch from Sean Finney, modified
+    by John Goerzen.
+  * FEATURE: Support sending OfflineIMAP a signal to force a sync to
+    start.  Patch from Jim Pryor (e1fb9492f)
+  * FEATURE: Support for IMAP IDLE; import newer imaplib.  Patch from
+    James Bunton.  Additional patch from James Bunton to check for IDLE
+    in CAPABILITIES response.  Patch series merged in 9e085565.
+  * FEATURE: Allow keepalive to be overridden by user if imapfolders set.
+    Patch from James Bunton.
+  * FEATURE: Support /etc/netrc in addition to ~/.netrc.  Patch from
+    Jim Pryor.
+  * FEATURE: Sync accounts in order specified.  Patch from Jonny Lamb.
+  * FIX: Apply patch from Eric Dorland to fix autorefresh with Kerberos.
+  * FIX: Set gssapi to false on Kerberos error.  Patch from Christoph
+    Höger.
+  * COSMETIC: Make Ctrl-C cleaner.  Patch from Jim Pryor.
+  * COSMETIC: Fix typoes in example config file.
+    Patch from Alexey Mahotkin.
+  * COMPAT: Apply patch from Michael Witten to remove use of a private
+    attribute in imaplibutil.py (5fe379f66)
+  * COMPAT: Use md5 from haslib if available.  md5 module deprecated
+    since Python 2.5.  Patch from Loui Chang.  Fix to Chang's patch from
+    Paul Hinze.
+  * COMPAT: Apply Darwin support patch from Vincent Beffara.  Fixes
+    software.complete.org #20.  Commit 10c2b6fbaa.
+  * MISC: Better make clean, .gitignore files.  Patches from 
+    Nicolas Sebrecht.    
+
+ -- John Goerzen <jgoerzen@complete.org>  Wed, 01 Jul 2009 20:49:58 -0500
 
 offlineimap (6.0.3) unstable; urgency=low
 
index 4efe72740d60dcacdcb14e9be61cc3f78ffe218f..ed7a5783544909db55b48c9d33407f8a28bc6f96 100644 (file)
@@ -1,6 +1,5 @@
 manual.txt
 manual.pdf
 manual.html
-README
 UPGRADING
 FAQ.html
index 57a7586e4b339553ca15ce2f76600a89f5c6d01d..b3dc41ebcd3c727b1db7817a87949ee7e1adcf51 100644 (file)
@@ -1 +1 @@
-2.3-
+2.5-
index 48f8f13e21483e19d83f6e19c563cd826f222505..b9aaecbab1cd706d90c3b19c28b6ae13281fe27c 100644 (file)
@@ -74,7 +74,7 @@ ui = Curses.Blinkenlights, TTY.TTYUI,
 # 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.
+# OfflineIMAP from propagating those changes to the IMAP server.
 
 ignore-readonly = no
 
@@ -166,7 +166,7 @@ remoterepository = RemoteExample
 
 ########## Advanced settings
 
-# You can have offlineimap continue running indefinately, automatically
+# You can have offlineimap continue running indefinitely, automatically
 # syncing your mail periodically.  If you want that, specify how
 # frequently to do that (in minutes) here.  You can also specify
 # fractional minutes (ie, 3.25).
@@ -462,7 +462,7 @@ remoteuser = username@gmail.com
 # continue to exist in the '[Gmail]/All Mail' folder.  If `realdelete`
 # is set to `True`, then deleted messages will really be deleted
 # during `offlineimap` sync, by moving them to the '[Gmail]/Trash'
-# folder.  BEWARE: this will deleted a messages from *all folders* it
+# folder.  BEWARE: this will delete a messages from *all folders* it
 # belongs to!
 #
 # See http://mail.google.com/support/bin/answer.py?answer=77657&topic=12815
index 1247bded21d9ea6dcda7c1507333206a1a0bb06b..c813c7fa4736b5571d05e26e7bcc272fc0e9b825 100755 (executable)
@@ -18,4 +18,4 @@
 #    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
 from offlineimap import init
-init.startup('6.0.3')
+init.startup('6.1.0')
index 7a20c37908168f59c19c8ee4959b2a102c2a9365..a4933960d817dbad4c813130af78c9ba874f1952 100644 (file)
@@ -37,9 +37,9 @@ class SigListener(Queue):
                     # folders haven't yet been added, or this account is once-only; drop signal
                     return
                 elif self.folders:
-                    for folder in self.folders:
+                    for foldernr in range(len(self.folders)):
                         # requeue folder
-                        self.folders[folder] = True
+                        self.folders[foldernr][1] = True
                     self.quick = False
                     return
                 # else folders have already been cleared, put signal...
@@ -49,22 +49,22 @@ class SigListener(Queue):
     def addfolders(self, remotefolders, autorefreshes, quick):
         self.folderlock.acquire()
         try:
-            self.folders = {}
+            self.folders = []
             self.quick = quick
             self.autorefreshes = autorefreshes
             for folder in remotefolders:
                 # new folders are queued
-                self.folders[folder] = True
+                self.folders.append([folder, True])
         finally:
             self.folderlock.release()
     def clearfolders(self):
         self.folderlock.acquire()
         try:
-            for folder in self.folders:
-                if self.folders[folder]:
+            for folder, queued in self.folders:
+                if queued:
                     # some folders still in queue
                     return False
-            self.folders.clear()
+            self.folders[:] = []
             return True
         finally:
             self.folderlock.release()
@@ -74,10 +74,10 @@ class SigListener(Queue):
             dirty = True
             while dirty:
                 dirty = False
-                for folder in self.folders:
-                    if self.folders[folder]:
+                for foldernr, (folder, queued) in enumerate(self.folders):
+                    if queued:
                         # mark folder as no longer queued
-                        self.folders[folder] = False
+                        self.folders[foldernr][1] = False
                         dirty = True
                         quick = self.quick
                         self.folderlock.release()
@@ -109,6 +109,7 @@ class Account(CustomConfig.ConfigHelperMixin):
         self.localeval = config.getlocaleval()
         self.ui = UIBase.getglobalui()
         self.refreshperiod = self.getconffloat('autorefresh', 0.0)
+        self.quickrefreshcount = self.getconfint('quick', 0)
         self.quicknum = 0
         if self.refreshperiod == 0.0:
             self.refreshperiod = None
@@ -144,8 +145,11 @@ class Account(CustomConfig.ConfigHelperMixin):
 
         for item in kaobjs:
             item.startkeepalive()
-        
-        refreshperiod = int(self.refreshperiod * 60)
+
+        sleeptime = int(self.refreshperiod * 60)
+        if (self.quickrefreshcount > 0):
+            sleeptime = int(sleeptime / self.quickrefreshcount)
+
 #         try:
 #             sleepresult = siglistener.get_nowait()
 #             # retrieved signal before sleep started
@@ -153,8 +157,8 @@ class Account(CustomConfig.ConfigHelperMixin):
 #                 # catching signal 1 here means folders were cleared before signal was posted
 #                 pass
 #         except Empty:
-#             sleepresult = self.ui.sleep(refreshperiod, siglistener)
-        sleepresult = self.ui.sleep(refreshperiod, siglistener)
+#             sleepresult = self.ui.sleep(sleeptime, siglistener)
+        sleepresult = self.ui.sleep(sleeptime, siglistener)
         if sleepresult == 1:
             self.quicknum = 0
 
index 937500f0b7e9f28ddf5ad33bbc36565cc68eec11..811d759a48ab3ea28680317e7d5f13de623f6b9e 100644 (file)
@@ -88,8 +88,8 @@ class MaildirFolder(BaseFolder):
         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)])
+            files.extend(os.path.join(fulldirname, filename) for
+                         filename in os.listdir(fulldirname))
         for file in files:
             messagename = os.path.basename(file)
             foldermatch = messagename.find(folderstr) != -1
@@ -199,9 +199,8 @@ class MaildirFolder(BaseFolder):
         ui.debug('maildir', 'savemessage: moving from %s to %s' % \
                  (tmpmessagename, messagename))
         if tmpmessagename != messagename: # then rename it
-            os.link(os.path.join(tmpdir, tmpmessagename),
+            os.rename(os.path.join(tmpdir, tmpmessagename),
                     os.path.join(tmpdir, messagename))
-            os.unlink(os.path.join(tmpdir, tmpmessagename))
 
         if self.dofsync:
             try:
index 24267546a154239274ac67ed3e283257bc6684c9..2f7919b02cdc621a39f91841fdcc1d0ea68c9457 100644 (file)
@@ -1,4 +1,4 @@
-#!/usr/bin/env python2.5
+#!/usr/bin/env python
 
 """Threaded IMAP4 client.
 
@@ -17,9 +17,9 @@ Public functions: Internaldate2Time
 __all__ = ("IMAP4", "IMAP4_SSL", "IMAP4_stream",
            "Internaldate2Time", "ParseFlags", "Time2Internaldate")
 
-__version__ = "2.6"
+__version__ = "2.11"
 __release__ = "2"
-__revision__ = "6"
+__revision__ = "11"
 __credits__ = """
 Authentication code contributed by Donn Cave <donn@u.washington.edu> June 1998.
 String method conversion by ESR, February 2001.
@@ -29,11 +29,11 @@ GET/SETQUOTA contributed by Andreas Zeidler <az@kreativkombinat.de> June 2002.
 PROXYAUTH contributed by Rick Holbert <holbert.13@osu.edu> November 2002.
 IDLE via threads suggested by Philippe Normand <phil@respyre.org> January 2005.
 GET/SETANNOTATION contributed by Tomas Lindroos <skitta@abo.fi> June 2005.
-New socket open code from http://www.python.org/doc/lib/socket-example.html."""
+COMPRESS/DEFLATE contributed by Bron Gondwana <brong@brong.net> May 2009."""
 __author__ = "Piers Lauder <piers@janeelix.com>"
-# Source URL: http://www.cs.usyd.edu.au/~piers/python/imaplib2
+__URL__ = "http://janeelix.com/piers/python/imaplib2"
 
-import binascii, os, Queue, random, re, select, socket, sys, time, threading
+import binascii, os, Queue, random, re, select, socket, sys, time, threading, zlib
 
 select_module = select
 
@@ -62,6 +62,7 @@ Commands = {
         'CAPABILITY':   ((NONAUTH, AUTH, SELECTED),   True),
         'CHECK':        ((SELECTED,),                 True),
         'CLOSE':        ((SELECTED,),                 False),
+        'COMPRESS':     ((AUTH,),                     False),
         'COPY':         ((SELECTED,),                 True),
         'CREATE':       ((AUTH, SELECTED),            True),
         'DELETE':       ((AUTH, SELECTED),            True),
@@ -264,6 +265,9 @@ class IMAP4(object):
         self._accumulated_data = []     # Message data accumulated so far
         self._literal_expected = None   # Message data descriptor
 
+        self.compressor = None          # COMPRESS/DEFLATE if not None
+        self.decompressor = None
+
         # Create unique tag for this session,
         # and compile tagged response matcher.
 
@@ -358,7 +362,8 @@ class IMAP4(object):
 
 
     def open_socket(self):
-        """Open socket choosing first address family available."""
+        """open_socket()
+        Open socket choosing first address family available."""
 
         msg = (-1, 'could not open socket')
         for res in socket.getaddrinfo(self.host, self.port, socket.AF_UNSPEC, socket.SOCK_STREAM):
@@ -379,17 +384,38 @@ class IMAP4(object):
         return s
 
 
+    def start_compressing(self):
+        """start_compressing()
+        Enable deflate compression on the socket (RFC 4978)."""
+
+        # rfc 1951 - pure DEFLATE, so use -15 for both windows
+        self.decompressor = zlib.decompressobj(-15)
+        self.compressor = zlib.compressobj(zlib.Z_DEFAULT_COMPRESSION, zlib.DEFLATED, -15)
+
+
     def read(self, size):
         """data = read(size)
         Read at most 'size' bytes from remote."""
 
-        return self.sock.recv(size)
+        if self.decompressor is None:
+            return self.sock.recv(size)
+
+        if self.decompressor.unconsumed_tail:
+            data = self.decompressor.unconsumed_tail
+        else:
+            data = self.sock.recv(8192)
+
+        return self.decompressor.decompress(data, size)
 
 
     def send(self, data):
         """send(data)
         Send 'data' to remote."""
 
+        if self.compressor is not None:
+            data = self.compressor.compress(data)
+            data += self.compressor.flush(zlib.Z_SYNC_FLUSH)
+
         self.sock.sendall(data)
 
 
@@ -411,6 +437,22 @@ class IMAP4(object):
     #       Utility methods
 
 
+    def enable_compression(self):
+        """enable_compression()
+        Ask the server to start compressing the connection.
+        Should be called from user of this class after instantiation, as in:
+            if 'COMPRESS=DEFLATE' in imapobj.capabilities:
+                imapobj.enable_compression()"""
+
+        try:
+            typ, dat = self._simple_command('COMPRESS', 'DEFLATE')
+            if typ == 'OK':
+                self.start_compressing()
+                if __debug__: self._log(1, 'Enabled COMPRESS=DEFLATE')
+        finally:
+            self.state_change_pending.release()
+
+
     def recent(self, **kw):
         """(typ, [data]) = recent()
         Return most recent 'RECENT' responses if any exist,
@@ -433,7 +475,7 @@ class IMAP4(object):
 
         typ, dat = self._untagged_response(code, [None], code.upper())
         return self._deliver_dat(typ, dat, kw)
-        
+
 
 
 
@@ -647,9 +689,9 @@ class IMAP4(object):
         List mailbox names in directory matching pattern.
         'data' is list of LIST responses.
 
-       NB: for 'pattern':
-       % matches all except separator ( so LIST "" "%" returns names at root)
-       * matches all (so LIST "" "*" returns whole directory tree from root)"""
+        NB: for 'pattern':
+        % matches all except separator ( so LIST "" "%" returns names at root)
+        * matches all (so LIST "" "*" returns whole directory tree from root)"""
 
         name = 'LIST'
         kw['untagged_response'] = name
@@ -813,7 +855,7 @@ class IMAP4(object):
                     self.state = AUTH
                 if __debug__: self._log(1, 'state => AUTH')
                 if typ == 'BAD':
-                    self._deliver_exc(self.error, '%s command error: %s %s' % (name, typ, dat), kw)
+                    self._deliver_exc(self.error, '%s command error: %s %s. Data: %.100s' % (name, typ, dat, mailbox), kw)
                 return self._deliver_dat(typ, dat, kw)
             self.state = SELECTED
             if __debug__: self._log(1, 'state => SELECTED')
@@ -1043,20 +1085,25 @@ class IMAP4(object):
         literal = self.literal
         if literal is not None:
             self.literal = None
-            if isinstance(literal, str):
+            if isinstance(literal, basestring):
                 literator = None
                 data = '%s {%s}' % (data, len(literal))
             else:
                 literator = literal
 
+        if __debug__: self._log(4, 'data=%s' % data)
+
         rqb.data = '%s%s' % (data, CRLF)
-        self.ouq.put(rqb)
 
         if literal is None:
+            self.ouq.put(rqb)
             return rqb
 
+        # Must setup continuation expectancy *before* ouq.put 
         crqb = self._request_push(tag='continuation')
 
+        self.ouq.put(rqb)
+
         while True:
             # Wait for continuation response
 
@@ -1076,6 +1123,10 @@ class IMAP4(object):
             if literal is None:
                 break
 
+            if literator is not None:
+                # Need new request for next continuation response
+                crqb = self._request_push(tag='continuation')
+
             if __debug__: self._log(4, 'write literal size %s' % len(literal))
             crqb.data = '%s%s' % (literal, CRLF)
             self.ouq.put(crqb)
@@ -1083,10 +1134,6 @@ class IMAP4(object):
             if literator is None:
                 break
 
-            self.commands_lock.acquire()
-            self.tagged_commands['continuation'] = crqb
-            self.commands_lock.release()
-
         return rqb
 
 
@@ -1098,7 +1145,7 @@ class IMAP4(object):
         self._check_bye()
         if typ == 'BAD':
             if __debug__: self._print_log()
-            raise self.error('%s command error: %s %s' % (rqb.name, typ, dat))
+            raise self.error('%s command error: %s %s. Data: %.100s' % (rqb.name, typ, dat, rqb.data))
         if 'untagged_response' in kw:
             return self._untagged_response(typ, dat, kw['untagged_response'])
         return typ, dat
@@ -1122,12 +1169,11 @@ class IMAP4(object):
         typ, dat = response
         if typ == 'BAD':
             if __debug__: self._print_log()
-            rqb.abort(self.error, '%s command error: %s %s' % (rqb.name, typ, dat))
+            rqb.abort(self.error, '%s command error: %s %s. Data: %.100s' % (rqb.name, typ, dat, rqb.data))
             return
         if 'untagged_response' in kw:
-            rqb.deliver(self._untagged_response(typ, dat, kw['untagged_response']))
-        else:
-            rqb.deliver(response)
+            response = self._untagged_response(typ, dat, kw['untagged_response'])
+        rqb.deliver(response)
 
 
     def _deliver_dat(self, typ, dat, kw):
@@ -1147,12 +1193,13 @@ class IMAP4(object):
     def _end_idle(self):
 
         irqb = self.idle_rqb
-        if irqb is not None:
-            self.idle_rqb = None
-            self.idle_timeout = None
-            irqb.data = 'DONE%s' % CRLF
-            self.ouq.put(irqb)
-            if __debug__: self._log(2, 'server IDLE finished')
+        if irqb is None:
+            return
+        self.idle_rqb = None
+        self.idle_timeout = None
+        irqb.data = 'DONE%s' % CRLF
+        self.ouq.put(irqb)
+        if __debug__: self._log(2, 'server IDLE finished')
 
 
     def _match(self, cre, s):
@@ -1337,7 +1384,7 @@ class IMAP4(object):
 
         threading.currentThread().setName('hdlr')
 
-       time.sleep(0.1) # Don't start handling before main thread ready
+        time.sleep(0.1)   # Don't start handling before main thread ready
 
         if __debug__: self._log(1, 'starting')
 
@@ -1366,7 +1413,7 @@ class IMAP4(object):
             if line is None:
                 break
 
-            if not isinstance(line, str):
+            if not isinstance(line, basestring):
                 typ, val = line
                 break
 
@@ -1664,7 +1711,12 @@ class IMAP4_SSL(IMAP4):
         self.host = host is not None and host or ''
         self.port = port is not None and port or IMAP4_SSL_PORT
         self.sock = self.open_socket()
-        self.sslobj = socket.ssl(self.sock, self.keyfile, self.certfile)
+
+        try:
+                import ssl
+                self.sslobj = ssl.wrap_socket(self.sock, self.keyfile, self.certfile)
+        except ImportError:
+                self.sslobj = socket.ssl(self.sock, self.keyfile, self.certfile)
 
         self.read_fd = self.sock.fileno()
 
@@ -1673,13 +1725,25 @@ class IMAP4_SSL(IMAP4):
         """data = read(size)
         Read at most 'size' bytes from remote."""
 
-        return self.sslobj.read(size)
+        if self.decompressor is None:
+            return self.sslobj.read(size)
+
+        if self.decompressor.unconsumed_tail:
+            data = self.decompressor.unconsumed_tail
+        else:
+            data = self.sslobj.read(8192)
+
+        return self.decompressor.decompress(data, size)
 
 
     def send(self, data):
         """send(data)
         Send 'data' to remote."""
 
+        if self.compressor is not None:
+            data = self.compressor.compress(data)
+            data += self.compressor.flush(zlib.Z_SYNC_FLUSH)
+
         # NB: socket.ssl needs a "sendall" method to match socket objects.
         bytes = len(data)
         while bytes > 0:
@@ -1736,12 +1800,24 @@ class IMAP4_stream(IMAP4):
     def read(self, size):
         """Read 'size' bytes from remote."""
 
-        return os.read(self.read_fd, size)
+        if self.decompressor is None:
+            return os.read(self.read_fd, size)
+
+        if self.decompressor.unconsumed_tail:
+            data = self.decompressor.unconsumed_tail
+        else:
+            data = os.read(self.read_fd, 8192)
+
+        return self.decompressor.decompress(data, size)
 
 
     def send(self, data):
         """Send data to remote."""
 
+        if self.compressor is not None:
+            data = self.compressor.compress(data)
+            data += self.compressor.flush(zlib.Z_SYNC_FLUSH)
+
         self.writefile.write(data)
         self.writefile.flush()
 
@@ -1920,7 +1996,7 @@ if __name__ == '__main__':
     import getopt, getpass
 
     try:
-        optlist, args = getopt.getopt(sys.argv[1:], 'd:l:s:p:')
+        optlist, args = getopt.getopt(sys.argv[1:], 'd:l:s:p:v')
     except getopt.error, val:
         optlist, args = (), ()
 
@@ -1938,6 +2014,9 @@ if __name__ == '__main__':
         elif opt == '-s':
             stream_command = val
             if not args: args = (stream_command,)
+        elif opt == '-v':
+            print __version__
+            sys.exit(0)
 
     if not args: args = ('',)
     if not port: port = (keyfile is not None) and IMAP4_SSL_PORT or IMAP4_PORT
@@ -1947,7 +2026,7 @@ if __name__ == '__main__':
     USER = getpass.getuser()
 
     test_mesg = 'From: %(user)s@localhost%(lf)sSubject: IMAP4 test%(lf)s%(lf)s%(data)s' \
-                       % {'user':USER, 'lf':'\n', 'data':open(__file__).read()}
+                     % {'user':USER, 'lf':'\n', 'data':open(__file__).read()}
     test_seq1 = [
     ('list', ('""', '%')),
     ('create', ('/tmp/imaplib2_test.0',)),
@@ -2028,6 +2107,8 @@ if __name__ == '__main__':
             test_seq1.insert(0, ('login', (USER, PASSWD)))
         M._mesg('PROTOCOL_VERSION = %s' % M.PROTOCOL_VERSION)
         M._mesg('CAPABILITIES = %r' % (M.capabilities,))
+        if 'COMPRESS=DEFLATE' in M.capabilities:
+            M.enable_compression()
 
         for cmd,args in test_seq1:
             run(cmd, args, cb=1)
index 5fdab910e3dd67a58e79785b969a9ec4c96483ba..836c86fff75cec2fc1f93bcde91d04bd07dfe098 100644 (file)
@@ -23,6 +23,9 @@ from offlineimap.imaplib2 import *
 # Import the symbols we need that aren't exported by default
 from offlineimap.imaplib2 import IMAP4_PORT, IMAP4_SSL_PORT, InternalDate, Mon2num
 
+# ssl is new in python 2.6
+if (sys.version_info[0] == 2 and sys.version_info[1] >= 6) or sys.version_info[0] >= 3:
+    import ssl
 
 class IMAP4_Tunnel(IMAP4):
     """IMAP4 client class over a tunnel
index c850e99a01fc3963f8becdecea8dea783bbd004d..d18ed961130c989d3cb5b67f9b8506153b6b3fc9 100644 (file)
@@ -274,6 +274,7 @@ class IMAPServer:
                         try:
                             imapobj.authenticate('GSSAPI', self.gssauth)
                         except imapobj.error, val:
+                            self.gssapi = False
                             UIBase.getglobalui().debug('imap',
                                 'GSSAPI Authentication failed')               
                         else:
@@ -334,6 +335,10 @@ class IMAPServer:
         self.assignedconnections = []
         self.availableconnections = []
         self.lastowner = {}
+        # reset kerberos state
+        self.gss_step = self.GSS_STATE_STEP
+        self.gss_vc = None
+        self.gssapi = False
         self.connectionlock.release()
 
     def keepalive(self, timeout, event):
index 526478c86c91106676ffb5da3c145dcf55901a21..8d888b43d8c0884d80ef22da728be215f065edeb 100644 (file)
@@ -158,7 +158,7 @@ def startup(versionno):
         activeaccounts = activeaccounts.split(",")
         allaccounts = accounts.AccountHashGenerator(config)
 
-        syncaccounts = {}
+        syncaccounts = []
         for account in activeaccounts:
             if account not in allaccounts:
                 if len(allaccounts) == 0:
@@ -168,7 +168,8 @@ def startup(versionno):
                     for name in allaccounts.keys():
                         errormsg += '\n%s'%name
                 ui.terminate(1, errortitle = 'Unknown Account "%s"'%account, errormsg = errormsg)
-            syncaccounts[account] = allaccounts[account]
+            if account not in syncaccounts:
+                syncaccounts.append(account)
 
         server = None
         remoterepos = None
index ddcf9546c1ad0a3f408453bf5cd62eecfad1b1cd..7bc17568dd0cff60cf332552a9881b784d90448e 100644 (file)
@@ -1,11 +1,11 @@
 productname = 'OfflineIMAP'
-versionstr = "6.0.3"
+versionstr = "6.1.1"
 
 versionlist = versionstr.split(".")
 major = versionlist[0]
 minor = versionlist[1]
 patch = versionlist[2]
-copyright = "Copyright (C) 2002 - 2008 John Goerzen"
+copyright = "Copyright (C) 2002 - 2009 John Goerzen"
 author = "John Goerzen"
 author_email = "jgoerzen@complete.org"
 description = "Disconnected Universal IMAP Mail Synchronization/Reader Support"
@@ -18,7 +18,7 @@ COPYING for details.  This is free software, and you are welcome
 to distribute it under the conditions laid out in COPYING."""
 
 homepage = "http://software.complete.org/offlineimap/"
-license = """Copyright (C) 2002 - 2008 John Goerzen <jgoerzen@complete.org>
+license = """Copyright (C) 2002 - 2009 John Goerzen <jgoerzen@complete.org>
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by