VirtualMailManager/VirtualMailManager.py
branchv0.6.x
changeset 166 b152ad5c7071
parent 162 0ac9ef587769
child 168 fd496561acc6
equal deleted inserted replaced
165:7e50e4c49ed7 166:b152ad5c7071
    49         if self.__chkCfgFile():
    49         if self.__chkCfgFile():
    50             self.__Cfg = Cfg(self.__cfgFileName)
    50             self.__Cfg = Cfg(self.__cfgFileName)
    51             self.__Cfg.load()
    51             self.__Cfg.load()
    52             self.__Cfg.check()
    52             self.__Cfg.check()
    53             self.__cfgSections = self.__Cfg.getsections()
    53             self.__cfgSections = self.__Cfg.getsections()
    54             self.__scheme = self.__Cfg.get('misc', 'passwdscheme')
    54             self.__scheme = self.__Cfg.get('misc', 'password_scheme')
    55             self._postconf = Postconf(self.__Cfg.get('bin', 'postconf'))
    55             self._postconf = Postconf(self.__Cfg.get('bin', 'postconf'))
    56         if not os.sys.argv[1] in ['cf', 'configure']:
    56         if not os.sys.argv[1] in ['cf', 'configure']:
    57             self.__chkenv()
    57             self.__chkenv()
    58 
    58 
    59     def __findCfgFile(self):
    59     def __findCfgFile(self):
    81         else:
    81         else:
    82             return True
    82             return True
    83 
    83 
    84     def __chkenv(self):
    84     def __chkenv(self):
    85         """"""
    85         """"""
    86         if not os.path.exists(self.__Cfg.get('domdir', 'base')):
    86         if not os.path.exists(self.__Cfg.get('misc', 'base_dir')):
    87             old_umask = os.umask(0006)
    87             old_umask = os.umask(0006)
    88             os.makedirs(self.__Cfg.get('domdir', 'base'), 0771)
    88             os.makedirs(self.__Cfg.get('misc', 'base_dir'), 0771)
    89             os.chown(self.__Cfg.get('domdir', 'base'), 0,
    89             os.chown(self.__Cfg.get('misc', 'base_dir'), 0,
    90                     self.__Cfg.getint('misc', 'gid_mail'))
    90                     self.__Cfg.getint('misc', 'gid_mail'))
    91             os.umask(old_umask)
    91             os.umask(old_umask)
    92         elif not os.path.isdir(self.__Cfg.get('domdir', 'base')):
    92         elif not os.path.isdir(self.__Cfg.get('misc', 'base_dir')):
    93             raise VMMException(_(u'“%s” is not a directory.\n\
    93             raise VMMException(_(u'“%s” is not a directory.\n\
    94 (vmm.cfg: section "domdir", option "base")') %
    94 (vmm.cfg: section "misc", option "base_dir")') %
    95                 self.__Cfg.get('domdir', 'base'), ERR.NO_SUCH_DIRECTORY)
    95                 self.__Cfg.get('misc', 'base_dir'), ERR.NO_SUCH_DIRECTORY)
    96         for opt, val in self.__Cfg.items('bin'):
    96         for opt, val in self.__Cfg.items('bin'):
    97             if not os.path.exists(val):
    97             if not os.path.exists(val):
    98                 raise VMMException(_(u'“%(binary)s” doesn\'t exist.\n\
    98                 raise VMMException(_(u'“%(binary)s” doesn\'t exist.\n\
    99 (vmm.cfg: section "bin", option "%(option)s")') %{'binary': val,'option': opt},
    99 (vmm.cfg: section "bin", option "%(option)s")') %{'binary': val,'option': opt},
   100                     ERR.NO_SUCH_BINARY)
   100                     ERR.NO_SUCH_BINARY)
   235     def __getDomain(self, domainname, transport=None):
   235     def __getDomain(self, domainname, transport=None):
   236         if transport is None:
   236         if transport is None:
   237             transport = self.__Cfg.get('misc', 'transport')
   237             transport = self.__Cfg.get('misc', 'transport')
   238         self.__dbConnect()
   238         self.__dbConnect()
   239         return Domain(self.__dbh, domainname,
   239         return Domain(self.__dbh, domainname,
   240                 self.__Cfg.get('domdir', 'base'), transport)
   240                 self.__Cfg.get('misc', 'base_dir'), transport)
   241 
   241 
   242     def __getDiskUsage(self, directory):
   242     def __getDiskUsage(self, directory):
   243         """Estimate file space usage for the given directory.
   243         """Estimate file space usage for the given directory.
   244 
   244 
   245         Keyword arguments:
   245         Keyword arguments:
   257             self.__warnings.append(_('No such directory: %s') % directory)
   257             self.__warnings.append(_('No such directory: %s') % directory)
   258         return isdir
   258         return isdir
   259 
   259 
   260     def __makedir(self, directory, mode=None, uid=None, gid=None):
   260     def __makedir(self, directory, mode=None, uid=None, gid=None):
   261         if mode is None:
   261         if mode is None:
   262             mode = self.__Cfg.getint('maildir', 'mode')
   262             mode = self.__Cfg.getint('account', 'directory_mode')
   263         if uid is None:
   263         if uid is None:
   264             uid = 0
   264             uid = 0
   265         if gid is None:
   265         if gid is None:
   266             gid = 0
   266             gid = 0
   267         os.makedirs(directory, mode)
   267         os.makedirs(directory, mode)
   268         os.chown(directory, uid, gid)
   268         os.chown(directory, uid, gid)
   269 
   269 
   270     def __domDirMake(self, domdir, gid):
   270     def __domDirMake(self, domdir, gid):
   271         os.umask(0006)
   271         os.umask(0006)
   272         oldpwd = os.getcwd()
   272         oldpwd = os.getcwd()
   273         basedir = self.__Cfg.get('domdir', 'base')
   273         basedir = self.__Cfg.get('misc', 'base_dir')
   274         domdirdirs = domdir.replace(basedir+'/', '').split('/')
   274         domdirdirs = domdir.replace(basedir+'/', '').split('/')
   275 
   275 
   276         os.chdir(basedir)
   276         os.chdir(basedir)
   277         if not os.path.isdir(domdirdirs[0]):
   277         if not os.path.isdir(domdirdirs[0]):
   278             self.__makedir(domdirdirs[0], 489, 0,
   278             self.__makedir(domdirdirs[0], 489, 0,
   279                     self.__Cfg.getint('misc', 'gid_mail'))
   279                            self.__Cfg.getint('misc', 'gid_mail'))
   280         os.chdir(domdirdirs[0])
   280         os.chdir(domdirdirs[0])
   281         os.umask(0007)
   281         os.umask(0007)
   282         self.__makedir(domdirdirs[1], self.__Cfg.getint('domdir', 'mode'), 0,
   282         self.__makedir(domdirdirs[1],
   283                 gid)
   283                        self.__Cfg.getint('domain', 'directory_mode'), 0, gid)
   284         os.chdir(oldpwd)
   284         os.chdir(oldpwd)
   285 
   285 
   286     def __subscribeFL(self, folderlist, uid, gid):
   286     def __subscribeFL(self, folderlist, uid, gid):
   287         fname = os.path.join(self.__Cfg.get('maildir','name'), 'subscriptions')
   287         fname = os.path.join(self.__Cfg.get('maildir','name'), 'subscriptions')
   288         sf = file(fname, 'w')
   288         sf = file(fname, 'w')
   311             folder = folder.strip()
   311             folder = folder.strip()
   312             if len(folder) and not folder.count('..')\
   312             if len(folder) and not folder.count('..')\
   313             and re.match(RE_MBOX_NAMES, folder):
   313             and re.match(RE_MBOX_NAMES, folder):
   314                 folders.append('%s/.%s' % (maildir, folder))
   314                 folders.append('%s/.%s' % (maildir, folder))
   315         subdirs = ['cur', 'new', 'tmp']
   315         subdirs = ['cur', 'new', 'tmp']
   316         mode = self.__Cfg.getint('maildir', 'mode')
   316         mode = self.__Cfg.getint('account', 'directory_mode')
   317 
   317 
   318         self.__makedir('%s' % uid, mode, uid, gid)
   318         self.__makedir('%s' % uid, mode, uid, gid)
   319         os.chdir('%s' % uid)
   319         os.chdir('%s' % uid)
   320         for folder in folders:
   320         for folder in folders:
   321             self.__makedir(folder, mode, uid, gid)
   321             self.__makedir(folder, mode, uid, gid)
   346 
   346 
   347     def __domDirDelete(self, domdir, gid):
   347     def __domDirDelete(self, domdir, gid):
   348         if gid > 0:
   348         if gid > 0:
   349             if not self.__isdir(domdir):
   349             if not self.__isdir(domdir):
   350                 return
   350                 return
   351             basedir = self.__Cfg.get('domdir', 'base')
   351             basedir = self.__Cfg.get('misc', 'base_dir')
   352             domdirdirs = domdir.replace(basedir+'/', '').split('/')
   352             domdirdirs = domdir.replace(basedir+'/', '').split('/')
   353             domdirparent = os.path.join(basedir, domdirdirs[0])
   353             domdirparent = os.path.join(basedir, domdirdirs[0])
   354             if basedir.count('..') or domdir.count('..'):
   354             if basedir.count('..') or domdir.count('..'):
   355                 raise VMMException(_(u'Found ".." in domain directory path.'),
   355                 raise VMMException(_(u'Found ".." in domain directory path.'),
   356                         ERR.FOUND_DOTS_IN_PATH)
   356                         ERR.FOUND_DOTS_IN_PATH)
   485             raise VMMDomainException(_(u"Invalid argument: “%s”") % force,
   485             raise VMMDomainException(_(u"Invalid argument: “%s”") % force,
   486                 ERR.INVALID_OPTION)
   486                 ERR.INVALID_OPTION)
   487         dom = self.__getDomain(domainname)
   487         dom = self.__getDomain(domainname)
   488         gid = dom.getID()
   488         gid = dom.getID()
   489         domdir = dom.getDir()
   489         domdir = dom.getDir()
   490         if self.__Cfg.getboolean('misc', 'forcedel') or force == 'delall':
   490         if self.__Cfg.getboolean('domain', 'force_del') or force == 'delall':
   491             dom.delete(True, True)
   491             dom.delete(True, True)
   492         elif force == 'deluser':
   492         elif force == 'deluser':
   493             dom.delete(delUser=True)
   493             dom.delete(delUser=True)
   494         elif force == 'delalias':
   494         elif force == 'delalias':
   495             dom.delete(delAlias=True)
   495             dom.delete(delAlias=True)
   496         else:
   496         else:
   497             dom.delete()
   497             dom.delete()
   498         if self.__Cfg.getboolean('domdir', 'delete'):
   498         if self.__Cfg.getboolean('domain', 'delete_directory'):
   499             self.__domDirDelete(domdir, gid)
   499             self.__domDirDelete(domdir, gid)
   500 
   500 
   501     def domainInfo(self, domainname, details=None):
   501     def domainInfo(self, domainname, details=None):
   502         if details not in [None, 'accounts', 'aliasdomains', 'aliases', 'full',
   502         if details not in [None, 'accounts', 'aliasdomains', 'aliases', 'full',
   503                 'relocated', 'detailed']:
   503                 'relocated', 'detailed']:
   587         acc = self.__getAccount(emailaddress, password)
   587         acc = self.__getAccount(emailaddress, password)
   588         if password is None:
   588         if password is None:
   589             password = self._readpass()
   589             password = self._readpass()
   590             acc.setPassword(self.__pwhash(password))
   590             acc.setPassword(self.__pwhash(password))
   591         acc.save(self.__Cfg.get('maildir', 'name'),
   591         acc.save(self.__Cfg.get('maildir', 'name'),
   592                 self.__Cfg.getint('misc', 'dovecotvers'),
   592                 self.__Cfg.getint('misc', 'dovecot_vers'),
   593                 self.__Cfg.getboolean('services', 'smtp'),
   593                 self.__Cfg.getboolean('account', 'smtp'),
   594                 self.__Cfg.getboolean('services', 'pop3'),
   594                 self.__Cfg.getboolean('account', 'pop3'),
   595                 self.__Cfg.getboolean('services', 'imap'),
   595                 self.__Cfg.getboolean('account', 'imap'),
   596                 self.__Cfg.getboolean('services', 'sieve'))
   596                 self.__Cfg.getboolean('account', 'sieve'))
   597         self.__mailDirMake(acc.getDir('domain'), acc.getUID(), acc.getGID())
   597         self.__mailDirMake(acc.getDir('domain'), acc.getUID(), acc.getGID())
   598 
   598 
   599     def aliasAdd(self, aliasaddress, targetaddress):
   599     def aliasAdd(self, aliasaddress, targetaddress):
   600         alias = self.__getAlias(aliasaddress, targetaddress)
   600         alias = self.__getAlias(aliasaddress, targetaddress)
   601         alias.save(long(self._postconf.read('virtual_alias_expansion_limit')))
   601         alias.save(long(self._postconf.read('virtual_alias_expansion_limit')))
   613                     ERR.INVALID_AGUMENT)
   613                     ERR.INVALID_AGUMENT)
   614         acc = self.__getAccount(emailaddress)
   614         acc = self.__getAccount(emailaddress)
   615         uid = acc.getUID()
   615         uid = acc.getUID()
   616         gid = acc.getGID()
   616         gid = acc.getGID()
   617         acc.delete(force)
   617         acc.delete(force)
   618         if self.__Cfg.getboolean('maildir', 'delete'):
   618         if self.__Cfg.getboolean('account', 'delete_directory'):
   619             try:
   619             try:
   620                 self.__userDirDelete(acc.getDir('domain'), uid, gid)
   620                 self.__userDirDelete(acc.getDir('domain'), uid, gid)
   621             except VMMException, e:
   621             except VMMException, e:
   622                 if e.code() in [ERR.FOUND_DOTS_IN_PATH,
   622                 if e.code() in [ERR.FOUND_DOTS_IN_PATH,
   623                         ERR.MAILDIR_PERM_MISMATCH, ERR.NO_SUCH_DIRECTORY]:
   623                         ERR.MAILDIR_PERM_MISMATCH, ERR.NO_SUCH_DIRECTORY]:
   641     def userInfo(self, emailaddress, details=None):
   641     def userInfo(self, emailaddress, details=None):
   642         if details not in [None, 'du', 'aliases', 'full']:
   642         if details not in [None, 'du', 'aliases', 'full']:
   643             raise VMMException(_(u'Invalid argument: “%s”') % details,
   643             raise VMMException(_(u'Invalid argument: “%s”') % details,
   644                     ERR.INVALID_AGUMENT)
   644                     ERR.INVALID_AGUMENT)
   645         acc = self.__getAccount(emailaddress)
   645         acc = self.__getAccount(emailaddress)
   646         info = acc.getInfo(self.__Cfg.getint('misc', 'dovecotvers'))
   646         info = acc.getInfo(self.__Cfg.getint('misc', 'dovecot_vers'))
   647         if self.__Cfg.getboolean('maildir', 'diskusage')\
   647         if self.__Cfg.getboolean('account', 'disk_usage')\
   648         or details in ['du', 'full']:
   648         or details in ['du', 'full']:
   649             info['disk usage'] = self.__getDiskUsage('%(maildir)s' % info)
   649             info['disk usage'] = self.__getDiskUsage('%(maildir)s' % info)
   650             if details in [None, 'du']:
   650             if details in [None, 'du']:
   651                 return info
   651                 return info
   652         if details in ['aliases', 'full']:
   652         if details in ['aliases', 'full']:
   680             self.__warnings.append(_(u'\
   680             self.__warnings.append(_(u'\
   681 The service name “managesieve” is deprecated and will be removed\n\
   681 The service name “managesieve” is deprecated and will be removed\n\
   682    in a future release.\n\
   682    in a future release.\n\
   683    Please use the service name “sieve” instead.'))
   683    Please use the service name “sieve” instead.'))
   684         acc = self.__getAccount(emailaddress)
   684         acc = self.__getAccount(emailaddress)
   685         acc.disable(self.__Cfg.getint('misc', 'dovecotvers'), service)
   685         acc.disable(self.__Cfg.getint('misc', 'dovecot_vers'), service)
   686 
   686 
   687     def userEnable(self, emailaddress, service=None):
   687     def userEnable(self, emailaddress, service=None):
   688         if service == 'managesieve':
   688         if service == 'managesieve':
   689             service = 'sieve'
   689             service = 'sieve'
   690             self.__warnings.append(_(u'\
   690             self.__warnings.append(_(u'\
   691 The service name “managesieve” is deprecated and will be removed\n\
   691 The service name “managesieve” is deprecated and will be removed\n\
   692    in a future release.\n\
   692    in a future release.\n\
   693    Please use the service name “sieve” instead.'))
   693    Please use the service name “sieve” instead.'))
   694         acc = self.__getAccount(emailaddress)
   694         acc = self.__getAccount(emailaddress)
   695         acc.enable(self.__Cfg.getint('misc', 'dovecotvers'), service)
   695         acc.enable(self.__Cfg.getint('misc', 'dovecot_vers'), service)
   696 
   696 
   697     def relocatedAdd(self, emailaddress, targetaddress):
   697     def relocatedAdd(self, emailaddress, targetaddress):
   698         relocated = self.__getRelocated(emailaddress, targetaddress)
   698         relocated = self.__getRelocated(emailaddress, targetaddress)
   699         relocated.save()
   699         relocated.save()
   700 
   700