diff -r 02d467e4fbab -r 0684790fff7c VirtualMailManager/__init__.py --- a/VirtualMailManager/__init__.py Wed Feb 10 08:55:51 2010 +0000 +++ b/VirtualMailManager/__init__.py Thu Feb 11 03:08:11 2010 +0000 @@ -12,8 +12,8 @@ from encodings.idna import ToASCII, ToUnicode from VirtualMailManager.constants.ERROR import \ - DOMAIN_INVALID, DOMAIN_TOO_LONG, NOT_EXECUTABLE, NO_SUCH_BINARY, \ - NO_SUCH_DIRECTORY + DOMAIN_INVALID, DOMAIN_TOO_LONG, LOCALPART_INVALID, LOCALPART_TOO_LONG, \ + NOT_EXECUTABLE, NO_SUCH_BINARY, NO_SUCH_DIRECTORY from VirtualMailManager.constants.VERSION import * from VirtualMailManager.Exceptions import VMMException @@ -24,8 +24,8 @@ # version information from VERSION '__author__', '__date__', '__version__', # error codes - 'ENCODING', 'ace2idna', 'chk_domainname', 'exec_ok', 'expand_path', - 'get_unicode', 'idn2ascii', 'is_dir', + 'ENCODING', 'ace2idna', 'check_domainname', 'check_localpart', 'exec_ok', + 'expand_path', 'get_unicode', 'idn2ascii', 'is_dir', ] @@ -37,18 +37,26 @@ locale.setlocale(locale.LC_ALL, 'C') ENCODING = locale.nl_langinfo(locale.CODESET) -RE_ASCII_CHARS = """^[\x20-\x7E]*$""" -RE_DOMAIN = """^(?:[a-z0-9-]{1,63}\.){1,}[a-z]{2,6}$""" +RE_ASCII_CHARS = r"^[\x20-\x7E]*$" +RE_DOMAIN = r"^(?:[a-z0-9-]{1,63}\.){1,}[a-z]{2,6}$" +RE_LOCALPART = r"[^\w!#$%&'\*\+-\.\/=?^_`{\|}~]" + + +# there may be many domain and e-mail address checks +re_obj_domain = re.compile(RE_DOMAIN) +re_obj_localpart = re.compile(RE_LOCALPART) gettext.install('vmm', '/usr/local/share/locale', unicode=1) + def get_unicode(string): """Converts `string` to `unicode`, if necessary.""" if isinstance(string, unicode): return string return unicode(string, ENCODING, 'replace') + def expand_path(path): """Expands paths, starting with ``.`` or ``~``, to an absolute path.""" if path.startswith('.'): @@ -57,6 +65,7 @@ return os.path.expanduser(path) return path + def is_dir(path): """Checks if ``path`` is a directory. @@ -64,10 +73,11 @@ """ path = expand_path(path) if not os.path.isdir(path): - raise VMMException(_(u'“%s” is not a directory') % get_unicode(path), - NO_SUCH_DIRECTORY) + raise VMMException(_(u'“%s” is not a directory') % + get_unicode(path), NO_SUCH_DIRECTORY) return path + def exec_ok(binary): """Checks if the ``binary`` exists and if it is executable. @@ -83,27 +93,49 @@ get_unicode(binary), NOT_EXECUTABLE) return binary + def idn2ascii(domainname): """Converts the idn domain name `domainname` into punycode.""" return '.'.join([ToASCII(lbl) for lbl in domainname.split('.') if lbl]) + def ace2idna(domainname): """Converts the domain name `domainname` from ACE according to IDNA.""" return u'.'.join([ToUnicode(lbl) for lbl in domainname.split('.') if lbl]) -def chk_domainname(domainname): + +def check_domainname(domainname): """Returns the validated domain name `domainname`. It also converts the name of the domain from IDN to ASCII, if necessary. - Throws an VMMException, if the domain name is too long or doesn't look + Throws an `VMMException`, if the domain name is too long or doesn't look like a valid domain name (label.label.label). """ - if not re.match(RE_ASCII_CHARS, domainname): + if not re_obj_domain.match(domainname): domainname = idn2ascii(domainname) if len(domainname) > 255: - raise VMMException(_(u'The domain name is too long.'), DOMAIN_TOO_LONG) - if not re.match(RE_DOMAIN, domainname): - raise VMMException(_(u'The domain name “%s” is invalid.') % domainname, + raise VMMException(_(u'The domain name is too long'), DOMAIN_TOO_LONG) + if not re_obj_domain.match(domainname): + raise VMMException(_(u'The domain name %r is invalid') % domainname, DOMAIN_INVALID) return domainname + + +def check_localpart(localpart): + """Returns the validated local-part *localpart*. + + Throws a `VMMException` if the local-part is too long or contains + invalid characters. + """ + if len(localpart) > 64: + raise VMMException(_(u'The local-part %r is too long') % localpart, + LOCALPART_TOO_LONG) + invalid_chars = set(re_obj_localpart.findall(localpart)) + if invalid_chars: + i_chars = u''.join((u'"%s" ' % c for c in invalid_chars)) + raise VMMException(_(u"The local-part %(l_part)r contains invalid \ +characters: %(i_chars)s") % + {'l_part': localpart, 'i_chars': i_chars}, + LOCALPART_INVALID) + return localpart