VirtualMailManager/handler.py
branchv0.6.x
changeset 355 48bf20b43f2e
parent 351 4bba5fb90b78
child 366 d6573da35b5f
equal deleted inserted replaced
354:a653c43048b1 355:48bf20b43f2e
    15 import os
    15 import os
    16 import re
    16 import re
    17 
    17 
    18 from shutil import rmtree
    18 from shutil import rmtree
    19 from subprocess import Popen, PIPE
    19 from subprocess import Popen, PIPE
    20 
       
    21 from pyPgSQL import PgSQL  # python-pgsql - http://pypgsql.sourceforge.net
       
    22 
    20 
    23 from VirtualMailManager.account import Account
    21 from VirtualMailManager.account import Account
    24 from VirtualMailManager.alias import Alias
    22 from VirtualMailManager.alias import Alias
    25 from VirtualMailManager.aliasdomain import AliasDomain
    23 from VirtualMailManager.aliasdomain import AliasDomain
    26 from VirtualMailManager.common import exec_ok, lisdir
    24 from VirtualMailManager.common import exec_ok, lisdir
    28 from VirtualMailManager.constants import MIN_GID, MIN_UID, \
    26 from VirtualMailManager.constants import MIN_GID, MIN_UID, \
    29      ACCOUNT_EXISTS, ALIAS_EXISTS, CONF_NOFILE, CONF_NOPERM, CONF_WRONGPERM, \
    27      ACCOUNT_EXISTS, ALIAS_EXISTS, CONF_NOFILE, CONF_NOPERM, CONF_WRONGPERM, \
    30      DATABASE_ERROR, DOMAINDIR_GROUP_MISMATCH, DOMAIN_INVALID, \
    28      DATABASE_ERROR, DOMAINDIR_GROUP_MISMATCH, DOMAIN_INVALID, \
    31      FOUND_DOTS_IN_PATH, INVALID_ARGUMENT, MAILDIR_PERM_MISMATCH, \
    29      FOUND_DOTS_IN_PATH, INVALID_ARGUMENT, MAILDIR_PERM_MISMATCH, \
    32      NOT_EXECUTABLE, NO_SUCH_ACCOUNT, NO_SUCH_ALIAS, NO_SUCH_BINARY, \
    30      NOT_EXECUTABLE, NO_SUCH_ACCOUNT, NO_SUCH_ALIAS, NO_SUCH_BINARY, \
    33      NO_SUCH_DIRECTORY, NO_SUCH_RELOCATED, RELOCATED_EXISTS
    31      NO_SUCH_DIRECTORY, NO_SUCH_RELOCATED, RELOCATED_EXISTS, VMM_ERROR
    34 from VirtualMailManager.domain import Domain, get_gid
    32 from VirtualMailManager.domain import Domain, get_gid
    35 from VirtualMailManager.emailaddress import EmailAddress
    33 from VirtualMailManager.emailaddress import EmailAddress
    36 from VirtualMailManager.errors import \
    34 from VirtualMailManager.errors import \
    37      DomainError, NotRootError, PermissionError, VMMError
    35      DomainError, NotRootError, PermissionError, VMMError
    38 from VirtualMailManager.mailbox import new as new_mailbox
    36 from VirtualMailManager.mailbox import new as new_mailbox
    40 from VirtualMailManager.relocated import Relocated
    38 from VirtualMailManager.relocated import Relocated
    41 from VirtualMailManager.transport import Transport
    39 from VirtualMailManager.transport import Transport
    42 
    40 
    43 
    41 
    44 _ = lambda msg: msg
    42 _ = lambda msg: msg
       
    43 _db_mod = None
    45 
    44 
    46 CFG_FILE = 'vmm.cfg'
    45 CFG_FILE = 'vmm.cfg'
    47 CFG_PATH = '/root:/usr/local/etc:/etc'
    46 CFG_PATH = '/root:/usr/local/etc:/etc'
    48 RE_DOMAIN_SEARCH = """^[a-z0-9-\.]+$"""
    47 RE_DOMAIN_SEARCH = """^[a-z0-9-\.]+$"""
    49 TYPE_ACCOUNT = 0x1
    48 TYPE_ACCOUNT = 0x1
    57 
    56 
    58 
    57 
    59 class Handler(object):
    58 class Handler(object):
    60     """Wrapper class to simplify the access on all the stuff from
    59     """Wrapper class to simplify the access on all the stuff from
    61     VirtualMailManager"""
    60     VirtualMailManager"""
    62     __slots__ = ('_cfg', '_cfg_fname', '_dbh', '_warnings')
    61     __slots__ = ('_cfg', '_cfg_fname', '_db_connect', '_dbh', '_warnings')
    63 
    62 
    64     def __init__(self, skip_some_checks=False):
    63     def __init__(self, skip_some_checks=False):
    65         """Creates a new Handler instance.
    64         """Creates a new Handler instance.
    66 
    65 
    67         ``skip_some_checks`` : bool
    66         ``skip_some_checks`` : bool
    73         """
    72         """
    74         self._cfg_fname = ''
    73         self._cfg_fname = ''
    75         self._warnings = []
    74         self._warnings = []
    76         self._cfg = None
    75         self._cfg = None
    77         self._dbh = None
    76         self._dbh = None
       
    77         self._db_connect = None
    78 
    78 
    79         if os.geteuid():
    79         if os.geteuid():
    80             raise NotRootError(_(u"You are not root.\n\tGood bye!\n"),
    80             raise NotRootError(_(u"You are not root.\n\tGood bye!\n"),
    81                                CONF_NOPERM)
    81                                CONF_NOPERM)
    82         if self._check_cfg_file():
    82         if self._check_cfg_file():
    83             self._cfg = Cfg(self._cfg_fname)
    83             self._cfg = Cfg(self._cfg_fname)
    84             self._cfg.load()
    84             self._cfg.load()
    85         if not skip_some_checks:
    85         if not skip_some_checks:
    86             self._cfg.check()
    86             self._cfg.check()
    87             self._chkenv()
    87             self._chkenv()
       
    88             self._set_db_connect()
    88 
    89 
    89     def _find_cfg_file(self):
    90     def _find_cfg_file(self):
    90         """Search the CFG_FILE in CFG_PATH.
    91         """Search the CFG_FILE in CFG_PATH.
    91         Raise a VMMError when no vmm.cfg could be found.
    92         Raise a VMMError when no vmm.cfg could be found.
    92         """
    93         """
   141                                    {'cfg_file': self._cfg_fname,
   142                                    {'cfg_file': self._cfg_fname,
   142                                     'option': opt}, err.code)
   143                                     'option': opt}, err.code)
   143                 else:
   144                 else:
   144                     raise
   145                     raise
   145 
   146 
   146     def _db_connect(self):
   147     def _set_db_connect(self):
       
   148         """check which module to use and set self._db_connect"""
       
   149         global _db_mod
       
   150         if self._cfg.dget('database.module').lower() == 'psycopg2':
       
   151             try:
       
   152                 _db_mod = __import__('psycopg2')
       
   153             except ImportError:
       
   154                 raise VMMError(_(u"Unable to import database module '%s'") %
       
   155                                'psycopg2', VMM_ERROR)
       
   156             self._db_connect = self._psycopg2_connect
       
   157         else:
       
   158             try:
       
   159                 tmp = __import__('pyPgSQL', globals(), locals(), ['PgSQL'])
       
   160             except ImportError:
       
   161                 raise VMMError(_(u"Unable to import database module '%s'") %
       
   162                                'pyPgSQL', VMM_ERROR)
       
   163             _db_mod = tmp.PgSQL
       
   164             self._db_connect = self._pypgsql_connect
       
   165 
       
   166     def _pypgsql_connect(self):
   147         """Creates a pyPgSQL.PgSQL.connection instance."""
   167         """Creates a pyPgSQL.PgSQL.connection instance."""
   148         if self._dbh is None or (isinstance(self._dbh, PgSQL.Connection) and
   168         if self._dbh is None or (isinstance(self._dbh, _db_mod.Connection) and
   149                                   not self._dbh._isOpen):
   169                                   not self._dbh._isOpen):
   150             try:
   170             try:
   151                 self._dbh = PgSQL.connect(
   171                 self._dbh = _db_mod.connect(
   152                         database=self._cfg.dget('database.name'),
   172                         database=self._cfg.dget('database.name'),
   153                         user=self._cfg.pget('database.user'),
   173                         user=self._cfg.pget('database.user'),
   154                         host=self._cfg.dget('database.host'),
   174                         host=self._cfg.dget('database.host'),
       
   175                         port=self._cfg.dget('database.port'),
   155                         password=self._cfg.pget('database.pass'),
   176                         password=self._cfg.pget('database.pass'),
   156                         client_encoding='utf8', unicode_results=True)
   177                         client_encoding='utf8', unicode_results=True)
   157                 dbc = self._dbh.cursor()
   178                 dbc = self._dbh.cursor()
   158                 dbc.execute("SET NAMES 'UTF8'")
   179                 dbc.execute("SET NAMES 'UTF8'")
   159                 dbc.close()
   180                 dbc.close()
   160             except PgSQL.libpq.DatabaseError, err:
   181             except _db_mod.libpq.DatabaseError, err:
       
   182                 raise VMMError(str(err), DATABASE_ERROR)
       
   183 
       
   184     def _psycopg2_connect(self):
       
   185         """Return a new psycopg2 connection object."""
       
   186         if self._dbh is None or \
       
   187           (isinstance(self._dbh, _db_mod.extensions.connection) and
       
   188            self._dbh.closed):
       
   189             try:
       
   190                 self._dbh = _db_mod.connect(
       
   191                         host=self._cfg.dget('database.host'),
       
   192                         sslmode=self._cfg.dget('database.sslmode'),
       
   193                         port=self._cfg.dget('database.port'),
       
   194                         database=self._cfg.dget('database.name'),
       
   195                         user=self._cfg.pget('database.user'),
       
   196                         password=self._cfg.pget('database.pass'))
       
   197                 self._dbh.set_client_encoding('utf8')
       
   198                 _db_mod.extensions.register_type(_db_mod.extensions.UNICODE)
       
   199                 dbc = self._dbh.cursor()
       
   200                 dbc.execute("SET NAMES 'UTF8'")
       
   201                 dbc.close()
       
   202             except _db_mod.DatabaseError, err:
   161                 raise VMMError(str(err), DATABASE_ERROR)
   203                 raise VMMError(str(err), DATABASE_ERROR)
   162 
   204 
   163     def _chk_other_address_types(self, address, exclude):
   205     def _chk_other_address_types(self, address, exclude):
   164         """Checks if the EmailAddress *address* is known as `TYPE_ACCOUNT`,
   206         """Checks if the EmailAddress *address* is known as `TYPE_ACCOUNT`,
   165         `TYPE_ALIAS` or `TYPE_RELOCATED`, but not as the `TYPE_*` specified
   207         `TYPE_ALIAS` or `TYPE_RELOCATED`, but not as the `TYPE_*` specified