6 |
6 |
7 import os |
7 import os |
8 import re |
8 import re |
9 import locale |
9 import locale |
10 |
10 |
11 from constants.VERSION import * |
11 from encodings.idna import ToASCII, ToUnicode |
12 import constants.ERROR as ERR |
12 |
|
13 from VirtualMailManager.constants.ERROR import \ |
|
14 DOMAIN_INVALID, DOMAIN_TOO_LONG, NOT_EXECUTABLE, NO_SUCH_BINARY, \ |
|
15 NO_SUCH_DIRECTORY |
|
16 from VirtualMailManager.constants.VERSION import * |
|
17 from VirtualMailManager.Exceptions import VMMException |
|
18 |
|
19 |
|
20 __all__ = [ |
|
21 # imported modules |
|
22 'os', 're', 'locale', |
|
23 # version information from VERSION |
|
24 '__author__', '__date__', '__version__', |
|
25 # error codes |
|
26 'ENCODING', 'ace2idna', 'chk_domainname', 'exec_ok', 'expand_path', |
|
27 'get_unicode', 'idn2ascii', 'is_dir', |
|
28 ] |
|
29 |
13 |
30 |
14 # Try to set all of the locales according to the current |
31 # Try to set all of the locales according to the current |
15 # environment variables and get the character encoding. |
32 # environment variables and get the character encoding. |
16 try: |
33 try: |
17 locale.setlocale(locale.LC_ALL, '') |
34 locale.setlocale(locale.LC_ALL, '') |
18 except locale.Error: |
35 except locale.Error: |
19 locale.setlocale(locale.LC_ALL, 'C') |
36 locale.setlocale(locale.LC_ALL, 'C') |
20 ENCODING = locale.nl_langinfo(locale.CODESET) |
37 ENCODING = locale.nl_langinfo(locale.CODESET) |
21 |
38 |
22 def w_std(*args): |
39 RE_ASCII_CHARS = """^[\x20-\x7E]*$""" |
23 """Writes each arg of args, encoded in the current ENCODING, to stdout and |
40 RE_DOMAIN = """^(?:[a-z0-9-]{1,63}\.){1,}[a-z]{2,6}$""" |
24 appends a newline.""" |
|
25 _write = os.sys.stdout.write |
|
26 for arg in args: |
|
27 _write(arg.encode(ENCODING, 'replace')) |
|
28 _write('\n') |
|
29 |
41 |
30 def w_err(code, *args): |
|
31 """Writes each arg of args, encoded in the current ENCODING, to stderr and |
|
32 appends a newline. |
|
33 This function additional interrupts the program execution and uses 'code' |
|
34 system exit status.""" |
|
35 _write = os.sys.stderr.write |
|
36 for arg in args: |
|
37 _write(arg.encode(ENCODING, 'replace')) |
|
38 _write('\n') |
|
39 os.sys.exit(code) |
|
40 |
42 |
41 def get_unicode(string): |
43 def get_unicode(string): |
42 """Converts `string` to `unicode`, if necessary.""" |
44 """Converts `string` to `unicode`, if necessary.""" |
43 if isinstance(string, unicode): |
45 if isinstance(string, unicode): |
44 return string |
46 return string |
45 return unicode(string, ENCODING, 'replace') |
47 return unicode(string, ENCODING, 'replace') |
46 |
48 |
47 __all__ = [ |
49 def expand_path(path): |
48 # imported modules |
50 """Expands paths, starting with ``.`` or ``~``, to an absolute path.""" |
49 'os', 're', 'locale', |
51 if path.startswith('.'): |
50 # version information from VERSION |
52 return os.path.abspath(path) |
51 '__author__', '__date__', '__version__', |
53 if path.startswith('~'): |
52 # error codes |
54 return os.path.expanduser(path) |
53 'ERR', |
55 return path |
54 # defined stuff |
56 |
55 'ENCODING', 'get_unicode', 'w_std', 'w_err' |
57 def is_dir(path): |
56 ] |
58 """Checks if ``path`` is a directory. |
57 # EOF |
59 |
|
60 Throws a `VMMException` if ``path`` is not a directory. |
|
61 """ |
|
62 path = expand_path(path) |
|
63 if not os.path.isdir(path): |
|
64 raise VMMException(_(u'“%s” is not a directory') % get_unicode(path), |
|
65 NO_SUCH_DIRECTORY) |
|
66 return path |
|
67 |
|
68 def exec_ok(binary): |
|
69 """Checks if the ``binary`` exists and if it is executable. |
|
70 |
|
71 Throws a `VMMException` if the ``binary`` isn't a file or is not |
|
72 executable. |
|
73 """ |
|
74 binary = expand_path(binary) |
|
75 if not os.path.isfile(binary): |
|
76 raise VMMException(_(u'“%s” is not a file') % get_unicode(binary), |
|
77 NO_SUCH_BINARY) |
|
78 if not os.access(binary, os.X_OK): |
|
79 raise VMMException(_(u'File is not executable: “%s”') % \ |
|
80 get_unicode(binary), NOT_EXECUTABLE) |
|
81 return binary |
|
82 |
|
83 def idn2ascii(domainname): |
|
84 """Converts the idn domain name `domainname` into punycode.""" |
|
85 return '.'.join([ToASCII(lbl) for lbl in domainname.split('.') if lbl]) |
|
86 |
|
87 def ace2idna(domainname): |
|
88 """Converts the domain name `domainname` from ACE according to IDNA.""" |
|
89 return u'.'.join([ToUnicode(lbl) for lbl in domainname.split('.') if lbl]) |
|
90 |
|
91 def chk_domainname(domainname): |
|
92 """Returns the validated domain name `domainname`. |
|
93 |
|
94 It also converts the name of the domain from IDN to ASCII, if necessary. |
|
95 |
|
96 Throws an VMMException, if the domain name is too long or doesn't look |
|
97 like a valid domain name (label.label.label). |
|
98 """ |
|
99 if not re.match(RE_ASCII_CHARS, domainname): |
|
100 domainname = idn2ascii(domainname) |
|
101 if len(domainname) > 255: |
|
102 raise VMMException(_(u'The domain name is too long.'), DOMAIN_TOO_LONG) |
|
103 if not re.match(RE_DOMAIN, domainname): |
|
104 raise VMMException(_(u'The domain name “%s” is invalid.') % domainname, |
|
105 DOMAIN_INVALID) |
|
106 return domainname |