VirtualMailManager/cli/__init__.py
changeset 760 b678a1c43027
parent 748 659c4476c57c
child 761 e4e656f19771
equal deleted inserted replaced
748:659c4476c57c 760:b678a1c43027
     1 # -*- coding: UTF-8 -*-
       
     2 # Copyright (c) 2010 - 2014, Pascal Volk
       
     3 # See COPYING for distribution information.
       
     4 """
       
     5     VirtualMailManager.cli
       
     6     ~~~~~~~~~~~~~~~~~~~~~~
       
     7 
       
     8     VirtualMailManager's command line interface.
       
     9 """
       
    10 
       
    11 import os
       
    12 from array import array
       
    13 from fcntl import ioctl
       
    14 from getpass import getpass
       
    15 from termios import TIOCGWINSZ
       
    16 
       
    17 from VirtualMailManager import ENCODING
       
    18 from VirtualMailManager.constants import VMM_TOO_MANY_FAILURES
       
    19 from VirtualMailManager.errors import VMMError
       
    20 
       
    21 
       
    22 __all__ = ('prog', 'get_winsize', 'read_pass', 'w_err', 'w_std')
       
    23 
       
    24 _ = lambda msg: msg
       
    25 _std_write = os.sys.stdout.write
       
    26 _err_write = os.sys.stderr.write
       
    27 prog = os.path.basename(os.sys.argv[0])
       
    28 
       
    29 
       
    30 def w_std(*args):
       
    31     """Writes a line for each arg of *args*, encoded in the current
       
    32     ENCODING, to stdout.
       
    33     """
       
    34     _std_write('\n'.join(a.encode(ENCODING, 'replace') for a in args) + '\n')
       
    35 
       
    36 
       
    37 def w_err(code, *args):
       
    38     """Writes a line for each arg of *args*, encoded in the current
       
    39     ENCODING, to stderr.
       
    40     This function optionally interrupts the program execution if *code*
       
    41     does not equal to 0. *code* will be used as the system exit status.
       
    42     """
       
    43     _err_write('\n'.join(a.encode(ENCODING, 'replace') for a in args) + '\n')
       
    44     if code:
       
    45         os.sys.exit(code)
       
    46 
       
    47 
       
    48 def get_winsize():
       
    49     """Returns a tuple of integers ``(ws_row, ws_col)`` with the height and
       
    50     width of the terminal."""
       
    51     fd = None
       
    52     for dev in (os.sys.stdout, os.sys.stderr, os.sys.stdin):
       
    53         if hasattr(dev, 'fileno') and os.isatty(dev.fileno()):
       
    54             fd = dev.fileno()
       
    55             break
       
    56     if fd is None:  # everything seems to be redirected
       
    57         # fall back to environment or assume some common defaults
       
    58         ws_row, ws_col = 24, 80
       
    59         try:
       
    60             ws_col = int(os.environ.get('COLUMNS', 80))
       
    61             ws_row = int(os.environ.get('LINES', 24))
       
    62         except ValueError:
       
    63             pass
       
    64         return ws_row, ws_col
       
    65     #"struct winsize" with the ``unsigned short int``s ws_{row,col,{x,y}pixel}
       
    66     ws = array('H', (0, 0, 0, 0))
       
    67     ioctl(fd, TIOCGWINSZ, ws, True)
       
    68     ws_row, ws_col = ws[:2]
       
    69     return ws_row, ws_col
       
    70 
       
    71 
       
    72 def read_pass():
       
    73     """Interactive 'password chat', returns the password in plain format.
       
    74 
       
    75     Throws a VMMError after the third failure.
       
    76     """
       
    77     # TP: Please preserve the trailing space.
       
    78     readp_msg0 = _(u'Enter new password: ').encode(ENCODING, 'replace')
       
    79     # TP: Please preserve the trailing space.
       
    80     readp_msg1 = _(u'Retype new password: ').encode(ENCODING, 'replace')
       
    81     mismatched = True
       
    82     failures = 0
       
    83     while mismatched:
       
    84         if failures > 2:
       
    85             raise VMMError(_(u'Too many failures - try again later.'),
       
    86                            VMM_TOO_MANY_FAILURES)
       
    87         clear0 = getpass(prompt=readp_msg0)
       
    88         clear1 = getpass(prompt=readp_msg1)
       
    89         if clear0 != clear1:
       
    90             failures += 1
       
    91             w_err(0, _(u'Sorry, passwords do not match.'))
       
    92             continue
       
    93         if not clear0:
       
    94             failures += 1
       
    95             w_err(0, _(u'Sorry, empty passwords are not permitted.'))
       
    96             continue
       
    97         mismatched = False
       
    98     return clear0
       
    99 
       
   100 del _