Hello community, here is the log from the commit of package offlineimap for openSUSE:Factory checked in at 2017-03-14 10:06:25 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/offlineimap (Old) and /work/SRC/openSUSE:Factory/.offlineimap.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "offlineimap" Tue Mar 14 10:06:25 2017 rev:37 rq:479120 version:7.0.14 Changes: -------- --- /work/SRC/openSUSE:Factory/offlineimap/offlineimap.changes 2017-02-15 10:07:48.784301958 +0100 +++ /work/SRC/openSUSE:Factory/.offlineimap.new/offlineimap.changes 2017-03-14 10:07:16.366211205 +0100 @@ -1,0 +2,8 @@ +Mon Mar 13 17:37:04 UTC 2017 - mimi...@gmail.com + +- update to 7.0.14 +* SQLite: avoid concurrent writes on backend migration. +* Fix ipv6 configuration handling. +* Prevent synchronization of identical folders from multiple threads + +------------------------------------------------------------------- Old: ---- offlineimap-7.0.13.tar.gz New: ---- offlineimap-7.0.14.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ offlineimap.spec ++++++ --- /var/tmp/diff_new_pack.XQjUxN/_old 2017-03-14 10:07:16.926131920 +0100 +++ /var/tmp/diff_new_pack.XQjUxN/_new 2017-03-14 10:07:16.930131354 +0100 @@ -19,7 +19,7 @@ %{!?_userunitdir:%define _userunitdir /usr/lib/systemd/user} Name: offlineimap -Version: 7.0.13 +Version: 7.0.14 Release: 0 Summary: Powerful IMAP/Maildir Synchronization Tool License: GPL-2.0+ ++++++ offlineimap-7.0.13.tar.gz -> offlineimap-7.0.14.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/offlineimap-7.0.13/Changelog.md new/offlineimap-7.0.14/Changelog.md --- old/offlineimap-7.0.13/Changelog.md 2017-01-27 19:49:42.000000000 +0100 +++ new/offlineimap-7.0.14/Changelog.md 2017-03-11 13:22:18.000000000 +0100 @@ -15,6 +15,48 @@ * The following excerpt is only usefull when rendered in the website. {:toc} +### OfflineIMAP v7.0.14 (2017-03-11) + +#### Notes + +Here is a new small fixup release for the v7.0 series. The first v7.0.0 release +is near to 8 months old. This v7.0.14 release is more reliable than v6.7.0.3. +Hence, I'm deprecating the v6.7 series. + +Now, you are all enjoined to migrate to v7.0.14. Migrating back to v6.7 is not +supported so you might like to backup your local maildirs and metadata first. + +We will fully remove the legacy text backend driver in near future. The SQLite +driver proved to be better for both performance and reliability. + +With this release we use imaplib2 v2.57 to support some faulting IMAP servers, +fix a little bug about the backend migration to SQLite and serialize the sync +processes to prevent from issues when both IDLE and autorefresh are enabled. + +Happy sync'ing! + +#### Authors + +- Nicolas Sebrecht (5) +- 927589452 (2) +- Jens Heinrich (1) +- Stéphane Graber (1) + +#### Fixes + +- SQLite: avoid concurrent writes on backend migration. [Nicolas Sebrecht] +- Fix ipv6 configuration handling. [Stéphane Graber] +- Prevent synchronization of identical folders from multiple threads. [Nicolas Sebrecht] + +#### Changes + +- Bump from imaplib2 v2.55 to v2.57. [Nicolas Sebrecht] +- scripts/get-repository.sh: use portable /bin/sh. [Jens Heinrich] +- MAINTAINERS: add new tester. [Nicolas Sebrecht] +- scripts/get-repository.sh: use env to call bash. [mailingli...@927589452.de] + + + ### OfflineIMAP v7.0.13 (2017-01-27) #### Notes diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/offlineimap-7.0.13/MAINTAINERS.rst new/offlineimap-7.0.14/MAINTAINERS.rst --- old/offlineimap-7.0.13/MAINTAINERS.rst 2017-01-27 19:49:42.000000000 +0100 +++ new/offlineimap-7.0.14/MAINTAINERS.rst 2017-03-11 13:22:18.000000000 +0100 @@ -4,53 +4,58 @@ ======== - Abdó Roig-Maranges - - email: abdo.roig at gmail.com - - github: aroig + - email: abdo.roig at gmail.com + - github: aroig - Ben Boeckel - - email: mathstuf at gmail.com - - github: mathstuf + - email: mathstuf at gmail.com + - github: mathstuf + +- Chris Coleman + - email: christocoleman at yahoo.com + - github: chris001 - Darshit Shah - - email: darnir at gmail.com - - github: darnir + - email: darnir at gmail.com + - github: darnir - Eygene Ryabinkin - - email: rea at freebsd.org - - github: konvpalto - - other: FreeBSD maintainer + - email: rea at freebsd.org + - github: konvpalto + - other: FreeBSD maintainer - Igor Almeida - - email: igor.contato at gmail.com - - github: igoralmeida + - email: igor.contato at gmail.com + - github: igoralmeida - Ilias Tsitsimpis - - email: i.tsitsimpis at gmail.com - - github: iliastsi - - other: Debian maintainer + - email: i.tsitsimpis at gmail.com + - github: iliastsi + - other: Debian maintainer - "J" - - email: offlineimap at 927589452.de - - other: FreeBSD user + - email: offlineimap at 927589452.de + - github: 927589452 + - other: FreeBSD user - Łukasz Żarnowiecki - - email: dolohow at outlook.com - - github: dolohow + - email: dolohow at outlook.com + - github: dolohow - Nicolas Sebrecht - - email: nicolas.s-dev at laposte.net - - github: nicolas33 - - system: Linux + - email: nicolas.s-dev at laposte.net + - github: nicolas33 + - system: Linux - Rainer M Krug - - email: Rainer at krugs.de - - github: rkrug - - system: OSX + - email: Rainer at krugs.de + - github: rkrug + - system: OSX - Sebastian Spaeth - - email: sebastian at sspaeth.de - - github: spaetz - - other: left the project but still responding + - email: sebastian at sspaeth.de + - github: spaetz + - other: left the project but still responding Testers @@ -58,6 +63,7 @@ - Abdó Roig-Maranges - Ben Boeckel +- Chris Coleman - Darshit Shah - Eygene Ryabinkin - Igor Almeida diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/offlineimap-7.0.13/offlineimap/__init__.py new/offlineimap-7.0.14/offlineimap/__init__.py --- old/offlineimap-7.0.13/offlineimap/__init__.py 2017-01-27 19:49:42.000000000 +0100 +++ new/offlineimap-7.0.14/offlineimap/__init__.py 2017-03-11 13:22:18.000000000 +0100 @@ -2,8 +2,8 @@ __productname__ = 'OfflineIMAP' # Expecting trailing "-rcN" or "" for stable releases. -__version__ = "7.0.13" -__copyright__ = "Copyright 2002-2016 John Goerzen & contributors" +__version__ = "7.0.14" +__copyright__ = "Copyright 2002-2017 John Goerzen & contributors" __author__ = "John Goerzen" __author_email__= "offlineimap-proj...@lists.alioth.debian.org" __description__ = "Disconnected Universal IMAP Mail Synchronization/Reader Support" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/offlineimap-7.0.13/offlineimap/accounts.py new/offlineimap-7.0.14/offlineimap/accounts.py --- old/offlineimap-7.0.13/offlineimap/accounts.py 2017-01-27 19:49:42.000000000 +0100 +++ new/offlineimap-7.0.14/offlineimap/accounts.py 2017-03-11 13:22:18.000000000 +0100 @@ -15,7 +15,7 @@ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA from subprocess import Popen, PIPE -from threading import Event +from threading import Event, Lock import os import time from sys import exc_info @@ -29,6 +29,9 @@ from offlineimap.threadutil import InstanceLimitedThread FOLDER_NAMESPACE = 'LIMITED_FOLDER_' +# Key: account name, Value: Dict of Key: remotefolder name, Value: lock. +SYNC_MUTEXES = {} +SYNC_MUTEXES_LOCK = Lock() try: import fcntl @@ -430,11 +433,35 @@ self.ui.error(e, exc_info()[2], msg="Calling hook") +#XXX: This function should likely be refactored. This should not be passed the +# account instance. def syncfolder(account, remotefolder, quick): """Synchronizes given remote folder for the specified account. - Filtered folders on the remote side will not invoke this function. However, - this might be called in a concurrently.""" + Filtered folders on the remote side will not invoke this function. + + When called in concurrently for the same localfolder, syncs are + serialized.""" + + def acquire_mutex(): + account_name = account.getname() + localfolder_name = localfolder.getfullname() + + with SYNC_MUTEXES_LOCK: + if SYNC_MUTEXES.get(account_name) is None: + SYNC_MUTEXES[account_name] = {} + # The localfolder full name is good to uniquely identify the sync + # transaction. + if SYNC_MUTEXES[account_name].get(localfolder_name) is None: + #XXX: This lock could be an external file lock so we can remove + # the lock at the account level. + SYNC_MUTEXES[account_name][localfolder_name] = Lock() + + # Acquire the lock. + SYNC_MUTEXES[account_name][localfolder_name].acquire() + + def release_mutex(): + SYNC_MUTEXES[account.getname()][localfolder.getfullname()].release() def check_uid_validity(): # If either the local or the status folder has messages and @@ -528,6 +555,9 @@ # Load local folder. localfolder = account.get_local_folder(remotefolder) + # Acquire the mutex to start syncing. + acquire_mutex() + # Add the folder to the mbnames mailboxes. mbnames.add(account.name, localrepos.getlocalroot(), localfolder.getname()) @@ -616,3 +646,5 @@ if folder in locals(): locals()[folder].dropmessagelistcache() statusfolder.closefiles() + # Release the mutex of this sync transaction. + release_mutex() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/offlineimap-7.0.13/offlineimap/bundled_imaplib2.py new/offlineimap-7.0.14/offlineimap/bundled_imaplib2.py --- old/offlineimap-7.0.13/offlineimap/bundled_imaplib2.py 2017-01-27 19:49:42.000000000 +0100 +++ new/offlineimap-7.0.14/offlineimap/bundled_imaplib2.py 2017-03-11 13:22:18.000000000 +0100 @@ -18,9 +18,9 @@ "Internaldate2Time", "ParseFlags", "Time2Internaldate", "Mon2num", "MonthNames", "InternalDate") -__version__ = "2.55" +__version__ = "2.57" __release__ = "2" -__revision__ = "55" +__revision__ = "57" __credits__ = """ Authentication code contributed by Donn Cave <d...@u.washington.edu> June 1998. String method conversion by ESR, February 2001. @@ -109,6 +109,7 @@ 'CREATE': ((AUTH, SELECTED), True), 'DELETE': ((AUTH, SELECTED), True), 'DELETEACL': ((AUTH, SELECTED), True), + 'ENABLE': ((AUTH,), False), 'EXAMINE': ((AUTH, SELECTED), False), 'EXPUNGE': ((SELECTED,), True), 'FETCH': ((SELECTED,), True), @@ -300,17 +301,18 @@ class readonly(abort): pass # Mailbox status changed to READ-ONLY + # These must be encoded according to utf8 setting in _mode_xxx(): + _literal = br'.*{(?P<size>\d+)}$' + _untagged_status = br'\* (?P<data>\d+) (?P<type>[A-Z-]+)( (?P<data2>.*))?' + continuation_cre = re.compile(r'\+( (?P<data>.*))?') - literal_cre = re.compile(r'.*{(?P<size>\d+)}$') mapCRLF_cre = re.compile(r'\r\n|\r|\n') # Need to quote "atom-specials" :- # "(" / ")" / "{" / SP / 0x00 - 0x1f / 0x7f / "%" / "*" / DQUOTE / "\" / "]" # so match not the inverse set mustquote_cre = re.compile(r"[^!#$&'+,./0-9:;<=>?@A-Z\[^_`a-z|}~-]") response_code_cre = re.compile(r'\[(?P<type>[A-Z-]+)( (?P<data>[^\]]*))?\]') - # sequence_set_cre = re.compile(r"^[0-9]+(:([0-9]+|\*))?(,[0-9]+(:([0-9]+|\*))?)*$") untagged_response_cre = re.compile(r'\* (?P<type>[A-Z-]+)( (?P<data>.*))?') - untagged_status_cre = re.compile(r'\* (?P<data>\d+) (?P<type>[A-Z-]+)( (?P<data2>.*))?') def __init__(self, host=None, port=None, debug=None, debug_file=None, identifier=None, timeout=None, debug_buf_lvl=None): @@ -342,6 +344,8 @@ + self.tagpre + r'\d+) (?P<type>[A-Z]+) (?P<data>.*)') + self._mode_ascii() # Only option in py2 + if __debug__: self._init_debug(debug, debug_file, debug_buf_lvl) self.resp_timeout = timeout # Timeout waiting for command response @@ -428,6 +432,28 @@ raise AttributeError("Unknown IMAP4 command: '%s'" % attr) + def _mode_ascii(self): + self.utf8_enabled = False + self._encoding = 'ascii' + if bytes != str: + self.literal_cre = re.compile(self._literal, re.ASCII) + self.untagged_status_cre = re.compile(self._untagged_status, re.ASCII) + else: + self.literal_cre = re.compile(self._literal) + self.untagged_status_cre = re.compile(self._untagged_status) + + + def _mode_utf8(self): + self.utf8_enabled = True + self._encoding = 'utf-8' + if bytes != str: + self.literal_cre = re.compile(self._literal) + self.untagged_status_cre = re.compile(self._untagged_status) + else: + self.literal_cre = re.compile(self._literal, re.UNICODE) + self.untagged_status_cre = re.compile(self._untagged_status, re.UNICODE) + + # Overridable methods @@ -676,7 +702,10 @@ date_time = Time2Internaldate(date_time) else: date_time = None - self.literal = self.mapCRLF_cre.sub(CRLF, message) + literal = self.mapCRLF_cre.sub(CRLF, message) + if self.utf8_enabled: + literal = b'UTF8 (' + literal + b')' + self.literal = literal try: return self._simple_command(name, mailbox, flags, date_time, **kw) finally: @@ -774,6 +803,19 @@ return self._simple_command('DELETEACL', mailbox, who, **kw) + def enable(self, capability): + """Send an RFC5161 enable string to the server. + + (typ, [data]) = <intance>.enable(capability) + """ + if 'ENABLE' not in self.capabilities: + raise self.error("Server does not support ENABLE") + typ, data = self._simple_command('ENABLE', capability) + if typ == 'OK' and 'UTF8=ACCEPT' in capability.upper(): + self._mode_utf8() + return typ, data + + def examine(self, mailbox='INBOX', **kw): """(typ, [data]) = examine(mailbox='INBOX') Select a mailbox for READ-ONLY access. (Flushes all untagged responses.) @@ -1025,11 +1067,14 @@ def search(self, charset, *criteria, **kw): """(typ, [data]) = search(charset, criterion, ...) Search mailbox for matching messages. + If UTF8 is enabled, charset MUST be None. 'data' is space separated list of matching message numbers.""" name = 'SEARCH' kw['untagged_response'] = name if charset: + if self.utf8_enabled: + raise self.error("Non-None charset not valid in UTF8 mode") return self._simple_command(name, 'CHARSET', charset, *criteria, **kw) return self._simple_command(name, *criteria, **kw) @@ -1412,6 +1457,9 @@ if not ok: break + if data == 'go ahead': # Apparently not uncommon broken IMAP4 server response to AUTHENTICATE command + data = '' + # Send literal if literator is not None: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/offlineimap-7.0.13/offlineimap/folder/LocalStatusSQLite.py new/offlineimap-7.0.14/offlineimap/folder/LocalStatusSQLite.py --- old/offlineimap-7.0.13/offlineimap/folder/LocalStatusSQLite.py 2017-01-27 19:49:42.000000000 +0100 +++ new/offlineimap-7.0.14/offlineimap/folder/LocalStatusSQLite.py 2017-03-11 13:22:18.000000000 +0100 @@ -1,5 +1,5 @@ # Local status cache virtual folder: SQLite backend -# Copyright (C) 2009-2016 Stewart Smith and contributors. +# Copyright (C) 2009-2017 Stewart Smith and contributors. # # 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 @@ -282,16 +282,17 @@ def saveall(self): """Saves the entire messagelist to the database.""" - data = [] - for uid, msg in self.messagelist.items(): - mtime = msg['mtime'] - flags = ''.join(sorted(msg['flags'])) - labels = ', '.join(sorted(msg['labels'])) - data.append((uid, flags, mtime, labels)) - - self.__sql_write('INSERT OR REPLACE INTO status ' - '(id,flags,mtime,labels) VALUES (?,?,?,?)', - data, executemany=True) + with self._databaseFileLock.getLock(): + data = [] + for uid, msg in self.messagelist.items(): + mtime = msg['mtime'] + flags = ''.join(sorted(msg['flags'])) + labels = ', '.join(sorted(msg['labels'])) + data.append((uid, flags, mtime, labels)) + + self.__sql_write('INSERT OR REPLACE INTO status ' + '(id,flags,mtime,labels) VALUES (?,?,?,?)', + data, executemany=True) # Following some pure SQLite functions, where we chose to use diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/offlineimap-7.0.13/offlineimap/repository/IMAP.py new/offlineimap-7.0.14/offlineimap/repository/IMAP.py --- old/offlineimap-7.0.13/offlineimap/repository/IMAP.py 2017-01-27 19:49:42.000000000 +0100 +++ new/offlineimap-7.0.14/offlineimap/repository/IMAP.py 2017-03-11 13:22:18.000000000 +0100 @@ -222,7 +222,7 @@ return self.getconfint('remoteport', None) def getipv6(self): - return self.getconfboolean('ipv6', False) + return self.getconfboolean('ipv6', None) def getssl(self): return self.getconfboolean('ssl', True) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/offlineimap-7.0.13/offlineimap/repository/LocalStatus.py new/offlineimap-7.0.14/offlineimap/repository/LocalStatus.py --- old/offlineimap-7.0.13/offlineimap/repository/LocalStatus.py 2017-01-27 19:49:42.000000000 +0100 +++ new/offlineimap-7.0.14/offlineimap/repository/LocalStatus.py 2017-03-11 13:22:18.000000000 +0100 @@ -1,5 +1,5 @@ # Local status cache repository support -# Copyright (C) 2002-2016 John Goerzen & contributors +# Copyright (C) 2002-2017 John Goerzen & contributors # # 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 @@ -21,6 +21,7 @@ from offlineimap.folder.LocalStatusSQLite import LocalStatusSQLiteFolder from offlineimap.repository.Base import BaseRepository + class LocalStatusRepository(BaseRepository): def __init__(self, reposname, account): BaseRepository.__init__(self, reposname, account) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/offlineimap-7.0.13/scripts/get-repository.sh new/offlineimap-7.0.14/scripts/get-repository.sh --- old/offlineimap-7.0.13/scripts/get-repository.sh 2017-01-27 19:49:42.000000000 +0100 +++ new/offlineimap-7.0.14/scripts/get-repository.sh 2017-03-11 13:22:18.000000000 +0100 @@ -1,6 +1,6 @@ -#!/bin/bash +#!/bin/sh # -# Licence: this file is in the public deomain. +# Licence: this file is in the public domain. # # Download and configure the repositories of the website or wiki. @@ -10,7 +10,7 @@ # # TODO # -function final_note () { +final_note () { cat <<EOF Now, you can fork the repository into Github from $2 @@ -22,7 +22,7 @@ EOF } -function setup () { +setup () { target_dir=$1 remote_url=$2 @@ -49,7 +49,7 @@ fi } -function configure_website () { +configure_website () { renderer='./render.sh' echo "Found Github username: '$1'" @@ -65,7 +65,7 @@ fi } -function configure_wiki () { +configure_wiki () { : # noop }