96 tmp = os.path.join(path, CFG_FILE) |
96 tmp = os.path.join(path, CFG_FILE) |
97 if os.path.isfile(tmp): |
97 if os.path.isfile(tmp): |
98 self._cfg_fname = tmp |
98 self._cfg_fname = tmp |
99 break |
99 break |
100 if not self._cfg_fname: |
100 if not self._cfg_fname: |
101 raise VMMError(_(u"Could not find '%(cfg_file)s' in: " |
101 raise VMMError(_("Could not find '%(cfg_file)s' in: " |
102 u"'%(cfg_path)s'") % {'cfg_file': CFG_FILE, |
102 "'%(cfg_path)s'") % {'cfg_file': CFG_FILE, |
103 'cfg_path': CFG_PATH}, CONF_NOFILE) |
103 'cfg_path': CFG_PATH}, CONF_NOFILE) |
104 |
104 |
105 def _check_cfg_file(self): |
105 def _check_cfg_file(self): |
106 """Checks the configuration file, returns bool""" |
106 """Checks the configuration file, returns bool""" |
107 self._find_cfg_file() |
107 self._find_cfg_file() |
108 fstat = os.stat(self._cfg_fname) |
108 fstat = os.stat(self._cfg_fname) |
109 fmode = int(oct(fstat.st_mode & 0777)) |
109 fmode = int(oct(fstat.st_mode & 0o777)) |
110 if fmode % 100 and fstat.st_uid != fstat.st_gid or \ |
110 if fmode % 100 and fstat.st_uid != fstat.st_gid or \ |
111 fmode % 10 and fstat.st_uid == fstat.st_gid: |
111 fmode % 10 and fstat.st_uid == fstat.st_gid: |
112 # TP: Please keep the backticks around the command. `chmod 0600 …` |
112 # TP: Please keep the backticks around the command. `chmod 0600 …` |
113 raise PermissionError(_(u"wrong permissions for '%(file)s': " |
113 raise PermissionError(_("wrong permissions for '%(file)s': " |
114 u"%(perms)s\n`chmod 0600 %(file)s` would " |
114 "%(perms)s\n`chmod 0600 %(file)s` would " |
115 u"be great.") % {'file': self._cfg_fname, |
115 "be great.") % {'file': self._cfg_fname, |
116 'perms': fmode}, CONF_WRONGPERM) |
116 'perms': fmode}, CONF_WRONGPERM) |
117 else: |
117 else: |
118 return True |
118 return True |
119 |
119 |
120 def _chkenv(self): |
120 def _chkenv(self): |
122 required executables exists and are executable. |
122 required executables exists and are executable. |
123 If not, a VMMError will be raised""" |
123 If not, a VMMError will be raised""" |
124 dir_created = False |
124 dir_created = False |
125 basedir = self._cfg.dget('misc.base_directory') |
125 basedir = self._cfg.dget('misc.base_directory') |
126 if not os.path.exists(basedir): |
126 if not os.path.exists(basedir): |
127 old_umask = os.umask(0006) |
127 old_umask = os.umask(0o006) |
128 os.makedirs(basedir, 0771) |
128 os.makedirs(basedir, 0o771) |
129 os.chown(basedir, 0, 0) |
129 os.chown(basedir, 0, 0) |
130 os.umask(old_umask) |
130 os.umask(old_umask) |
131 dir_created = True |
131 dir_created = True |
132 if not dir_created and not lisdir(basedir): |
132 if not dir_created and not lisdir(basedir): |
133 raise VMMError(_(u"'%(path)s' is not a directory.\n(%(cfg_file)s: " |
133 raise VMMError(_("'%(path)s' is not a directory.\n(%(cfg_file)s: " |
134 u"section 'misc', option 'base_directory')") % |
134 "section 'misc', option 'base_directory')") % |
135 {'path': basedir, 'cfg_file': self._cfg_fname}, |
135 {'path': basedir, 'cfg_file': self._cfg_fname}, |
136 NO_SUCH_DIRECTORY) |
136 NO_SUCH_DIRECTORY) |
137 for opt, val in self._cfg.items('bin'): |
137 for opt, val in self._cfg.items('bin'): |
138 try: |
138 try: |
139 exec_ok(val) |
139 exec_ok(val) |
140 except VMMError, err: |
140 except VMMError as err: |
141 if err.code in (NO_SUCH_BINARY, NOT_EXECUTABLE): |
141 if err.code in (NO_SUCH_BINARY, NOT_EXECUTABLE): |
142 raise VMMError(err.msg + _(u"\n(%(cfg_file)s: section " |
142 raise VMMError(err.msg + _("\n(%(cfg_file)s: section " |
143 u"'bin', option '%(option)s')") % |
143 "'bin', option '%(option)s')") % |
144 {'cfg_file': self._cfg_fname, |
144 {'cfg_file': self._cfg_fname, |
145 'option': opt}, err.code) |
145 'option': opt}, err.code) |
146 else: |
146 else: |
147 raise |
147 raise |
148 |
148 |
290 """Create a directory for the `domain` and its accounts.""" |
290 """Create a directory for the `domain` and its accounts.""" |
291 cwd = os.getcwd() |
291 cwd = os.getcwd() |
292 hashdir, domdir = domain.directory.split(os.path.sep)[-2:] |
292 hashdir, domdir = domain.directory.split(os.path.sep)[-2:] |
293 dir_created = False |
293 dir_created = False |
294 os.chdir(self._cfg.dget('misc.base_directory')) |
294 os.chdir(self._cfg.dget('misc.base_directory')) |
295 old_umask = os.umask(0022) |
295 old_umask = os.umask(0o022) |
296 if not os.path.exists(hashdir): |
296 if not os.path.exists(hashdir): |
297 os.mkdir(hashdir, 0711) |
297 os.mkdir(hashdir, 0o711) |
298 os.chown(hashdir, 0, 0) |
298 os.chown(hashdir, 0, 0) |
299 dir_created = True |
299 dir_created = True |
300 if not dir_created and not lisdir(hashdir): |
300 if not dir_created and not lisdir(hashdir): |
301 raise VMMError(_(u"'%s' is not a directory.") % hashdir, |
301 raise VMMError(_("'%s' is not a directory.") % hashdir, |
302 NO_SUCH_DIRECTORY) |
302 NO_SUCH_DIRECTORY) |
303 if os.path.exists(domain.directory): |
303 if os.path.exists(domain.directory): |
304 raise VMMError(_(u"The file/directory '%s' already exists.") % |
304 raise VMMError(_("The file/directory '%s' already exists.") % |
305 domain.directory, VMM_ERROR) |
305 domain.directory, VMM_ERROR) |
306 os.mkdir(os.path.join(hashdir, domdir), |
306 os.mkdir(os.path.join(hashdir, domdir), |
307 self._cfg.dget('domain.directory_mode')) |
307 self._cfg.dget('domain.directory_mode')) |
308 os.chown(domain.directory, 0, domain.gid) |
308 os.chown(domain.directory, 0, domain.gid) |
309 os.umask(old_umask) |
309 os.umask(old_umask) |
346 `uid` : int/long |
346 `uid` : int/long |
347 The user's UID (commonly AccountObj.uid) |
347 The user's UID (commonly AccountObj.uid) |
348 `gid` : int/long |
348 `gid` : int/long |
349 The user's GID (commonly AccountObj.gid) |
349 The user's GID (commonly AccountObj.gid) |
350 """ |
350 """ |
351 assert all(isinstance(xid, (long, int)) for xid in (uid, gid)) and \ |
351 assert all(isinstance(xid, int) for xid in (uid, gid)) and \ |
352 isinstance(domdir, basestring) |
352 isinstance(domdir, str) |
353 if uid < MIN_UID or gid < MIN_GID: |
353 if uid < MIN_UID or gid < MIN_GID: |
354 raise VMMError(_(u"UID '%(uid)u' and/or GID '%(gid)u' are less " |
354 raise VMMError(_("UID '%(uid)u' and/or GID '%(gid)u' are less " |
355 u"than %(min_uid)u/%(min_gid)u.") % {'uid': uid, |
355 "than %(min_uid)u/%(min_gid)u.") % {'uid': uid, |
356 'gid': gid, 'min_gid': MIN_GID, 'min_uid': MIN_UID}, |
356 'gid': gid, 'min_gid': MIN_GID, 'min_uid': MIN_UID}, |
357 MAILDIR_PERM_MISMATCH) |
357 MAILDIR_PERM_MISMATCH) |
358 if domdir.count('..'): |
358 if domdir.count('..'): |
359 raise VMMError(_(u'Found ".." in domain directory path: %s') % |
359 raise VMMError(_('Found ".." in domain directory path: %s') % |
360 domdir, FOUND_DOTS_IN_PATH) |
360 domdir, FOUND_DOTS_IN_PATH) |
361 if not lisdir(domdir): |
361 if not lisdir(domdir): |
362 raise VMMError(_(u"No such directory: %s") % domdir, |
362 raise VMMError(_("No such directory: %s") % domdir, |
363 NO_SUCH_DIRECTORY) |
363 NO_SUCH_DIRECTORY) |
364 os.chdir(domdir) |
364 os.chdir(domdir) |
365 userdir = '%s' % uid |
365 userdir = '%s' % uid |
366 if not lisdir(userdir): |
366 if not lisdir(userdir): |
367 self._warnings.append(_(u"No such directory: %s") % |
367 self._warnings.append(_("No such directory: %s") % |
368 os.path.join(domdir, userdir)) |
368 os.path.join(domdir, userdir)) |
369 return |
369 return |
370 mdstat = os.lstat(userdir) |
370 mdstat = os.lstat(userdir) |
371 if (mdstat.st_uid, mdstat.st_gid) != (uid, gid): |
371 if (mdstat.st_uid, mdstat.st_gid) != (uid, gid): |
372 raise VMMError(_(u'Detected owner/group mismatch in home ' |
372 raise VMMError(_('Detected owner/group mismatch in home ' |
373 u'directory.'), MAILDIR_PERM_MISMATCH) |
373 'directory.'), MAILDIR_PERM_MISMATCH) |
374 rmtree(userdir, ignore_errors=True) |
374 rmtree(userdir, ignore_errors=True) |
375 |
375 |
376 def _delete_domain_dir(self, domdir, gid): |
376 def _delete_domain_dir(self, domdir, gid): |
377 """Delete a domain's directory. |
377 """Delete a domain's directory. |
378 |
378 |
381 `domdir` : basestring |
381 `domdir` : basestring |
382 The domain's directory (commonly DomainObj.directory) |
382 The domain's directory (commonly DomainObj.directory) |
383 `gid` : int/long |
383 `gid` : int/long |
384 The domain's GID (commonly DomainObj.gid) |
384 The domain's GID (commonly DomainObj.gid) |
385 """ |
385 """ |
386 assert isinstance(domdir, basestring) and isinstance(gid, (long, int)) |
386 assert isinstance(domdir, str) and isinstance(gid, int) |
387 if gid < MIN_GID: |
387 if gid < MIN_GID: |
388 raise VMMError(_(u"GID '%(gid)u' is less than '%(min_gid)u'.") % |
388 raise VMMError(_("GID '%(gid)u' is less than '%(min_gid)u'.") % |
389 {'gid': gid, 'min_gid': MIN_GID}, |
389 {'gid': gid, 'min_gid': MIN_GID}, |
390 DOMAINDIR_GROUP_MISMATCH) |
390 DOMAINDIR_GROUP_MISMATCH) |
391 if domdir.count('..'): |
391 if domdir.count('..'): |
392 raise VMMError(_(u'Found ".." in domain directory path: %s') % |
392 raise VMMError(_('Found ".." in domain directory path: %s') % |
393 domdir, FOUND_DOTS_IN_PATH) |
393 domdir, FOUND_DOTS_IN_PATH) |
394 if not lisdir(domdir): |
394 if not lisdir(domdir): |
395 self._warnings.append(_('No such directory: %s') % domdir) |
395 self._warnings.append(_('No such directory: %s') % domdir) |
396 return |
396 return |
397 dirst = os.lstat(domdir) |
397 dirst = os.lstat(domdir) |
398 if dirst.st_gid != gid: |
398 if dirst.st_gid != gid: |
399 raise VMMError(_(u'Detected group mismatch in domain directory: ' |
399 raise VMMError(_('Detected group mismatch in domain directory: ' |
400 u'%s') % domdir, DOMAINDIR_GROUP_MISMATCH) |
400 '%s') % domdir, DOMAINDIR_GROUP_MISMATCH) |
401 rmtree(domdir, ignore_errors=True) |
401 rmtree(domdir, ignore_errors=True) |
402 |
402 |
403 def has_warnings(self): |
403 def has_warnings(self): |
404 """Checks if warnings are present, returns bool.""" |
404 """Checks if warnings are present, returns bool.""" |
405 return bool(len(self._warnings)) |
405 return bool(len(self._warnings)) |
423 return self._cfg.pget(option) |
423 return self._cfg.pget(option) |
424 |
424 |
425 def cfg_install(self): |
425 def cfg_install(self): |
426 """Installs the cfg_dget method as ``cfg_dget`` into the built-in |
426 """Installs the cfg_dget method as ``cfg_dget`` into the built-in |
427 namespace.""" |
427 namespace.""" |
428 import __builtin__ |
428 import builtins |
429 assert 'cfg_dget' not in __builtin__.__dict__ |
429 assert 'cfg_dget' not in builtins.__dict__ |
430 __builtin__.__dict__['cfg_dget'] = self._cfg.dget |
430 builtins.__dict__['cfg_dget'] = self._cfg.dget |
431 |
431 |
432 def domain_add(self, domainname, transport=None): |
432 def domain_add(self, domainname, transport=None): |
433 """Wrapper around Domain's set_quotalimit, set_transport and save.""" |
433 """Wrapper around Domain's set_quotalimit, set_transport and save.""" |
434 dom = self._get_domain(domainname) |
434 dom = self._get_domain(domainname) |
435 if transport is None: |
435 if transport is None: |
436 dom.set_transport(Transport(self._dbh, |
436 dom.set_transport(Transport(self._dbh, |
437 transport=self._cfg.dget('domain.transport'))) |
437 transport=self._cfg.dget('domain.transport'))) |
438 else: |
438 else: |
439 dom.set_transport(Transport(self._dbh, transport=transport)) |
439 dom.set_transport(Transport(self._dbh, transport=transport)) |
440 dom.set_quotalimit(QuotaLimit(self._dbh, |
440 dom.set_quotalimit(QuotaLimit(self._dbh, |
441 bytes=long(self._cfg.dget('domain.quota_bytes')), |
441 bytes=int(self._cfg.dget('domain.quota_bytes')), |
442 messages=self._cfg.dget('domain.quota_messages'))) |
442 messages=self._cfg.dget('domain.quota_messages'))) |
443 dom.set_serviceset(ServiceSet(self._dbh, |
443 dom.set_serviceset(ServiceSet(self._dbh, |
444 imap=self._cfg.dget('domain.imap'), |
444 imap=self._cfg.dget('domain.imap'), |
445 pop3=self._cfg.dget('domain.pop3'), |
445 pop3=self._cfg.dget('domain.pop3'), |
446 sieve=self._cfg.dget('domain.sieve'), |
446 sieve=self._cfg.dget('domain.sieve'), |
449 dom.save() |
449 dom.save() |
450 self._make_domain_dir(dom) |
450 self._make_domain_dir(dom) |
451 |
451 |
452 def domain_quotalimit(self, domainname, bytes_, messages=0, force=None): |
452 def domain_quotalimit(self, domainname, bytes_, messages=0, force=None): |
453 """Wrapper around Domain.update_quotalimit().""" |
453 """Wrapper around Domain.update_quotalimit().""" |
454 if not all(isinstance(i, (int, long)) for i in (bytes_, messages)): |
454 if not all(isinstance(i, int) for i in (bytes_, messages)): |
455 raise TypeError("'bytes_' and 'messages' have to be " |
455 raise TypeError("'bytes_' and 'messages' have to be " |
456 "integers or longs.") |
456 "integers or longs.") |
457 if force is not None and force != 'force': |
457 if force is not None and force != 'force': |
458 raise DomainError(_(u"Invalid argument: '%s'") % force, |
458 raise DomainError(_("Invalid argument: '%s'") % force, |
459 INVALID_ARGUMENT) |
459 INVALID_ARGUMENT) |
460 dom = self._get_domain(domainname) |
460 dom = self._get_domain(domainname) |
461 quotalimit = QuotaLimit(self._dbh, bytes=bytes_, messages=messages) |
461 quotalimit = QuotaLimit(self._dbh, bytes=bytes_, messages=messages) |
462 if force is None: |
462 if force is None: |
463 dom.update_quotalimit(quotalimit) |
463 dom.update_quotalimit(quotalimit) |
466 |
466 |
467 def domain_services(self, domainname, force=None, *services): |
467 def domain_services(self, domainname, force=None, *services): |
468 """Wrapper around Domain.update_serviceset().""" |
468 """Wrapper around Domain.update_serviceset().""" |
469 kwargs = dict.fromkeys(SERVICES, False) |
469 kwargs = dict.fromkeys(SERVICES, False) |
470 if force is not None and force != 'force': |
470 if force is not None and force != 'force': |
471 raise DomainError(_(u"Invalid argument: '%s'") % force, |
471 raise DomainError(_("Invalid argument: '%s'") % force, |
472 INVALID_ARGUMENT) |
472 INVALID_ARGUMENT) |
473 for service in set(services): |
473 for service in set(services): |
474 if service not in SERVICES: |
474 if service not in SERVICES: |
475 raise DomainError(_(u"Unknown service: '%s'") % service, |
475 raise DomainError(_("Unknown service: '%s'") % service, |
476 UNKNOWN_SERVICE) |
476 UNKNOWN_SERVICE) |
477 kwargs[service] = True |
477 kwargs[service] = True |
478 |
478 |
479 dom = self._get_domain(domainname) |
479 dom = self._get_domain(domainname) |
480 serviceset = ServiceSet(self._dbh, **kwargs) |
480 serviceset = ServiceSet(self._dbh, **kwargs) |
481 dom.update_serviceset(serviceset, (True, False)[not force]) |
481 dom.update_serviceset(serviceset, (True, False)[not force]) |
482 |
482 |
483 def domain_transport(self, domainname, transport, force=None): |
483 def domain_transport(self, domainname, transport, force=None): |
484 """Wrapper around Domain.update_transport()""" |
484 """Wrapper around Domain.update_transport()""" |
485 if force is not None and force != 'force': |
485 if force is not None and force != 'force': |
486 raise DomainError(_(u"Invalid argument: '%s'") % force, |
486 raise DomainError(_("Invalid argument: '%s'") % force, |
487 INVALID_ARGUMENT) |
487 INVALID_ARGUMENT) |
488 dom = self._get_domain(domainname) |
488 dom = self._get_domain(domainname) |
489 trsp = Transport(self._dbh, transport=transport) |
489 trsp = Transport(self._dbh, transport=transport) |
490 if force is None: |
490 if force is None: |
491 dom.update_transport(trsp) |
491 dom.update_transport(trsp) |
515 """Wrapper around Domain.get_info(), Domain.get_accounts(), |
515 """Wrapper around Domain.get_info(), Domain.get_accounts(), |
516 Domain.get_aliase_names(), Domain.get_aliases() and |
516 Domain.get_aliase_names(), Domain.get_aliases() and |
517 Domain.get_relocated.""" |
517 Domain.get_relocated.""" |
518 if details not in [None, 'accounts', 'aliasdomains', 'aliases', 'full', |
518 if details not in [None, 'accounts', 'aliasdomains', 'aliases', 'full', |
519 'relocated', 'catchall']: |
519 'relocated', 'catchall']: |
520 raise VMMError(_(u"Invalid argument: '%s'") % details, |
520 raise VMMError(_("Invalid argument: '%s'") % details, |
521 INVALID_ARGUMENT) |
521 INVALID_ARGUMENT) |
522 dom = self._get_domain(domainname) |
522 dom = self._get_domain(domainname) |
523 dominfo = dom.get_info() |
523 dominfo = dom.get_info() |
524 if dominfo['domain name'].startswith('xn--'): |
524 if dominfo['domain name'].startswith('xn--'): |
525 dominfo['domain name'] += ' (%s)' % \ |
525 dominfo['domain name'] += ' (%s)' % \ |
615 dpattern = parts[1] |
615 dpattern = parts[1] |
616 dlike = dpattern.startswith('%') or dpattern.endswith('%') |
616 dlike = dpattern.startswith('%') or dpattern.endswith('%') |
617 |
617 |
618 checkp = lpattern.strip('%') if llike else lpattern |
618 checkp = lpattern.strip('%') if llike else lpattern |
619 if len(checkp) > 0 and re.search(RE_LOCALPART, checkp): |
619 if len(checkp) > 0 and re.search(RE_LOCALPART, checkp): |
620 raise VMMError(_(u"The pattern '%s' contains invalid " |
620 raise VMMError(_("The pattern '%s' contains invalid " |
621 u"characters.") % pattern, |
621 "characters.") % pattern, |
622 LOCALPART_INVALID) |
622 LOCALPART_INVALID) |
623 else: |
623 else: |
624 # else just match on domains |
624 # else just match on domains |
625 # (or should that be local part, I don't know…) |
625 # (or should that be local part, I don't know…) |
626 dpattern = parts[0] |
626 dpattern = parts[0] |
627 dlike = dpattern.startswith('%') or dpattern.endswith('%') |
627 dlike = dpattern.startswith('%') or dpattern.endswith('%') |
628 |
628 |
629 checkp = dpattern.strip('%') if dlike else dpattern |
629 checkp = dpattern.strip('%') if dlike else dpattern |
630 if len(checkp) > 0 and not re.match(RE_DOMAIN_SEARCH, checkp): |
630 if len(checkp) > 0 and not re.match(RE_DOMAIN_SEARCH, checkp): |
631 raise VMMError(_(u"The pattern '%s' contains invalid " |
631 raise VMMError(_("The pattern '%s' contains invalid " |
632 u"characters.") % pattern, DOMAIN_INVALID) |
632 "characters.") % pattern, DOMAIN_INVALID) |
633 self._db_connect() |
633 self._db_connect() |
634 from VirtualMailManager.common import search_addresses |
634 from VirtualMailManager.common import search_addresses |
635 return search_addresses(self._dbh, typelimit=typelimit, |
635 return search_addresses(self._dbh, typelimit=typelimit, |
636 lpattern=lpattern, llike=llike, |
636 lpattern=lpattern, llike=llike, |
637 dpattern=dpattern, dlike=dlike) |
637 dpattern=dpattern, dlike=dlike) |
638 |
638 |
639 def user_add(self, emailaddress, password): |
639 def user_add(self, emailaddress, password): |
640 """Wrapper around Account.set_password() and Account.save().""" |
640 """Wrapper around Account.set_password() and Account.save().""" |
641 acc = self._get_account(emailaddress) |
641 acc = self._get_account(emailaddress) |
642 if acc: |
642 if acc: |
643 raise VMMError(_(u"The account '%s' already exists.") % |
643 raise VMMError(_("The account '%s' already exists.") % |
644 acc.address, ACCOUNT_EXISTS) |
644 acc.address, ACCOUNT_EXISTS) |
645 self._is_other_address(acc.address, TYPE_ACCOUNT) |
645 self._is_other_address(acc.address, TYPE_ACCOUNT) |
646 acc.set_password(password) |
646 acc.set_password(password) |
647 acc.save() |
647 acc.save() |
648 self._make_account_dirs(acc) |
648 self._make_account_dirs(acc) |
661 self._warnings.append(_('Ignored destination addresses:')) |
661 self._warnings.append(_('Ignored destination addresses:')) |
662 self._warnings.extend((' * %s' % w for w in warnings)) |
662 self._warnings.extend((' * %s' % w for w in warnings)) |
663 for destination in destinations: |
663 for destination in destinations: |
664 if destination.gid and \ |
664 if destination.gid and \ |
665 not self._chk_other_address_types(destination, TYPE_RELOCATED): |
665 not self._chk_other_address_types(destination, TYPE_RELOCATED): |
666 self._warnings.append(_(u"The destination account/alias '%s' " |
666 self._warnings.append(_("The destination account/alias '%s' " |
667 u"does not exist.") % destination) |
667 "does not exist.") % destination) |
668 |
668 |
669 def user_delete(self, emailaddress, force=False): |
669 def user_delete(self, emailaddress, force=False): |
670 """Wrapper around Account.delete(...)""" |
670 """Wrapper around Account.delete(...)""" |
671 if not isinstance(force, bool): |
671 if not isinstance(force, bool): |
672 raise TypeError('force must be a bool') |
672 raise TypeError('force must be a bool') |
673 acc = self._get_account(emailaddress) |
673 acc = self._get_account(emailaddress) |
674 if not acc: |
674 if not acc: |
675 raise VMMError(_(u"The account '%s' does not exist.") % |
675 raise VMMError(_("The account '%s' does not exist.") % |
676 acc.address, NO_SUCH_ACCOUNT) |
676 acc.address, NO_SUCH_ACCOUNT) |
677 uid = acc.uid |
677 uid = acc.uid |
678 gid = acc.gid |
678 gid = acc.gid |
679 dom_dir = acc.domain.directory |
679 dom_dir = acc.domain.directory |
680 acc_dir = acc.home |
680 acc_dir = acc.home |
681 acc.delete(force) |
681 acc.delete(force) |
682 if self._cfg.dget('account.delete_directory'): |
682 if self._cfg.dget('account.delete_directory'): |
683 try: |
683 try: |
684 self._delete_home(dom_dir, uid, gid) |
684 self._delete_home(dom_dir, uid, gid) |
685 except VMMError, err: |
685 except VMMError as err: |
686 if err.code in (FOUND_DOTS_IN_PATH, MAILDIR_PERM_MISMATCH, |
686 if err.code in (FOUND_DOTS_IN_PATH, MAILDIR_PERM_MISMATCH, |
687 NO_SUCH_DIRECTORY): |
687 NO_SUCH_DIRECTORY): |
688 warning = _(u"""\ |
688 warning = _("""\ |
689 The account has been successfully deleted from the database. |
689 The account has been successfully deleted from the database. |
690 But an error occurred while deleting the following directory: |
690 But an error occurred while deleting the following directory: |
691 '%(directory)s' |
691 '%(directory)s' |
692 Reason: %(reason)s""") % {'directory': acc_dir, 'reason': err.msg} |
692 Reason: %(reason)s""") % {'directory': acc_dir, 'reason': err.msg} |
693 self._warnings.append(warning) |
693 self._warnings.append(warning) |
760 destinations = [DestinationEmailAddress(addr, self._dbh) |
760 destinations = [DestinationEmailAddress(addr, self._dbh) |
761 for addr in targetaddresses] |
761 for addr in targetaddresses] |
762 warnings = [] |
762 warnings = [] |
763 try: |
763 try: |
764 catchall.del_destinations(destinations, warnings) |
764 catchall.del_destinations(destinations, warnings) |
765 except VMMError, err: |
765 except VMMError as err: |
766 error = err |
766 error = err |
767 if warnings: |
767 if warnings: |
768 self._warnings.append(_('Ignored destination addresses:')) |
768 self._warnings.append(_('Ignored destination addresses:')) |
769 self._warnings.extend((' * %s' % w for w in warnings)) |
769 self._warnings.extend((' * %s' % w for w in warnings)) |
770 if error: |
770 if error: |
771 raise error |
771 raise error |
772 |
772 |
773 def user_info(self, emailaddress, details=None): |
773 def user_info(self, emailaddress, details=None): |
774 """Wrapper around Account.get_info(...)""" |
774 """Wrapper around Account.get_info(...)""" |
775 if details not in (None, 'du', 'aliases', 'full'): |
775 if details not in (None, 'du', 'aliases', 'full'): |
776 raise VMMError(_(u"Invalid argument: '%s'") % details, |
776 raise VMMError(_("Invalid argument: '%s'") % details, |
777 INVALID_ARGUMENT) |
777 INVALID_ARGUMENT) |
778 acc = self._get_account(emailaddress) |
778 acc = self._get_account(emailaddress) |
779 if not acc: |
779 if not acc: |
780 if not self._is_other_address(acc.address, TYPE_ACCOUNT): |
780 if not self._is_other_address(acc.address, TYPE_ACCOUNT): |
781 raise VMMError(_(u"The account '%s' does not exist.") % |
781 raise VMMError(_("The account '%s' does not exist.") % |
782 acc.address, NO_SUCH_ACCOUNT) |
782 acc.address, NO_SUCH_ACCOUNT) |
783 info = acc.get_info() |
783 info = acc.get_info() |
784 if self._cfg.dget('account.disk_usage') or details in ('du', 'full'): |
784 if self._cfg.dget('account.disk_usage') or details in ('du', 'full'): |
785 path = os.path.join(acc.home, acc.mail_location.directory) |
785 path = os.path.join(acc.home, acc.mail_location.directory) |
786 info['disk usage'] = self._get_disk_usage(path) |
786 info['disk usage'] = self._get_disk_usage(path) |
797 self._db_connect() |
797 self._db_connect() |
798 return get_account_by_uid(uid, self._dbh) |
798 return get_account_by_uid(uid, self._dbh) |
799 |
799 |
800 def user_password(self, emailaddress, password): |
800 def user_password(self, emailaddress, password): |
801 """Wrapper for Account.modify('password' ...).""" |
801 """Wrapper for Account.modify('password' ...).""" |
802 if not isinstance(password, basestring) or not password: |
802 if not isinstance(password, str) or not password: |
803 raise VMMError(_(u"Could not accept password: '%s'") % password, |
803 raise VMMError(_("Could not accept password: '%s'") % password, |
804 INVALID_ARGUMENT) |
804 INVALID_ARGUMENT) |
805 acc = self._get_account(emailaddress) |
805 acc = self._get_account(emailaddress) |
806 if not acc: |
806 if not acc: |
807 raise VMMError(_(u"The account '%s' does not exist.") % |
807 raise VMMError(_("The account '%s' does not exist.") % |
808 acc.address, NO_SUCH_ACCOUNT) |
808 acc.address, NO_SUCH_ACCOUNT) |
809 acc.modify('password', password) |
809 acc.modify('password', password) |
810 |
810 |
811 def user_name(self, emailaddress, name): |
811 def user_name(self, emailaddress, name): |
812 """Wrapper for Account.modify('name', ...).""" |
812 """Wrapper for Account.modify('name', ...).""" |
813 acc = self._get_account(emailaddress) |
813 acc = self._get_account(emailaddress) |
814 if not acc: |
814 if not acc: |
815 raise VMMError(_(u"The account '%s' does not exist.") % |
815 raise VMMError(_("The account '%s' does not exist.") % |
816 acc.address, NO_SUCH_ACCOUNT) |
816 acc.address, NO_SUCH_ACCOUNT) |
817 acc.modify('name', name) |
817 acc.modify('name', name) |
818 |
818 |
819 def user_note(self, emailaddress, note): |
819 def user_note(self, emailaddress, note): |
820 """Wrapper for Account.modify('note', ...).""" |
820 """Wrapper for Account.modify('note', ...).""" |
821 acc = self._get_account(emailaddress) |
821 acc = self._get_account(emailaddress) |
822 if not acc: |
822 if not acc: |
823 raise VMMError(_(u"The account '%s' does not exist.") % |
823 raise VMMError(_("The account '%s' does not exist.") % |
824 acc.address, NO_SUCH_ACCOUNT) |
824 acc.address, NO_SUCH_ACCOUNT) |
825 acc.modify('note', note) |
825 acc.modify('note', note) |
826 |
826 |
827 def user_quotalimit(self, emailaddress, bytes_, messages=0): |
827 def user_quotalimit(self, emailaddress, bytes_, messages=0): |
828 """Wrapper for Account.update_quotalimit(QuotaLimit).""" |
828 """Wrapper for Account.update_quotalimit(QuotaLimit).""" |
829 acc = self._get_account(emailaddress) |
829 acc = self._get_account(emailaddress) |
830 if not acc: |
830 if not acc: |
831 raise VMMError(_(u"The account '%s' does not exist.") % |
831 raise VMMError(_("The account '%s' does not exist.") % |
832 acc.address, NO_SUCH_ACCOUNT) |
832 acc.address, NO_SUCH_ACCOUNT) |
833 if bytes_ == 'domain': |
833 if bytes_ == 'domain': |
834 quotalimit = None |
834 quotalimit = None |
835 else: |
835 else: |
836 if not all(isinstance(i, (int, long)) for i in (bytes_, messages)): |
836 if not all(isinstance(i, int) for i in (bytes_, messages)): |
837 raise TypeError("'bytes_' and 'messages' have to be " |
837 raise TypeError("'bytes_' and 'messages' have to be " |
838 "integers or longs.") |
838 "integers or longs.") |
839 quotalimit = QuotaLimit(self._dbh, bytes=bytes_, |
839 quotalimit = QuotaLimit(self._dbh, bytes=bytes_, |
840 messages=messages) |
840 messages=messages) |
841 acc.update_quotalimit(quotalimit) |
841 acc.update_quotalimit(quotalimit) |
842 |
842 |
843 def user_transport(self, emailaddress, transport): |
843 def user_transport(self, emailaddress, transport): |
844 """Wrapper for Account.update_transport(Transport).""" |
844 """Wrapper for Account.update_transport(Transport).""" |
845 if not isinstance(transport, basestring) or not transport: |
845 if not isinstance(transport, str) or not transport: |
846 raise VMMError(_(u"Could not accept transport: '%s'") % transport, |
846 raise VMMError(_("Could not accept transport: '%s'") % transport, |
847 INVALID_ARGUMENT) |
847 INVALID_ARGUMENT) |
848 acc = self._get_account(emailaddress) |
848 acc = self._get_account(emailaddress) |
849 if not acc: |
849 if not acc: |
850 raise VMMError(_(u"The account '%s' does not exist.") % |
850 raise VMMError(_("The account '%s' does not exist.") % |
851 acc.address, NO_SUCH_ACCOUNT) |
851 acc.address, NO_SUCH_ACCOUNT) |
852 transport = None if transport == 'domain' \ |
852 transport = None if transport == 'domain' \ |
853 else Transport(self._dbh, transport=transport) |
853 else Transport(self._dbh, transport=transport) |
854 acc.update_transport(transport) |
854 acc.update_transport(transport) |
855 |
855 |
856 def user_services(self, emailaddress, *services): |
856 def user_services(self, emailaddress, *services): |
857 """Wrapper around Account.update_serviceset().""" |
857 """Wrapper around Account.update_serviceset().""" |
858 acc = self._get_account(emailaddress) |
858 acc = self._get_account(emailaddress) |
859 if not acc: |
859 if not acc: |
860 raise VMMError(_(u"The account '%s' does not exist.") % |
860 raise VMMError(_("The account '%s' does not exist.") % |
861 acc.address, NO_SUCH_ACCOUNT) |
861 acc.address, NO_SUCH_ACCOUNT) |
862 if len(services) == 1 and services[0] == 'domain': |
862 if len(services) == 1 and services[0] == 'domain': |
863 serviceset = None |
863 serviceset = None |
864 else: |
864 else: |
865 kwargs = dict.fromkeys(SERVICES, False) |
865 kwargs = dict.fromkeys(SERVICES, False) |
866 for service in set(services): |
866 for service in set(services): |
867 if service not in SERVICES: |
867 if service not in SERVICES: |
868 raise VMMError(_(u"Unknown service: '%s'") % service, |
868 raise VMMError(_("Unknown service: '%s'") % service, |
869 UNKNOWN_SERVICE) |
869 UNKNOWN_SERVICE) |
870 kwargs[service] = True |
870 kwargs[service] = True |
871 serviceset = ServiceSet(self._dbh, **kwargs) |
871 serviceset = ServiceSet(self._dbh, **kwargs) |
872 acc.update_serviceset(serviceset) |
872 acc.update_serviceset(serviceset) |
873 |
873 |
880 self._is_other_address(relocated.address, TYPE_RELOCATED) |
880 self._is_other_address(relocated.address, TYPE_RELOCATED) |
881 destination = DestinationEmailAddress(targetaddress, self._dbh) |
881 destination = DestinationEmailAddress(targetaddress, self._dbh) |
882 relocated.set_destination(destination) |
882 relocated.set_destination(destination) |
883 if destination.gid and \ |
883 if destination.gid and \ |
884 not self._chk_other_address_types(destination, TYPE_RELOCATED): |
884 not self._chk_other_address_types(destination, TYPE_RELOCATED): |
885 self._warnings.append(_(u"The destination account/alias '%s' " |
885 self._warnings.append(_("The destination account/alias '%s' " |
886 u"does not exist.") % destination) |
886 "does not exist.") % destination) |
887 |
887 |
888 def relocated_info(self, emailaddress): |
888 def relocated_info(self, emailaddress): |
889 """Returns the target address of the relocated user with the given |
889 """Returns the target address of the relocated user with the given |
890 *emailaddress*.""" |
890 *emailaddress*.""" |
891 relocated = self._get_relocated(emailaddress) |
891 relocated = self._get_relocated(emailaddress) |
892 if relocated: |
892 if relocated: |
893 return relocated.get_info() |
893 return relocated.get_info() |
894 if not self._is_other_address(relocated.address, TYPE_RELOCATED): |
894 if not self._is_other_address(relocated.address, TYPE_RELOCATED): |
895 raise VMMError(_(u"The relocated user '%s' does not exist.") % |
895 raise VMMError(_("The relocated user '%s' does not exist.") % |
896 relocated.address, NO_SUCH_RELOCATED) |
896 relocated.address, NO_SUCH_RELOCATED) |
897 |
897 |
898 def relocated_delete(self, emailaddress): |
898 def relocated_delete(self, emailaddress): |
899 """Deletes the relocated user with the given *emailaddress* from |
899 """Deletes the relocated user with the given *emailaddress* from |
900 the database.""" |
900 the database.""" |