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