VirtualMailManager/Handler.py
branchv0.6.x
changeset 277 e50ffc0b8468
parent 272 446483386914
child 278 5d229a50b115
equal deleted inserted replaced
276:f2ecfe0a0e09 277:e50ffc0b8468
    40 RE_DOMAIN_SEARCH = """^[a-z0-9-\.]+$"""
    40 RE_DOMAIN_SEARCH = """^[a-z0-9-\.]+$"""
    41 RE_MBOX_NAMES = """^[\x20-\x25\x27-\x7E]*$"""
    41 RE_MBOX_NAMES = """^[\x20-\x25\x27-\x7E]*$"""
    42 TYPE_ACCOUNT = 0x1
    42 TYPE_ACCOUNT = 0x1
    43 TYPE_ALIAS = 0x2
    43 TYPE_ALIAS = 0x2
    44 TYPE_RELOCATED = 0x4
    44 TYPE_RELOCATED = 0x4
       
    45 _ = lambda msg: msg
    45 
    46 
    46 
    47 
    47 class Handler(object):
    48 class Handler(object):
    48     """Wrapper class to simplify the access on all the stuff from
    49     """Wrapper class to simplify the access on all the stuff from
    49     VirtualMailManager"""
    50     VirtualMailManager"""
   170             relocated = Relocated(self._dbh, address)
   171             relocated = Relocated(self._dbh, address)
   171             if relocated:
   172             if relocated:
   172                 return TYPE_RELOCATED
   173                 return TYPE_RELOCATED
   173         return 0
   174         return 0
   174 
   175 
   175     def __getAccount(self, address, password=None):
   176     def __getAccount(self, address):
   176         address = EmailAddress(address)
   177         address = EmailAddress(address)
   177         if not password is None:
       
   178             password = self.__pwhash(password)
       
   179         self.__dbConnect()
   178         self.__dbConnect()
   180         return Account(self._dbh, address, password)
   179         return Account(self._dbh, address)
   181 
   180 
   182     def __getAlias(self, address):
   181     def __getAlias(self, address):
   183         address = EmailAddress(address)
   182         address = EmailAddress(address)
   184         self.__dbConnect()
   183         self.__dbConnect()
   185         return Alias(self._dbh, address)
   184         return Alias(self._dbh, address)
   254         Keyword arguments:
   253         Keyword arguments:
   255         domdir -- the path to the domain directory
   254         domdir -- the path to the domain directory
   256         uid -- user id from the account
   255         uid -- user id from the account
   257         gid -- group id from the account
   256         gid -- group id from the account
   258         """
   257         """
       
   258         #  obsolete -> (mailbox / maillocation)
       
   259         return
   259         os.umask(0007)
   260         os.umask(0007)
   260         oldpwd = os.getcwd()
   261         oldpwd = os.getcwd()
   261         os.chdir(domdir)
   262         os.chdir(domdir)
   262 
   263 
   263         maildir = self._Cfg.dget('maildir.name')
   264         maildir = self._Cfg.dget('maildir.name')
   532                         _(u"The pattern '%s' contains invalid characters.") %
   533                         _(u"The pattern '%s' contains invalid characters.") %
   533                                pattern, ERR.DOMAIN_INVALID)
   534                                pattern, ERR.DOMAIN_INVALID)
   534         self.__dbConnect()
   535         self.__dbConnect()
   535         return search(self._dbh, pattern=pattern, like=like)
   536         return search(self._dbh, pattern=pattern, like=like)
   536 
   537 
   537     def userAdd(self, emailaddress, password):
   538     def user_add(self, emailaddress, password):
   538         if password is None or (isinstance(password, basestring) and
   539         """Wrapper around Account.set_password() and Account.save()."""
   539                                 not len(password)):
   540         acc = self.__getAccount(emailaddress)
   540             raise ValueError('could not accept password: %r' % password)
   541         acc.set_password(password)
   541         acc = self.__getAccount(emailaddress, self.__pwhash(password))
   542         acc.save()
   542         acc.save(self._Cfg.dget('maildir.name'),
   543         #  depends on modules mailbox and maillocation
   543                  self._Cfg.dget('misc.dovecot_version'),
   544         #  self.__mailDirMake(acc.domain_directory, acc.uid, acc.gid)
   544                  self._Cfg.dget('account.smtp'),
       
   545                  self._Cfg.dget('account.pop3'),
       
   546                  self._Cfg.dget('account.imap'),
       
   547                  self._Cfg.dget('account.sieve'))
       
   548         self.__mailDirMake(acc.getDir('domain'), acc.getUID(), acc.getGID())
       
   549 
   545 
   550     def aliasAdd(self, aliasaddress, *targetaddresses):
   546     def aliasAdd(self, aliasaddress, *targetaddresses):
   551         """Creates a new `Alias` entry for the given *aliasaddress* with
   547         """Creates a new `Alias` entry for the given *aliasaddress* with
   552         the given *targetaddresses*."""
   548         the given *targetaddresses*."""
   553         alias = self.__getAlias(aliasaddress)
   549         alias = self.__getAlias(aliasaddress)
   565                         not Handler.aliasExists(self._dbh, destination)):
   561                         not Handler.aliasExists(self._dbh, destination)):
   566                 self.__warnings.append(
   562                 self.__warnings.append(
   567                     _(u"The destination account/alias %r doesn't exist.") %
   563                     _(u"The destination account/alias %r doesn't exist.") %
   568                                        str(destination))
   564                                        str(destination))
   569 
   565 
   570     def userDelete(self, emailaddress, force=None):
   566     def user_delete(self, emailaddress, force=None):
   571         if force not in [None, 'delalias']:
   567         """Wrapper around Account.delete(...)"""
   572             raise VMMError(_(u"Invalid argument: “%s”") % force,
   568         if force not in (None, 'delalias'):
   573                     ERR.INVALID_AGUMENT)
   569             raise VMMError(_(u"Invalid argument: '%s'") % force,
       
   570                            ERR.INVALID_AGUMENT)
   574         acc = self.__getAccount(emailaddress)
   571         acc = self.__getAccount(emailaddress)
   575         uid = acc.getUID()
   572         if not acc:
   576         gid = acc.getGID()
   573             raise VMMError(_(u"The account '%s' doesn't exist.") %
   577         acc.delete(force)
   574                            acc.address, ERR.NO_SUCH_ACCOUNT)
       
   575         uid = acc.uid
       
   576         gid = acc.gid
       
   577         dom_dir = acc.domain_directory
       
   578         acc_dir = acc.home
       
   579         acc.delete(bool(force))
   578         if self._Cfg.dget('account.delete_directory'):
   580         if self._Cfg.dget('account.delete_directory'):
   579             try:
   581             try:
   580                 self.__userDirDelete(acc.getDir('domain'), uid, gid)
   582                 self.__userDirDelete(dom_dir, uid, gid)
   581             except VMMError, e:
   583             except VMMError, err:
   582                 if e.code in [ERR.FOUND_DOTS_IN_PATH,
   584                 if err.code in (ERR.FOUND_DOTS_IN_PATH,
   583                         ERR.MAILDIR_PERM_MISMATCH, ERR.NO_SUCH_DIRECTORY]:
   585                         ERR.MAILDIR_PERM_MISMATCH, ERR.NO_SUCH_DIRECTORY):
   584                     warning = _(u"""\
   586                     warning = _(u"""\
   585 The account has been successfully deleted from the database.
   587 The account has been successfully deleted from the database.
   586     But an error occurred while deleting the following directory:
   588     But an error occurred while deleting the following directory:
   587     “%(directory)s”
   589     “%(directory)s”
   588     Reason: %(reason)s""") % \
   590     Reason: %(reason)s""") % \
   589                     {'directory': acc.getDir('home'), 'reason': e.msg}
   591                                 {'directory': acc_dir, 'reason': err.msg}
   590                     self.__warnings.append(warning)
   592                     self.__warnings.append(warning)
   591                 else:
   593                 else:
   592                     raise
   594                     raise
   593 
   595 
   594     def aliasInfo(self, aliasaddress):
   596     def aliasInfo(self, aliasaddress):
   622         if targetaddress is None:
   624         if targetaddress is None:
   623             alias.delete()
   625             alias.delete()
   624         else:
   626         else:
   625             alias.del_destination(EmailAddress(targetaddress))
   627             alias.del_destination(EmailAddress(targetaddress))
   626 
   628 
   627     def userInfo(self, emailaddress, details=None):
   629     def user_info(self, emailaddress, details=None):
       
   630         """Wrapper around Account.get_info(...)"""
   628         if details not in (None, 'du', 'aliases', 'full'):
   631         if details not in (None, 'du', 'aliases', 'full'):
   629             raise VMMError(_(u'Invalid argument: “%s”') % details,
   632             raise VMMError(_(u"Invalid argument: '%s'") % details,
   630                                ERR.INVALID_AGUMENT)
   633                            ERR.INVALID_AGUMENT)
   631         acc = self.__getAccount(emailaddress)
   634         acc = self.__getAccount(emailaddress)
   632         info = acc.getInfo(self._Cfg.dget('misc.dovecot_version'))
   635         if not acc:
       
   636             raise VMMError(_(u"The account '%s' doesn't exist.") %
       
   637                            acc.address, ERR.NO_SUCH_ACCOUNT)
       
   638         info = acc.get_info()
   633         if self._Cfg.dget('account.disk_usage') or details in ('du', 'full'):
   639         if self._Cfg.dget('account.disk_usage') or details in ('du', 'full'):
   634             info['disk usage'] = self.__getDiskUsage('%(maildir)s' % info)
   640             path = os.path.join(acc.home, info['mail_location'].split('/')[-1])
       
   641             info['disk usage'] = self.__getDiskUsage(path)
   635             if details in (None, 'du'):
   642             if details in (None, 'du'):
   636                 return info
   643                 return info
   637         if details in ('aliases', 'full'):
   644         if details in ('aliases', 'full'):
   638             return (info, acc.getAliases())
   645             return (info, acc.get_aliases())
   639         return info
   646         return info
   640 
   647 
   641     def user_by_uid(self, uid):
   648     def user_by_uid(self, uid):
   642         """Search for an Account by its *uid*.
   649         """Search for an Account by its *uid*.
   643         Returns a dict (address, uid and gid) if a user could be found."""
   650         Returns a dict (address, uid and gid) if a user could be found."""
   644         from VirtualMailManager.Account import get_account_by_uid
   651         from VirtualMailManager.Account import get_account_by_uid
   645         self.__dbConnect()
   652         self.__dbConnect()
   646         return get_account_by_uid(uid, self._dbh)
   653         return get_account_by_uid(uid, self._dbh)
   647 
   654 
   648     def userPassword(self, emailaddress, password):
   655     def user_password(self, emailaddress, password):
   649         if password is None or (isinstance(password, basestring) and
   656         """Wrapper for Account.modify('password' ...)."""
   650                                 not len(password)):
   657         if not isinstance(password, basestring) or not password:
   651             raise ValueError('could not accept password: %r' % password)
   658             raise VMMError(_(u"Could not accept password: '%s'") % password,
       
   659                            ERR.INVALID_AGUMENT)
   652         acc = self.__getAccount(emailaddress)
   660         acc = self.__getAccount(emailaddress)
   653         if acc.getUID() == 0:
   661         if not acc:
   654             raise VMMError(_(u"Account doesn't exist"),
   662             raise VMMError(_(u"The account '%s' doesn't exist.") %
   655                                ERR.NO_SUCH_ACCOUNT)
   663                            acc.address, ERR.NO_SUCH_ACCOUNT)
   656         acc.modify('password', self.__pwhash(password, user=emailaddress))
   664         acc.modify('password', password)
   657 
   665 
   658     def userName(self, emailaddress, name):
   666     def user_name(self, emailaddress, name):
       
   667         """Wrapper for Account.modify('name', ...)."""
       
   668         if not isinstance(name, basestring) or not name:
       
   669             raise VMMError(_(u"Could not accept name: '%s'") % name,
       
   670                            ERR.INVALID_AGUMENT)
   659         acc = self.__getAccount(emailaddress)
   671         acc = self.__getAccount(emailaddress)
       
   672         if not acc:
       
   673             raise VMMError(_(u"The account '%s' doesn't exist.") %
       
   674                            acc.address, ERR.NO_SUCH_ACCOUNT)
   660         acc.modify('name', name)
   675         acc.modify('name', name)
   661 
   676 
   662     def userTransport(self, emailaddress, transport):
   677     def user_transport(self, emailaddress, transport):
       
   678         """Wrapper for Account.modify('transport', ...)."""
       
   679         if not isinstance(transport, basestring) or not transport:
       
   680             raise VMMError(_(u"Could not accept transport: '%s'") % transport,
       
   681                            ERR.INVALID_AGUMENT)
   663         acc = self.__getAccount(emailaddress)
   682         acc = self.__getAccount(emailaddress)
       
   683         if not acc:
       
   684             raise VMMError(_(u"The account '%s' doesn't exist.") %
       
   685                            acc.address, ERR.NO_SUCH_ACCOUNT)
   664         acc.modify('transport', transport)
   686         acc.modify('transport', transport)
   665 
   687 
   666     def userDisable(self, emailaddress, service=None):
   688     def user_disable(self, emailaddress, service=None):
   667         if service == 'managesieve':
   689         """Wrapper for Account.disable(service)"""
   668             service = 'sieve'
   690         if service not in (None, 'all', 'imap', 'pop3', 'smtp', 'sieve'):
   669             self.__warnings.append(_(u'\
   691             raise VMMError(_(u"Could not accept service: '%s'") % service,
   670 The service name “managesieve” is deprecated and will be removed\n\
   692                            ERR.INVALID_AGUMENT)
   671    in a future release.\n\
       
   672    Please use the service name “sieve” instead.'))
       
   673         acc = self.__getAccount(emailaddress)
   693         acc = self.__getAccount(emailaddress)
   674         acc.disable(self._Cfg.dget('misc.dovecot_version'), service)
   694         if not acc:
   675 
   695             raise VMMError(_(u"The account '%s' doesn't exist.") %
   676     def userEnable(self, emailaddress, service=None):
   696                            acc.address, ERR.NO_SUCH_ACCOUNT)
   677         if service == 'managesieve':
   697         acc.disable(service)
   678             service = 'sieve'
   698 
   679             self.__warnings.append(_(u'\
   699     def user_enable(self, emailaddress, service=None):
   680 The service name “managesieve” is deprecated and will be removed\n\
   700         """Wrapper for Account.enable(service)"""
   681    in a future release.\n\
   701         if service not in (None, 'all', 'imap', 'pop3', 'smtp', 'sieve'):
   682    Please use the service name “sieve” instead.'))
   702             raise VMMError(_(u"could not accept service: '%s'") % service,
       
   703                            ERR.INVALID_AGUMENT)
   683         acc = self.__getAccount(emailaddress)
   704         acc = self.__getAccount(emailaddress)
   684         acc.enable(self._Cfg.dget('misc.dovecot_version'), service)
   705         if not acc:
       
   706             raise VMMError(_(u"The account '%s' doesn't exist.") %
       
   707                            acc.address, ERR.NO_SUCH_ACCOUNT)
       
   708         acc.enable(service)
   685 
   709 
   686     def relocatedAdd(self, emailaddress, targetaddress):
   710     def relocatedAdd(self, emailaddress, targetaddress):
   687         """Creates a new `Relocated` entry in the database. If there is
   711         """Creates a new `Relocated` entry in the database. If there is
   688         already a relocated user with the given *emailaddress*, only the
   712         already a relocated user with the given *emailaddress*, only the
   689         *targetaddress* for the relocated user will be updated."""
   713         *targetaddress* for the relocated user will be updated."""
   720         relocated.delete()
   744         relocated.delete()
   721 
   745 
   722     def __del__(self):
   746     def __del__(self):
   723         if isinstance(self._dbh, PgSQL.Connection) and self._dbh._isOpen:
   747         if isinstance(self._dbh, PgSQL.Connection) and self._dbh._isOpen:
   724             self._dbh.close()
   748             self._dbh.close()
       
   749 
       
   750 del _