Merge branch 'next'

All current changes in next received some testing and no regressions
were spotted.  Make them to receive beating from people running "master".
This commit is contained in:
Eygene Ryabinkin 2014-10-08 08:53:25 +04:00
commit 060d75a904
5 changed files with 110 additions and 60 deletions

14
COPYING
View File

@ -348,3 +348,17 @@ proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General library. If this is what you want to do, use the GNU Library General
Public License instead of this License. Public License instead of this License.
----------------------------------------------------------------
In addition, as a special exception, the copyright holders give
permission to link the code of portions of this program with the OpenSSL
library under certain conditions as described in each individual source
file, and distribute linked combinations including the two.
You must obey the GNU General Public License in all respects for all of
the code used other than OpenSSL. If you modify file(s) with this
exception, you may extend this exception to your version of the file(s),
but you are not obligated to do so. If you do not wish to do so, delete
this exception statement from your version. If you delete this exception
statement from all source files in the program, then also delete it
here.

View File

@ -8,6 +8,15 @@ ChangeLog
OfflineIMAP v6.5.6.1 (YYYY-MM-DD) OfflineIMAP v6.5.6.1 (YYYY-MM-DD)
================================= =================================
* Added OpenSSL exception clause to our main GPL to allow
people to link with OpenSSL in run-time. It is needed
at least for Debian, see
https://lists.debian.org/debian-legal/2002/10/msg00113.html
for details.
* Fix warning-level message processing by MachineUI
(GitHub pull #64, GitHub pull #118).
* Support default CA bundle locations for a couple of * Support default CA bundle locations for a couple of
known Unix systems (Michael Vogt, GutHub pull #19) known Unix systems (Michael Vogt, GutHub pull #19)

View File

@ -17,9 +17,10 @@ documentation.
OfflineIMAP does not require additional python dependencies beyond python >=2.6 OfflineIMAP does not require additional python dependencies beyond python >=2.6
(although python-sqlite is strongly recommended). (although python-sqlite is strongly recommended).
OfflineIMAP is a Free Software project licensed under the GNU General Public OfflineIMAP is a Free Software project licensed under the GNU General
License version 2 (or later). You can download it for free, and you can modify Public License version 2 (or later) with a special exception that allows
it. In fact, you are encouraged to contribute to OfflineIMAP. the OpenSSL library to be used. You can download it for free, and you
can modify it. In fact, you are encouraged to contribute to OfflineIMAP.
Documentation Documentation
------------- -------------

View File

@ -8,7 +8,7 @@ __copyright__ = "Copyright 2002-2013 John Goerzen & contributors"
__author__ = "John Goerzen" __author__ = "John Goerzen"
__author_email__= "john@complete.org" __author_email__= "john@complete.org"
__description__ = "Disconnected Universal IMAP Mail Synchronization/Reader Support" __description__ = "Disconnected Universal IMAP Mail Synchronization/Reader Support"
__license__ = "Licensed under the GNU GPL v2+ (v2 or any later version)" __license__ = "Licensed under the GNU GPL v2 or any later version (with an OpenSSL exception)"
__bigcopyright__ = """%(__productname__)s %(__bigversion__)s __bigcopyright__ = """%(__productname__)s %(__bigversion__)s
%(__license__)s""" % locals() %(__license__)s""" % locals()
__homepage__ = "http://offlineimap.org" __homepage__ = "http://offlineimap.org"

View File

@ -28,82 +28,107 @@ protocol = '7.0.0'
class MachineLogFormatter(logging.Formatter): class MachineLogFormatter(logging.Formatter):
"""urlencodes any outputted line, to avoid multi-line output""" """urlencodes any outputted line, to avoid multi-line output"""
def format(self, record): def format(s, record):
# urlencode the "mesg" attribute and append to regular line... # Mapping of log levels to historic tag names
line = super(MachineLogFormatter, self).format(record) severity_map = {
return line + urlencode([('', record.mesg)])[1:] 'info': 'msg',
'warning': 'warn',
}
line = super(MachineLogFormatter, s).format(record)
severity = record.levelname.lower()
if severity in severity_map:
severity = severity_map[severity]
if hasattr(record, "machineui"):
command = record.machineui["command"]
whoami = record.machineui["id"]
else:
command = ""
whoami = currentThread().getName()
prefix = "%s:%s" % (command, urlencode([('', whoami)])[1:])
return "%s:%s:%s" % (severity, prefix, urlencode([('', line)])[1:])
class MachineUI(UIBase): class MachineUI(UIBase):
def __init__(self, config, loglevel = logging.INFO): def __init__(s, config, loglevel = logging.INFO):
super(MachineUI, self).__init__(config, loglevel) super(MachineUI, s).__init__(config, loglevel)
self._log_con_handler.createLock() s._log_con_handler.createLock()
"""lock needed to block on password input""" """lock needed to block on password input"""
# Set up the formatter that urlencodes the strings... # Set up the formatter that urlencodes the strings...
self._log_con_handler.setFormatter(MachineLogFormatter()) s._log_con_handler.setFormatter(MachineLogFormatter())
def _printData(self, command, msg): # Arguments:
self.logger.info("%s:%s:%s" % ( # - handler: must be method from s.logger that reflects
'msg', command, currentThread().getName()), extra={'mesg': msg}) # the severity of the passed message
# - command: command that produced this message
# - msg: the message itself
def _printData(s, handler, command, msg):
handler(msg,
extra = {
'machineui': {
'command': command,
'id': currentThread().getName(),
}
})
def _msg(s, msg): def _msg(s, msg):
s._printData('_display', msg) s._printData(s.logger.info, '_display', msg)
def warn(self, msg, minor = 0): def warn(s, msg, minor = 0):
# TODO, remove and cleanup the unused minor stuff # TODO, remove and cleanup the unused minor stuff
self.logger.warning("%s:%s:%s:%s" % ( s._printData(s.logger.warning, '', msg)
'warn', '', currentThread().getName(), msg))
def registerthread(self, account): def registerthread(s, account):
super(MachineUI, self).registerthread(account) super(MachineUI, s).registerthread(account)
self._printData('registerthread', account) s._printData(s.logger.info, 'registerthread', account)
def unregisterthread(s, thread): def unregisterthread(s, thread):
UIBase.unregisterthread(s, thread) UIBase.unregisterthread(s, thread)
s._printData('unregisterthread', thread.getName()) s._printData(s.logger.info, 'unregisterthread', thread.getName())
def debugging(s, debugtype): def debugging(s, debugtype):
s._printData('debugging', debugtype) s._printData(s.logger.debug, 'debugging', debugtype)
def acct(s, accountname): def acct(s, accountname):
s._printData('acct', accountname) s._printData(s.logger.info, 'acct', accountname)
def acctdone(s, accountname): def acctdone(s, accountname):
s._printData('acctdone', accountname) s._printData(s.logger.info, 'acctdone', accountname)
def validityproblem(s, folder): def validityproblem(s, folder):
s._printData('validityproblem', "%s\n%s\n%s\n%s" % \ s._printData(s.logger.warning, 'validityproblem', "%s\n%s\n%s\n%s" % \
(folder.getname(), folder.getrepository().getname(), (folder.getname(), folder.getrepository().getname(),
folder.get_saveduidvalidity(), folder.get_uidvalidity())) folder.get_saveduidvalidity(), folder.get_uidvalidity()))
def connecting(s, hostname, port): def connecting(s, hostname, port):
s._printData('connecting', "%s\n%s" % (hostname, str(port))) s._printData(s.logger.info, 'connecting', "%s\n%s" % (hostname, str(port)))
def syncfolders(s, srcrepos, destrepos): def syncfolders(s, srcrepos, destrepos):
s._printData('syncfolders', "%s\n%s" % (s.getnicename(srcrepos), s._printData(s.logger.info, 'syncfolders', "%s\n%s" % (s.getnicename(srcrepos),
s.getnicename(destrepos))) s.getnicename(destrepos)))
def syncingfolder(s, srcrepos, srcfolder, destrepos, destfolder): def syncingfolder(s, srcrepos, srcfolder, destrepos, destfolder):
s._printData('syncingfolder', "%s\n%s\n%s\n%s\n" % \ s._printData(s.logger.info, 'syncingfolder', "%s\n%s\n%s\n%s\n" % \
(s.getnicename(srcrepos), srcfolder.getname(), (s.getnicename(srcrepos), srcfolder.getname(),
s.getnicename(destrepos), destfolder.getname())) s.getnicename(destrepos), destfolder.getname()))
def loadmessagelist(s, repos, folder): def loadmessagelist(s, repos, folder):
s._printData('loadmessagelist', "%s\n%s" % (s.getnicename(repos), s._printData(s.logger.info, 'loadmessagelist', "%s\n%s" % (s.getnicename(repos),
folder.getvisiblename())) folder.getvisiblename()))
def messagelistloaded(s, repos, folder, count): def messagelistloaded(s, repos, folder, count):
s._printData('messagelistloaded', "%s\n%s\n%d" % \ s._printData(s.logger.info, 'messagelistloaded', "%s\n%s\n%d" % \
(s.getnicename(repos), folder.getname(), count)) (s.getnicename(repos), folder.getname(), count))
def syncingmessages(s, sr, sf, dr, df): def syncingmessages(s, sr, sf, dr, df):
s._printData('syncingmessages', "%s\n%s\n%s\n%s\n" % \ s._printData(s.logger.info, 'syncingmessages', "%s\n%s\n%s\n%s\n" % \
(s.getnicename(sr), sf.getname(), s.getnicename(dr), (s.getnicename(sr), sf.getname(), s.getnicename(dr),
df.getname())) df.getname()))
def copyingmessage(self, uid, num, num_to_copy, srcfolder, destfolder): def copyingmessage(s, uid, num, num_to_copy, srcfolder, destfolder):
self._printData('copyingmessage', "%d\n%s\n%s\n%s[%s]" % \ s._printData(s.logger.info, 'copyingmessage', "%d\n%s\n%s\n%s[%s]" % \
(uid, self.getnicename(srcfolder), srcfolder.getname(), (uid, s.getnicename(srcfolder), srcfolder.getname(),
self.getnicename(destfolder), destfolder)) s.getnicename(destfolder), destfolder))
def folderlist(s, list): def folderlist(s, list):
return ("\f".join(["%s\t%s" % (s.getnicename(x), x.getname()) for x in list])) return ("\f".join(["%s\t%s" % (s.getnicename(x), x.getname()) for x in list]))
@ -113,57 +138,58 @@ class MachineUI(UIBase):
def deletingmessages(s, uidlist, destlist): def deletingmessages(s, uidlist, destlist):
ds = s.folderlist(destlist) ds = s.folderlist(destlist)
s._printData('deletingmessages', "%s\n%s" % (s.uidlist(uidlist), ds)) s._printData(s.logger.info, 'deletingmessages', "%s\n%s" % (s.uidlist(uidlist), ds))
def addingflags(s, uidlist, flags, dest): def addingflags(s, uidlist, flags, dest):
s._printData("addingflags", "%s\n%s\n%s" % (s.uidlist(uidlist), s._printData(s.logger.info, "addingflags", "%s\n%s\n%s" % (s.uidlist(uidlist),
"\f".join(flags), "\f".join(flags),
dest)) dest))
def deletingflags(s, uidlist, flags, dest): def deletingflags(s, uidlist, flags, dest):
s._printData('deletingflags', "%s\n%s\n%s" % (s.uidlist(uidlist), s._printData(s.logger.info, 'deletingflags', "%s\n%s\n%s" % (s.uidlist(uidlist),
"\f".join(flags), "\f".join(flags),
dest)) dest))
def threadException(self, thread): def threadException(s, thread):
self._printData('threadException', "%s\n%s" % \ s._printData(s.logger.warning, 'threadException', "%s\n%s" % \
(thread.getName(), self.getThreadExceptionString(thread))) (thread.getName(), s.getThreadExceptionString(thread)))
self.delThreadDebugLog(thread) s.delThreadDebugLog(thread)
self.terminate(100) s.terminate(100)
def terminate(s, exitstatus = 0, errortitle = '', errormsg = ''): def terminate(s, exitstatus = 0, errortitle = '', errormsg = ''):
s._printData('terminate', "%d\n%s\n%s" % (exitstatus, errortitle, errormsg)) s._printData(s.logger.info, 'terminate', "%d\n%s\n%s" % (exitstatus, errortitle, errormsg))
sys.exit(exitstatus) sys.exit(exitstatus)
def mainException(s): def mainException(s):
s._printData('mainException', s.getMainExceptionString()) s._printData(s.logger.warning, 'mainException', s.getMainExceptionString())
def threadExited(s, thread): def threadExited(s, thread):
s._printData('threadExited', thread.getName()) s._printData(s.logger.info, 'threadExited', thread.getName())
UIBase.threadExited(s, thread) UIBase.threadExited(s, thread)
def sleeping(s, sleepsecs, remainingsecs): def sleeping(s, sleepsecs, remainingsecs):
s._printData('sleeping', "%d\n%d" % (sleepsecs, remainingsecs)) s._printData(s.logger.info, 'sleeping', "%d\n%d" % (sleepsecs, remainingsecs))
if sleepsecs > 0: if sleepsecs > 0:
time.sleep(sleepsecs) time.sleep(sleepsecs)
return 0 return 0
def getpass(self, accountname, config, errmsg = None): def getpass(s, accountname, config, errmsg = None):
if errmsg: if errmsg:
self._printData('getpasserror', "%s\n%s" % (accountname, errmsg), s._printData(s.logger.warning,
'getpasserror', "%s\n%s" % (accountname, errmsg),
False) False)
self._log_con_handler.acquire() # lock the console output s._log_con_handler.acquire() # lock the console output
try: try:
self._printData('getpass', accountname, False) s._printData(s.logger.info, 'getpass', accountname, False)
return (sys.stdin.readline()[:-1]) return (sys.stdin.readline()[:-1])
finally: finally:
self._log_con_handler.release() s._log_con_handler.release()
def init_banner(self): def init_banner(s):
self._printData('protocol', protocol) s._printData(s.logger.info, 'protocol', protocol)
self._printData('initbanner', offlineimap.banner) s._printData(s.logger.info, 'initbanner', offlineimap.banner)
def callhook(self, msg): def callhook(s, msg):
self._printData('callhook', msg) s._printData(s.logger.info, 'callhook', msg)