--- 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