VirtualMailManager/__init__.py
branchv0.6.x
changeset 185 6e1ef32fbd82
parent 174 974bafa59330
child 187 38b9a9859749
equal deleted inserted replaced
184:d0425225ce52 185:6e1ef32fbd82
     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