2002-07-11 07:38:14 +02:00
|
|
|
# TTY UI
|
2015-01-01 21:41:11 +01:00
|
|
|
# Copyright (C) 2002-2015 John Goerzen & contributors
|
2002-07-11 07:38:14 +02:00
|
|
|
#
|
|
|
|
# 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
|
2003-04-16 21:23:45 +02:00
|
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
|
|
# (at your option) any later version.
|
2002-07-11 07:38:14 +02:00
|
|
|
#
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License
|
|
|
|
# along with this program; if not, write to the Free Software
|
2006-08-12 06:15:55 +02:00
|
|
|
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
2011-10-26 16:47:21 +02:00
|
|
|
|
|
|
|
import logging
|
2011-03-11 22:13:21 +01:00
|
|
|
import sys
|
2012-01-19 02:00:09 +01:00
|
|
|
import time
|
2011-10-26 16:47:21 +02:00
|
|
|
from getpass import getpass
|
|
|
|
from offlineimap import banner
|
|
|
|
from offlineimap.ui.UIBase import UIBase
|
|
|
|
|
|
|
|
class TTYFormatter(logging.Formatter):
|
|
|
|
"""Specific Formatter that adds thread information to the log output"""
|
2015-01-01 21:41:11 +01:00
|
|
|
|
2011-10-26 16:47:21 +02:00
|
|
|
def __init__(self, *args, **kwargs):
|
2012-01-18 00:39:04 +01:00
|
|
|
#super() doesn't work in py2.6 as 'logging' uses old-style class
|
|
|
|
logging.Formatter.__init__(self, *args, **kwargs)
|
2011-10-26 16:47:21 +02:00
|
|
|
self._last_log_thread = None
|
|
|
|
|
|
|
|
def format(self, record):
|
|
|
|
"""Override format to add thread information"""
|
2012-01-18 00:39:04 +01:00
|
|
|
#super() doesn't work in py2.6 as 'logging' uses old-style class
|
|
|
|
log_str = logging.Formatter.format(self, record)
|
2011-10-26 16:47:21 +02:00
|
|
|
# If msg comes from a different thread than our last, prepend
|
|
|
|
# thread info. Most look like 'Account sync foo' or 'Folder
|
|
|
|
# sync foo'.
|
|
|
|
t_name = record.threadName
|
|
|
|
if t_name == 'MainThread':
|
|
|
|
return log_str # main thread doesn't get things prepended
|
|
|
|
if t_name != self._last_log_thread:
|
|
|
|
self._last_log_thread = t_name
|
|
|
|
log_str = "%s:\n %s" % (t_name, log_str)
|
|
|
|
else:
|
|
|
|
log_str = " %s" % log_str
|
|
|
|
return log_str
|
2002-06-21 07:29:12 +02:00
|
|
|
|
2015-01-01 21:41:11 +01:00
|
|
|
|
2002-06-21 07:42:39 +02:00
|
|
|
class TTYUI(UIBase):
|
2011-10-26 16:47:21 +02:00
|
|
|
def setup_consolehandler(self):
|
|
|
|
"""Backend specific console handler
|
2002-07-25 01:13:09 +02:00
|
|
|
|
2011-10-26 16:47:21 +02:00
|
|
|
Sets up things and adds them to self.logger.
|
|
|
|
:returns: The logging.Handler() for console output"""
|
2015-01-01 21:41:11 +01:00
|
|
|
|
2011-10-26 16:47:21 +02:00
|
|
|
# create console handler with a higher log level
|
|
|
|
ch = logging.StreamHandler()
|
|
|
|
#ch.setLevel(logging.DEBUG)
|
|
|
|
# create formatter and add it to the handlers
|
|
|
|
self.formatter = TTYFormatter("%(message)s")
|
|
|
|
ch.setFormatter(self.formatter)
|
|
|
|
# add the handlers to the logger
|
|
|
|
self.logger.addHandler(ch)
|
|
|
|
self.logger.info(banner)
|
|
|
|
# init lock for console output
|
|
|
|
ch.createLock()
|
|
|
|
return ch
|
2010-12-05 15:35:02 +01:00
|
|
|
|
2011-10-26 16:47:21 +02:00
|
|
|
def isusable(self):
|
|
|
|
"""TTYUI is reported as usable when invoked on a terminal"""
|
2015-01-01 21:41:11 +01:00
|
|
|
|
2011-10-26 16:47:21 +02:00
|
|
|
return sys.stdout.isatty() and sys.stdin.isatty()
|
2002-06-21 07:29:12 +02:00
|
|
|
|
2015-01-01 21:41:11 +01:00
|
|
|
def getpass(self, accountname, config, errmsg=None):
|
2011-10-26 16:47:21 +02:00
|
|
|
"""TTYUI backend is capable of querying the password"""
|
2015-01-01 21:41:11 +01:00
|
|
|
|
2002-11-05 00:15:42 +01:00
|
|
|
if errmsg:
|
2011-10-26 16:47:21 +02:00
|
|
|
self.warn("%s: %s" % (accountname, errmsg))
|
|
|
|
self._log_con_handler.acquire() # lock the console output
|
2002-11-05 00:15:42 +01:00
|
|
|
try:
|
2011-10-26 16:47:21 +02:00
|
|
|
return getpass("Enter password for account '%s': " % accountname)
|
2002-11-05 00:15:42 +01:00
|
|
|
finally:
|
2011-10-26 16:47:21 +02:00
|
|
|
self._log_con_handler.release()
|
2002-06-21 07:42:39 +02:00
|
|
|
|
2011-10-26 16:47:21 +02:00
|
|
|
def mainException(self):
|
|
|
|
if isinstance(sys.exc_info()[1], KeyboardInterrupt):
|
|
|
|
self.logger.warn("Timer interrupted at user request; program "
|
|
|
|
"terminating.\n")
|
|
|
|
self.terminate()
|
2002-07-05 04:34:39 +02:00
|
|
|
else:
|
2011-10-26 16:47:21 +02:00
|
|
|
UIBase.mainException(self)
|
2002-07-03 08:50:31 +02:00
|
|
|
|
2012-01-10 07:19:22 +01:00
|
|
|
def sleeping(self, sleepsecs, remainingsecs):
|
|
|
|
"""Sleep for sleepsecs, display remainingsecs to go.
|
|
|
|
|
|
|
|
Does nothing if sleepsecs <= 0.
|
|
|
|
Display a message on the screen if we pass a full minute.
|
|
|
|
|
|
|
|
This implementation in UIBase does not support this, but some
|
|
|
|
implementations return 0 for successful sleep and 1 for an
|
|
|
|
'abort', ie a request to sync immediately.
|
|
|
|
"""
|
2015-01-01 21:41:11 +01:00
|
|
|
|
2012-01-10 07:19:22 +01:00
|
|
|
if sleepsecs > 0:
|
|
|
|
if remainingsecs//60 != (remainingsecs-sleepsecs)//60:
|
|
|
|
self.logger.info("Next refresh in %.1f minutes" % (
|
|
|
|
remainingsecs/60.0))
|
|
|
|
time.sleep(sleepsecs)
|
|
|
|
return 0
|