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 |