diff --git a/Changelog.md b/Changelog.md index c0dccf4..5ebdc7a 100644 --- a/Changelog.md +++ b/Changelog.md @@ -15,6 +15,58 @@ Note to mainainers: * The following excerpt is only usefull when rendered in the website. {:toc} +### OfflineIMAP v7.2.2 (2018-12-22) + +#### Notes + +With this release offlineimap can renew the token for OAUTH2. There is better +integration for ArchLinux and OSX. SSL configuration options are more +consistent. + +There are bug fixes about maxage and GSSAPI. + +The imaplib2 library looks discontinued. I wonder we'll have no other choice +than maintaining our own fork. + +This release was tested by: + +- Nicolas Sebrecht + + +#### Authors + +- Nicolas Sebrecht (5) +- Philippe Loctaux (4) +- Benedikt Heine (2) +- Carnë Draug (2) +- Frode Aannevik (1) +- Robbie Harwood (1) + + +#### Features + +- 2890dec Added ssl certfile on osx for openssl pacakge on homebrew. [Philippe Loctaux] +- 761e10e Add Archlinux to list of supported distros. [Philippe Loctaux] + +#### Fixes + +- 8692799 Fix expired oauth2_access_token. [Frode Aannevik] +- 096aa07 Handle empty token with complete GSSAPI context. [Robbie Harwood] +- a51064e maxage: always compute the remote cache list for min_uid. [Nicolas Sebrecht] +- 698ec64 offlineimap.conf: minor fixes. [Nicolas Sebrecht] +- af3a35a offlineimap/utilis/distro.py: indentation fix. [Philippe Loctaux] +- d3ba837 Fix typo in exception message. [Benedikt Heine] +- c9005cd Check if username is provided before trying plain authentication.. [Carnë Draug] + +#### Changes + +- 5f9474e Print username instead of accountname when asking for password. [Carnë Draug] +- ce9a198 Chain tls_level and ssl_version only if ssl is enabled. [Benedikt Heine] +- 6ef5937 docs/website-doc.sh: minor improvements in comments of versions.yml. [Nicolas Sebrecht] +- 4544bb1 contrib/release.py: minor UI improvement. [Nicolas Sebrecht] +- d930125 fix dates in copyright lines. [Nicolas Sebrecht] + + ### OfflineIMAP v7.2.1 (2018-06-16) #### Notes diff --git a/offlineimap.conf b/offlineimap.conf index e866f09..e24a9a3 100644 --- a/offlineimap.conf +++ b/offlineimap.conf @@ -589,20 +589,19 @@ localfolders = ~/Test # This option stands in the [Repository LocalExample] section. # -# This option is similar to "utime_from_header" and could be use as a +# This option is similar to "utime_from_header" and could be used as a # complementary feature to keep track of a message date. This option only # makes sense for the Maildir type. # # By default each message is stored in a file which prefix is the fetch # timestamp and an order rank such as "1446590057_0". In a multithreading # environment message are fetched in a random order, then you can't trust -# the file name to sort your boxes. +# the filename to sort your boxes. # -# If set to "yes" the file name prefix if build on the message "Date" header +# If set to "yes" the filename prefix is built from the message "Date" header # (which should be present) or the "Received-date" if "Date" is not # found. If neither "Received-date" nor "Date" is found, the current system -# date is used. Now you can quickly sort your messages using their file -# names. +# date is used. Now you can quickly sort your messages using their filenames. # # Used in combination with "utime_from_header" all your message would be in # order with the correct mtime attribute. diff --git a/offlineimap/__init__.py b/offlineimap/__init__.py index 20a905a..c96a52c 100644 --- a/offlineimap/__init__.py +++ b/offlineimap/__init__.py @@ -2,7 +2,7 @@ __all__ = ['OfflineImap'] __productname__ = 'OfflineIMAP' # Expecting trailing "-rcN" or "" for stable releases. -__version__ = "7.2.1" +__version__ = "7.2.2" __copyright__ = "Copyright 2002-2018 John Goerzen & contributors" __author__ = "John Goerzen" __author_email__= "offlineimap-project@lists.alioth.debian.org" diff --git a/offlineimap/accounts.py b/offlineimap/accounts.py index 6418a8c..4aca7c4 100644 --- a/offlineimap/accounts.py +++ b/offlineimap/accounts.py @@ -511,6 +511,11 @@ def syncfolder(account, remotefolder, quick): uids = remotefolder.getmessageuidlist() localfolder.dropmessagelistcache() if len(uids) > 0: + # Reload the remote message list from min_uid. This avoid issues for + # old messages, which has been added from local on any previous run + # (IOW, message is older than maxage _and_ has high enough UID). + remotefolder.dropmessagelistcache() + remotefolder.cachemessagelist(min_uid=min(uids)) localfolder.cachemessagelist(min_uid=min(uids)) else: # Remote folder UIDs list is empty for the given range. We still @@ -523,6 +528,7 @@ def syncfolder(account, remotefolder, quick): uids = [uid for uid in uids if uid > 0] if len(uids) > 0: # Update the remote cache list for this new min(uids). + remotefolder.dropmessagelistcache() remotefolder.cachemessagelist(min_uid=min(uids)) def cachemessagelists_startdate(new, partial, date): diff --git a/offlineimap/imapserver.py b/offlineimap/imapserver.py index a412b7d..600ce65 100644 --- a/offlineimap/imapserver.py +++ b/offlineimap/imapserver.py @@ -15,6 +15,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +import datetime import hmac import socket import json @@ -111,6 +112,7 @@ class IMAPServer(object): self.oauth2_client_id = repos.getoauth2_client_id() self.oauth2_client_secret = repos.getoauth2_client_secret() self.oauth2_request_url = repos.getoauth2_request_url() + self.oauth2_access_token_expires_at = None self.delim = None self.root = None @@ -219,6 +221,12 @@ class IMAPServer(object): return retval def __xoauth2handler(self, response): + now = datetime.datetime.now() + if self.oauth2_access_token_expires_at \ + and self.oauth2_access_token_expires_at < now: + self.oauth2_access_token = None + self.ui.debug('imap', 'xoauth2handler: oauth2_access_token expired') + if self.oauth2_access_token is None: if self.oauth2_request_url is None: raise OfflineImapError("No remote oauth2_request_url for " @@ -256,9 +264,13 @@ class IMAPServer(object): raise OfflineImapError("xoauth2handler got: %s"% resp, OfflineImapError.ERROR.REPO) self.oauth2_access_token = resp['access_token'] + if u'expires_in' in resp: + self.oauth2_access_token_expires_at = now + datetime.timedelta( + seconds=resp['expires_in']/2 + ) - self.ui.debug('imap', 'xoauth2handler: access_token "%s"'% - self.oauth2_access_token) + self.ui.debug('imap', 'xoauth2handler: access_token "%s expires %s"'% ( + self.oauth2_access_token, self.oauth2_access_token_expires_at)) auth_string = 'user=%s\1auth=Bearer %s\1\1'% ( self.username, self.oauth2_access_token) #auth_string = base64.b64encode(auth_string) @@ -280,6 +292,13 @@ class IMAPServer(object): if not self.gss_vc.complete: response = self.gss_vc.step(token) return response if response else "" + elif token is None: + # uh... context is complete, so there's no negotiation we can + # do. But we also don't have a token, so we can't send any + # kind of response. Empirically, some (but not all) servers + # seem to put us in this state, and seem fine with getting no + # GSSAPI content in response, so give it to them. + return "" # Don't bother checking qop because we're over a TLS channel # already. But hey, if some server started encrypting tomorrow,