VMM/*: Moved some methods from classes to modules __init__.
- Adjusted many import statements.
- Small adjustments and whitespace cosmetics in Config.py
--- a/VirtualMailManager/Account.py Thu Feb 04 19:08:01 2010 +0000
+++ b/VirtualMailManager/Account.py Fri Feb 05 20:13:32 2010 +0000
@@ -4,12 +4,12 @@
"""Virtual Mail Manager's Account class to manage e-mail accounts."""
-from __main__ import ERR
-from Exceptions import VMMAccountException as AccE
-from Domain import Domain
-from Transport import Transport
-from MailLocation import MailLocation
-from EmailAddress import EmailAddress
+import VirtualMailManager.constants.ERROR as ERR
+from VirtualMailManager.Domain import Domain
+from VirtualMailManager.EmailAddress import EmailAddress
+from VirtualMailManager.Exceptions import VMMAccountException as AccE
+from VirtualMailManager.MailLocation import MailLocation
+from VirtualMailManager.Transport import Transport
import VirtualMailManager as VMM
class Account(object):
--- a/VirtualMailManager/Alias.py Thu Feb 04 19:08:01 2010 +0000
+++ b/VirtualMailManager/Alias.py Fri Feb 05 20:13:32 2010 +0000
@@ -4,10 +4,10 @@
"""Virtual Mail Manager's Alias class to manage e-mail aliases."""
-from __main__ import ERR
-from Exceptions import VMMAliasException as VMMAE
-from Domain import Domain
-from EmailAddress import EmailAddress
+import VirtualMailManager.constants.ERROR as ERR
+from VirtualMailManager.Domain import Domain
+from VirtualMailManager.EmailAddress import EmailAddress
+from VirtualMailManager.Exceptions import VMMAliasException as VMMAE
import VirtualMailManager as VMM
class Alias(object):
--- a/VirtualMailManager/AliasDomain.py Thu Feb 04 19:08:01 2010 +0000
+++ b/VirtualMailManager/AliasDomain.py Fri Feb 05 20:13:32 2010 +0000
@@ -4,16 +4,16 @@
"""Virtual Mail Manager's AliasDomain class to manage alias domains."""
-from __main__ import ERR
-from Exceptions import VMMAliasDomainException as VADE
-import VirtualMailManager as VMM
+import VirtualMailManager.constants.ERROR as ERR
+from VirtualMailManager import chk_domainname
+from VirtualMailManager.Exceptions import VMMAliasDomainException as VADE
class AliasDomain(object):
"""Class to manage e-mail alias domains."""
__slots__ = ('__gid', '__name', '_domain', '_dbh')
def __init__(self, dbh, domainname, targetDomain=None):
self._dbh = dbh
- self.__name = VMM.VirtualMailManager.chkDomainname(domainname)
+ self.__name = chk_domainname(domainname)
self.__gid = 0
self._domain = targetDomain
self._exists()
--- a/VirtualMailManager/Config.py Thu Feb 04 19:08:01 2010 +0000
+++ b/VirtualMailManager/Config.py Fri Feb 05 20:13:32 2010 +0000
@@ -36,10 +36,13 @@
from shutil import copy2
from ConfigParser import (Error, MissingSectionHeaderError, NoOptionError,
NoSectionError, ParsingError, RawConfigParser)
-from cStringIO import StringIO
+from cStringIO import StringIO# TODO: move interactive stff to cli
+
+import VirtualMailManager.constants.ERROR as ERR
-from __main__ import os, ENCODING, ERR, get_unicode, w_std
-from Exceptions import VMMConfigException
+from VirtualMailManager import ENCODING, exec_ok, get_unicode, is_dir
+from VirtualMailManager.cli import w_std# move to cli
+from VirtualMailManager.Exceptions import VMMConfigException
class BadOptionError(Error):
@@ -62,9 +65,9 @@
class LazyConfig(RawConfigParser):
"""The **lazy** derivate of the `RawConfigParser`.
-
+
There are two additional getters:
-
+
`LazyConfig.pget()`
The polymorphic getter, which returns a option's value with the
appropriate type.
@@ -127,7 +130,7 @@
* `BadOptionError`
* `NoSectionError`
* `NoOptionError`
- """
+ """
sect_opt = section_option.lower().split('.')
if len(sect_opt) != 2:# do we need a regexp to check the format?
raise BadOptionError(
@@ -158,13 +161,13 @@
def dget(self, option):
"""Returns the value of the `option`.
-
+
If the option could not be found in the configuration file, the
configured default value, from ``LazyConfig._cfg`` will be
returned.
-
+
Arguments:
-
+
`option` : string
the configuration option in the form
"``section``\ **.**\ ``option``"
@@ -188,7 +191,7 @@
def set(self, option, value):
"""Set the value of an option.
-
+
Throws a ``ValueError`` if `value` couldn't be converted to
``LazyConfigOption.cls``"""
section, option = self.__get_section_option(option)
@@ -202,7 +205,7 @@
def has_section(self, section):
"""Checks if ``section`` is a known configuration section."""
- return section.lower() in self._cfg
+ return section.lower() in self._cfg
def has_option(self, option):
"""Checks if the option (section\ **.**\ option) is a known
@@ -214,7 +217,6 @@
return False
-
class LazyConfigOption(object):
"""A simple container class for configuration settings.
@@ -266,7 +268,7 @@
"""Creates a new Config instance
Arguments:
-
+
``filename``
path to the configuration file
"""
@@ -290,11 +292,9 @@
'smtp' : LCO(bool_t, True, self.get_boolean),
},
'bin': {
- 'dovecotpw': LCO(str, '/usr/sbin/dovecotpw', self.get,
- self.exec_ok),
- 'du': LCO(str, '/usr/bin/du', self.get, self.exec_ok),
- 'postconf': LCO(str, '/usr/sbin/postconf', self.get,
- self.exec_ok),
+ 'dovecotpw': LCO(str, '/usr/sbin/dovecotpw', self.get, exec_ok),
+ 'du': LCO(str, '/usr/bin/du', self.get, exec_ok),
+ 'postconf': LCO(str, '/usr/sbin/postconf', self.get, exec_ok),
},
'database': {
'host': LCO(str, 'localhost', self.get),
@@ -313,7 +313,7 @@
'name': LCO(str, 'Maildir', self.get),
},
'misc': {
- 'base_directory': LCO(str, '/srv/mail', self.get, self.is_dir),
+ 'base_directory': LCO(str, '/srv/mail', self.get, is_dir),
'dovecot_version': LCO(int, 12, self.getint),
'gid_mail': LCO(int, 8, self.getint),
'password_scheme': LCO(str, 'CRAM-MD5', self.get,
@@ -341,6 +341,8 @@
Raises a VMMConfigException if the check fails.
"""
+ # TODO: There are only two settings w/o defaults.
+ # So there is no need for cStringIO
if not self.__chkCfg():
errmsg = StringIO()
errmsg.write(_(u'Missing options, which have no default value.\n'))
@@ -356,36 +358,10 @@
"""Returns an iterator object for all configuration sections."""
return self._cfg.iterkeys()
- def is_dir(self, path):
- """Checks if ``path`` is a directory.
-
- Throws a `ConfigValueError` if ``path`` is not a directory.
- """
- path = self.__expand_path(path)
- if not os.path.isdir(path):
- raise ConfigValueError(_(u'“%s” is not a directory') % \
- get_unicode(path))
- return path
-
- def exec_ok(self, binary):
- """Checks if the ``binary`` exists and if it is executable.
-
- Throws a `ConfigValueError` if the ``binary`` isn't a file or is
- not executable.
- """
- binary = self.__expand_path(binary)
- if not os.path.isfile(binary):
- raise ConfigValueError(_(u'“%s” is not a file') % \
- get_unicode(binary))
- if not os.access(binary, os.X_OK):
- raise ConfigValueError(_(u'File is not executable: “%s”') % \
- get_unicode(binary))
- return binary
-
def known_scheme(self, scheme):
"""Converts ``scheme`` to upper case and checks if is known by
Dovecot (listed in VirtualMailManager.SCHEMES).
-
+
Throws a `ConfigValueError` if the scheme is not listed in
VirtualMailManager.SCHEMES.
"""
@@ -404,6 +380,8 @@
Arguments:
sections -- list of strings with section names
"""
+ # TODO: Derivate CliConfig from Config an move the interactive
+ # stuff to CliConfig
input_fmt = _(u'Enter new value for option %(option)s \
[%(current_value)s]: ')
failures = 0
@@ -435,6 +413,7 @@
def __saveChanges(self):
"""Writes changes to the configuration file."""
+ # TODO: Move interactive stuff to CliConfig
copy2(self.__cfgFileName, self.__cfgFileName+'.bak')
self.__cfgFile = open(self.__cfgFileName, 'w')
self.write(self.__cfgFile)
@@ -442,7 +421,7 @@
def __chkCfg(self):
"""Checks all section's options for settings w/o default values.
-
+
Returns ``True`` if everything is fine, else ``False``."""
errors = False
for section in self._cfg.iterkeys():
@@ -456,10 +435,3 @@
self.__missing[section] = missing
return not errors
- def __expand_path(self, path):
- """Expands paths, starting with ``.`` or ``~``, to an absolute path."""
- if path.startswith('.'):
- return os.path.abspath(path)
- if path.startswith('~'):
- return os.path.expanduser(path)
- return path
--- a/VirtualMailManager/Domain.py Thu Feb 04 19:08:01 2010 +0000
+++ b/VirtualMailManager/Domain.py Fri Feb 05 20:13:32 2010 +0000
@@ -6,13 +6,17 @@
from random import choice
-from __main__ import ERR
-from Exceptions import VMMDomainException as VMMDE
-import VirtualMailManager as VMM
-from Transport import Transport
+from VirtualMailManager import chk_domainname
+from VirtualMailManager.constants.ERROR import \
+ ACCOUNT_AND_ALIAS_PRESENT, ACCOUNT_PRESENT, ALIAS_PRESENT, \
+ DOMAIN_ALIAS_EXISTS, DOMAIN_EXISTS, NO_SUCH_DOMAIN
+from VirtualMailManager.Exceptions import VMMDomainException as VMMDE
+from VirtualMailManager.Transport import Transport
+
MAILDIR_CHARS = '0123456789abcdefghijklmnopqrstuvwxyz'
+
class Domain(object):
"""Class to manage e-mail domains."""
__slots__ = ('_basedir','_domaindir','_id','_name','_transport','_dbh')
@@ -25,7 +29,7 @@
transport -- default vmm.cfg/misc/transport (str)
"""
self._dbh = dbh
- self._name = VMM.VirtualMailManager.chkDomainname(domainname)
+ self._name = chk_domainname(domainname)
self._basedir = basedir
if transport is not None:
self._transport = Transport(self._dbh, transport=transport)
@@ -34,8 +38,8 @@
self._id = 0
self._domaindir = None
if not self._exists() and self._isAlias():
- raise VMMDE(_(u"The domain “%s” is an alias domain.") %self._name,
- ERR.DOMAIN_ALIAS_EXISTS)
+ raise VMMDE(_(u"The domain “%s” is an alias domain.") % self._name,
+ DOMAIN_ALIAS_EXISTS)
def _exists(self):
"""Checks if the domain already exists.
@@ -120,13 +124,11 @@
hasAlias = False
if hasUser and hasAlias:
raise VMMDE(_(u'There are accounts and aliases.'),
- ERR.ACCOUNT_AND_ALIAS_PRESENT)
+ ACCOUNT_AND_ALIAS_PRESENT)
elif hasUser:
- raise VMMDE(_(u'There are accounts.'),
- ERR.ACCOUNT_PRESENT)
+ raise VMMDE(_(u'There are accounts.'), ACCOUNT_PRESENT)
elif hasAlias:
- raise VMMDE(_(u'There are aliases.'),
- ERR.ALIAS_PRESENT)
+ raise VMMDE(_(u'There are aliases.'), ALIAS_PRESENT)
def save(self):
"""Stores the new domain in the database."""
@@ -141,7 +143,7 @@
dbc.close()
else:
raise VMMDE(_(u'The domain “%s” already exists.') % self._name,
- ERR.DOMAIN_EXISTS)
+ DOMAIN_EXISTS)
def delete(self, delUser=False, delAlias=False):
"""Deletes the domain.
@@ -159,7 +161,7 @@
dbc.close()
else:
raise VMMDE(_(u"The domain “%s” doesn't exist.") % self._name,
- ERR.NO_SUCH_DOMAIN)
+ NO_SUCH_DOMAIN)
def updateTransport(self, transport, force=False):
"""Sets a new transport for the domain.
@@ -185,7 +187,7 @@
dbc.close()
else:
raise VMMDE(_(u"The domain “%s” doesn't exist.") % self._name,
- ERR.NO_SUCH_DOMAIN)
+ NO_SUCH_DOMAIN)
def getID(self):
"""Returns the ID of the domain."""
@@ -216,7 +218,7 @@
dbc.close()
if info is None:
raise VMMDE(_(u"The domain “%s” doesn't exist.") % self._name,
- ERR.NO_SUCH_DOMAIN)
+ NO_SUCH_DOMAIN)
else:
keys = ['gid', 'domainname', 'transport', 'domaindir',
'aliasdomains', 'accounts', 'aliases', 'relocated']
@@ -278,7 +280,7 @@
def search(dbh, pattern=None, like=False):
if pattern is not None and like is False:
- pattern = VMM.VirtualMailManager.chkDomainname(pattern)
+ pattern = chk_domainname(pattern)
sql = 'SELECT gid, domainname, is_primary FROM domain_name'
if pattern is None:
pass
--- a/VirtualMailManager/EmailAddress.py Thu Feb 04 19:08:01 2010 +0000
+++ b/VirtualMailManager/EmailAddress.py Fri Feb 05 20:13:32 2010 +0000
@@ -4,9 +4,11 @@
"""Virtual Mail Manager's EmailAddress class to handle e-mail addresses."""
-from __main__ import re, ERR
-from Exceptions import VMMEmailAddressException as VMMEAE
-import VirtualMailManager as VMM
+import re
+
+import VirtualMailManager.constants.ERROR as ERR
+from VirtualMailManager import chk_domainname
+from VirtualMailManager.Exceptions import VMMEmailAddressException as VMMEAE
RE_LOCALPART = """[^\w!#$%&'\*\+-\.\/=?^_`{\|}~]"""
@@ -40,15 +42,15 @@
localpart, domain = address.split('@')
except ValueError:
raise VMMEAE(_(u"Missing '@' sign in e-mail address “%s”.") %
- address, ERR.INVALID_ADDRESS)
+ address, ERR.INVALID_ADDRESS)
except AttributeError:
raise VMMEAE(_(u"“%s” doesn't look like an e-mail address.") %
- address, ERR.INVALID_ADDRESS)
+ address, ERR.INVALID_ADDRESS)
if len(domain) > 0:
- domain = VMM.VirtualMailManager.chkDomainname(domain)
+ domain = chk_domainname(domain)
else:
- raise VMMEAE(_(u"Missing domain name after “%s@”.") %
- localpart, ERR.DOMAIN_NO_NAME)
+ raise VMMEAE(_(u"Missing domain name after “%s@”.") % localpart,
+ ERR.DOMAIN_NO_NAME)
localpart = self.__chkLocalpart(localpart)
self._localpart, self._domainname = localpart, domain
--- a/VirtualMailManager/MailLocation.py Thu Feb 04 19:08:01 2010 +0000
+++ b/VirtualMailManager/MailLocation.py Fri Feb 05 20:13:32 2010 +0000
@@ -5,8 +5,10 @@
"""Virtual Mail Manager's MailLocation class to manage the mail_location
for accounts."""
-from __main__ import re, ERR
-from Exceptions import VMMMailLocationException as MLE
+import re
+
+import VirtualMailManager.constants.ERROR as ERR
+from VirtualMailManager.Exceptions import VMMMailLocationException as MLE
RE_MAILLOCATION = """^\w{1,20}$"""
--- a/VirtualMailManager/Relocated.py Thu Feb 04 19:08:01 2010 +0000
+++ b/VirtualMailManager/Relocated.py Fri Feb 05 20:13:32 2010 +0000
@@ -4,10 +4,10 @@
"""Virtual Mail Manager's Relocated class to manage relocated users."""
-from __main__ import ERR
-from Exceptions import VMMRelocatedException as VMMRE
-from Domain import Domain
-from EmailAddress import EmailAddress
+import VirtualMailManager.constants.ERROR as ERR
+from VirtualMailManager.Domain import Domain
+from VirtualMailManager.EmailAddress import EmailAddress
+from VirtualMailManager.Exceptions import VMMRelocatedException as VMMRE
import VirtualMailManager as VMM
class Relocated(object):
--- a/VirtualMailManager/Transport.py Thu Feb 04 19:08:01 2010 +0000
+++ b/VirtualMailManager/Transport.py Fri Feb 05 20:13:32 2010 +0000
@@ -5,8 +5,8 @@
"""Virtual Mail Manager's Transport class to manage the transport for
domains and accounts."""
-from __main__ import ERR
-from Exceptions import VMMTransportException
+import VirtualMailManager.constants.ERROR as ERR
+from VirtualMailManager.Exceptions import VMMTransportException
class Transport(object):
"""A wrapper class that provides access to the transport table"""
--- a/VirtualMailManager/__init__.py Thu Feb 04 19:08:01 2010 +0000
+++ b/VirtualMailManager/__init__.py Fri Feb 05 20:13:32 2010 +0000
@@ -8,8 +8,25 @@
import re
import locale
-from constants.VERSION import *
-import constants.ERROR as ERR
+from encodings.idna import ToASCII, ToUnicode
+
+from VirtualMailManager.constants.ERROR import \
+ DOMAIN_INVALID, DOMAIN_TOO_LONG, NOT_EXECUTABLE, NO_SUCH_BINARY, \
+ NO_SUCH_DIRECTORY
+from VirtualMailManager.constants.VERSION import *
+from VirtualMailManager.Exceptions import VMMException
+
+
+__all__ = [
+ # imported modules
+ 'os', 're', 'locale',
+ # version information from VERSION
+ '__author__', '__date__', '__version__',
+ # error codes
+ 'ENCODING', 'ace2idna', 'chk_domainname', 'exec_ok', 'expand_path',
+ 'get_unicode', 'idn2ascii', 'is_dir',
+]
+
# Try to set all of the locales according to the current
# environment variables and get the character encoding.
@@ -19,24 +36,9 @@
locale.setlocale(locale.LC_ALL, 'C')
ENCODING = locale.nl_langinfo(locale.CODESET)
-def w_std(*args):
- """Writes each arg of args, encoded in the current ENCODING, to stdout and
- appends a newline."""
- _write = os.sys.stdout.write
- for arg in args:
- _write(arg.encode(ENCODING, 'replace'))
- _write('\n')
+RE_ASCII_CHARS = """^[\x20-\x7E]*$"""
+RE_DOMAIN = """^(?:[a-z0-9-]{1,63}\.){1,}[a-z]{2,6}$"""
-def w_err(code, *args):
- """Writes each arg of args, encoded in the current ENCODING, to stderr and
- appends a newline.
- This function additional interrupts the program execution and uses 'code'
- system exit status."""
- _write = os.sys.stderr.write
- for arg in args:
- _write(arg.encode(ENCODING, 'replace'))
- _write('\n')
- os.sys.exit(code)
def get_unicode(string):
"""Converts `string` to `unicode`, if necessary."""
@@ -44,14 +46,61 @@
return string
return unicode(string, ENCODING, 'replace')
-__all__ = [
- # imported modules
- 'os', 're', 'locale',
- # version information from VERSION
- '__author__', '__date__', '__version__',
- # error codes
- 'ERR',
- # defined stuff
- 'ENCODING', 'get_unicode', 'w_std', 'w_err'
- ]
-# EOF
+def expand_path(path):
+ """Expands paths, starting with ``.`` or ``~``, to an absolute path."""
+ if path.startswith('.'):
+ return os.path.abspath(path)
+ if path.startswith('~'):
+ return os.path.expanduser(path)
+ return path
+
+def is_dir(path):
+ """Checks if ``path`` is a directory.
+
+ Throws a `VMMException` if ``path`` is not a directory.
+ """
+ path = expand_path(path)
+ if not os.path.isdir(path):
+ 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.
+
+ Throws a `VMMException` if the ``binary`` isn't a file or is not
+ executable.
+ """
+ binary = expand_path(binary)
+ if not os.path.isfile(binary):
+ raise VMMException(_(u'“%s” is not a file') % get_unicode(binary),
+ NO_SUCH_BINARY)
+ if not os.access(binary, os.X_OK):
+ raise VMMException(_(u'File is not executable: “%s”') % \
+ 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):
+ """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
+ like a valid domain name (label.label.label).
+ """
+ if not re.match(RE_ASCII_CHARS, 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,
+ DOMAIN_INVALID)
+ return domainname
--- a/VirtualMailManager/cli/handler.py Thu Feb 04 19:08:01 2010 +0000
+++ b/VirtualMailManager/cli/handler.py Fri Feb 05 20:13:32 2010 +0000
@@ -2,40 +2,49 @@
# Copyright (c) 2007 - 2010, Pascal Volk
# See COPYING for distribution information.
-"""The main class for vmm."""
+"""
+ VirtualMailManager.Handler
+ A wrapper class. It wraps round all other classes and does some
+ dependencies checks.
-from encodings.idna import ToASCII, ToUnicode
-from getpass import getpass
+ Additionally it communicates with the PostgreSQL database, creates
+ or deletes directories of domains or users.
+"""
+
+import os
+import re
+
from shutil import rmtree
from subprocess import Popen, PIPE
from pyPgSQL import PgSQL # python-pgsql - http://pypgsql.sourceforge.net
-from __main__ import os, re, ENCODING, ERR, w_std
-from ext.Postconf import Postconf
-from Account import Account
-from Alias import Alias
-from AliasDomain import AliasDomain
-from Config import Config as Cfg
-from Domain import Domain
-from EmailAddress import EmailAddress
-from Exceptions import *
-from Relocated import Relocated
+import VirtualMailManager.constants.ERROR as ERR
+from VirtualMailManager import ENCODING, ace2idna, exec_ok, read_pass
+from VirtualMailManager.Account import Account
+from VirtualMailManager.Alias import Alias
+from VirtualMailManager.AliasDomain import AliasDomain
+from VirtualMailManager.Config import Config as Cfg
+from VirtualMailManager.Domain import Domain
+from VirtualMailManager.EmailAddress import EmailAddress
+from VirtualMailManager.Exceptions import *
+from VirtualMailManager.Relocated import Relocated
+from VirtualMailManager.ext.Postconf import Postconf
SALTCHARS = './0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
-RE_ASCII_CHARS = """^[\x20-\x7E]*$"""
-RE_DOMAIN = """^(?:[a-z0-9-]{1,63}\.){1,}[a-z]{2,6}$"""
RE_DOMAIN_SRCH = """^[a-z0-9-\.]+$"""
RE_LOCALPART = """[^\w!#$%&'\*\+-\.\/=?^_`{\|}~]"""
RE_MBOX_NAMES = """^[\x20-\x25\x27-\x7E]*$"""
-class VirtualMailManager(object):
- """The main class for vmm"""
+class Handler(object):
+ """Wrapper class to simplify the access on all the stuff from
+ VirtualMailManager"""
+ # TODO: accept a LazyConfig object as argument
__slots__ = ('__Cfg', '__cfgFileName', '__dbh', '__scheme', '__warnings',
'_postconf')
def __init__(self):
- """Creates a new VirtualMailManager instance.
+ """Creates a new Handler instance.
Throws a VMMNotRootException if your uid is greater 0.
"""
self.__cfgFileName = ''
@@ -93,18 +102,25 @@
(vmm.cfg: section "misc", option "base_directory")') %
basedir, ERR.NO_SUCH_DIRECTORY)
for opt, val in self.__Cfg.items('bin'):
- if not os.path.exists(val):
- raise VMMException(_(u'“%(binary)s” doesn\'t exist.\n\
+ try:
+ exec_ok(val)
+ except VMMException, e:
+ code = e.code()
+ if code is ERR.NO_SUCH_BINARY:
+ raise VMMException(_(u'“%(binary)s” doesn\'t exist.\n\
(vmm.cfg: section "bin", option "%(option)s")') %{'binary': val,'option': opt},
- ERR.NO_SUCH_BINARY)
- elif not os.access(val, os.X_OK):
- raise VMMException(_(u'“%(binary)s” is not executable.\n\
+ ERR.NO_SUCH_BINARY)
+ elif code is ERR.NOT_EXECUTABLE:
+ raise VMMException(_(u'“%(binary)s” is not executable.\n\
(vmm.cfg: section "bin", option "%(option)s")') %{'binary': val,'option': opt},
- ERR.NOT_EXECUTABLE)
+ ERR.NOT_EXECUTABLE)
+ else:
+ raise
def __dbConnect(self):
"""Creates a pyPgSQL.PgSQL.connection instance."""
- if self.__dbh is None or not self.__dbh._isOpen:
+ if self.__dbh is None or (isinstance(self.__dbh, PgSQL.Connection) and
+ not self.__dbh._isOpen):
try:
self.__dbh = PgSQL.connect(
database=self.__Cfg.dget('database.name'),
@@ -118,42 +134,6 @@
except PgSQL.libpq.DatabaseError, e:
raise VMMException(str(e), ERR.DATABASE_ERROR)
- def idn2ascii(domainname):
- """Converts an idn domainname in punycode.
-
- Arguments:
- domainname -- the domainname to convert (unicode)
- """
- return '.'.join([ToASCII(lbl) for lbl in domainname.split('.') if lbl])
- idn2ascii = staticmethod(idn2ascii)
-
- def ace2idna(domainname):
- """Convertis a domainname from ACE according to IDNA
-
- Arguments:
- domainname -- the domainname to convert (str)
- """
- return u'.'.join([ToUnicode(lbl) for lbl in domainname.split('.')\
- if lbl])
- ace2idna = staticmethod(ace2idna)
-
- def chkDomainname(domainname):
- """Validates the domain name of an e-mail address.
-
- Keyword arguments:
- domainname -- the domain name that should be validated
- """
- if not re.match(RE_ASCII_CHARS, domainname):
- domainname = VirtualMailManager.idn2ascii(domainname)
- if len(domainname) > 255:
- raise VMMException(_(u'The domain name is too long.'),
- ERR.DOMAIN_TOO_LONG)
- if not re.match(RE_DOMAIN, domainname):
- raise VMMException(_(u'The domain name “%s” is invalid.') %\
- domainname, ERR.DOMAIN_INVALID)
- return domainname
- chkDomainname = staticmethod(chkDomainname)
-
def _exists(dbh, query):
dbc = dbh.cursor()
dbc.execute(query)
@@ -169,46 +149,23 @@
sql = "SELECT gid FROM users WHERE gid = (SELECT gid FROM domain_name\
WHERE domainname = '%s') AND local_part = '%s'" % (address._domainname,
address._localpart)
- return VirtualMailManager._exists(dbh, sql)
+ return Handler._exists(dbh, sql)
accountExists = staticmethod(accountExists)
def aliasExists(dbh, address):
sql = "SELECT DISTINCT gid FROM alias WHERE gid = (SELECT gid FROM\
domain_name WHERE domainname = '%s') AND address = '%s'" %\
(address._domainname, address._localpart)
- return VirtualMailManager._exists(dbh, sql)
+ return Handler._exists(dbh, sql)
aliasExists = staticmethod(aliasExists)
def relocatedExists(dbh, address):
sql = "SELECT gid FROM relocated WHERE gid = (SELECT gid FROM\
domain_name WHERE domainname = '%s') AND address = '%s'" %\
(address._domainname, address._localpart)
- return VirtualMailManager._exists(dbh, sql)
+ return Handler._exists(dbh, sql)
relocatedExists = staticmethod(relocatedExists)
- def _readpass(self):
- # TP: Please preserve the trailing space.
- readp_msg0 = _(u'Enter new password: ').encode(ENCODING, 'replace')
- # TP: Please preserve the trailing space.
- readp_msg1 = _(u'Retype new password: ').encode(ENCODING, 'replace')
- mismatched = True
- flrs = 0
- while mismatched:
- if flrs > 2:
- raise VMMException(_(u'Too many failures - try again later.'),
- ERR.VMM_TOO_MANY_FAILURES)
- clear0 = getpass(prompt=readp_msg0)
- clear1 = getpass(prompt=readp_msg1)
- if clear0 != clear1:
- flrs += 1
- w_std(_(u'Sorry, passwords do not match'))
- continue
- if len(clear0) < 1:
- flrs += 1
- w_std(_(u'Sorry, empty passwords are not permitted'))
- continue
- mismatched = False
- return clear0
def __getAccount(self, address, password=None):
self.__dbConnect()
@@ -500,8 +457,7 @@
dom = self.__getDomain(domainname)
dominfo = dom.getInfo()
if dominfo['domainname'].startswith('xn--'):
- dominfo['domainname'] += ' (%s)'\
- % VirtualMailManager.ace2idna(dominfo['domainname'])
+ dominfo['domainname'] += ' (%s)' % ace2idna(dominfo['domainname'])
if details is None:
return dominfo
elif details == 'accounts':
@@ -575,7 +531,7 @@
def userAdd(self, emailaddress, password):
acc = self.__getAccount(emailaddress, password)
if password is None:
- password = self._readpass()
+ password = read_pass()
acc.setPassword(self.__pwhash(password))
acc.save(self.__Cfg.dget('maildir.name'),
self.__Cfg.dget('misc.dovecot_version'),
@@ -589,8 +545,8 @@
alias = self.__getAlias(aliasaddress, targetaddress)
alias.save(long(self._postconf.read('virtual_alias_expansion_limit')))
gid = self.__getDomain(alias._dest._domainname).getID()
- if gid > 0 and not VirtualMailManager.accountExists(self.__dbh,
- alias._dest) and not VirtualMailManager.aliasExists(self.__dbh,
+ if gid > 0 and not Handler.accountExists(self.__dbh,
+ alias._dest) and not Handler.aliasExists(self.__dbh,
alias._dest):
self.__warnings.append(
_(u"The destination account/alias “%s” doesn't exist.")%\
@@ -642,7 +598,7 @@
return info
def userByID(self, uid):
- from Account import getAccountByID
+ from Handler.Account import getAccountByID
self.__dbConnect()
return getAccountByID(uid, self.__dbh)
@@ -651,7 +607,7 @@
if acc.getUID() == 0:
raise VMMException(_(u"Account doesn't exist"), ERR.NO_SUCH_ACCOUNT)
if password is None:
- password = self._readpass()
+ password = read_pass()
acc.modify('password', self.__pwhash(password, user=emailaddress))
def userName(self, emailaddress, name):
@@ -695,5 +651,5 @@
relocated.delete()
def __del__(self):
- if not self.__dbh is None and self.__dbh._isOpen:
+ if isinstance(self.__dbh, PgSQL.Connection) and self.__dbh._isOpen:
self.__dbh.close()
--- a/VirtualMailManager/ext/Postconf.py Thu Feb 04 19:08:01 2010 +0000
+++ b/VirtualMailManager/ext/Postconf.py Fri Feb 05 20:13:32 2010 +0000
@@ -4,9 +4,10 @@
"""A small - r/o - wrapper class for Postfix' postconf."""
+import re
from subprocess import Popen, PIPE
-from __main__ import re, ERR
+import VirtualMailManager.constants.ERROR as ERR
from VirtualMailManager.Exceptions import VMMException
RE_PC_PARAMS = """^\w+$"""
--- a/vmm Thu Feb 04 19:08:01 2010 +0000
+++ b/vmm Fri Feb 05 20:13:32 2010 +0000
@@ -9,6 +9,10 @@
from time import strftime, strptime
from VirtualMailManager import *
+from VirtualMailManager.cli import w_std, w_err
+
+
+# TODO: FIXME
from VirtualMailManager.VirtualMailManager import VirtualMailManager
import VirtualMailManager.Exceptions as VMME
import VirtualMailManager.constants.EXIT as EXIT
@@ -123,7 +127,7 @@
if not dom.startswith('xn--'):
w_std(u'\t%s' % dom)
else:
- w_std(u'\t%s (%s)' % (dom, vmm.ace2idna(dom)))
+ w_std(u'\t%s (%s)' % (dom, ace2idna(dom)))
else:
w_std(_(u'\tNone'))
print
@@ -147,7 +151,7 @@
def _formatDom(domain, main=True):
if domain.startswith('xn--'):
- domain = u'%s (%s)' % (domain, vmm.ace2idna(domain))
+ domain = u'%s (%s)' % (domain, ace2idna(domain))
if main:
return u'\t[+] %s' % domain
else:
@@ -174,7 +178,7 @@
msg = _('Alias domain information')
for k in ['alias', 'domain']:
if info[k].startswith('xn--'):
- info[k] = "%s (%s)" % (info[k], vmm.ace2idna(info[k]))
+ info[k] = "%s (%s)" % (info[k], ace2idna(info[k]))
w_std('%s\n%s' % (msg, '-'*len(msg)))
w_std(
_('\tThe alias domain %(alias)s belongs to:\n\t * %(domain)s')%info)