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