This list is closed, nobody may subscribe to it.
| 2009 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
(2) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2010 |
Jan
(18) |
Feb
(43) |
Mar
(11) |
Apr
(50) |
May
(10) |
Jun
|
Jul
(39) |
Aug
(30) |
Sep
|
Oct
|
Nov
|
Dec
|
| 2011 |
Jan
(14) |
Feb
(43) |
Mar
(2) |
Apr
|
May
|
Jun
|
Jul
(1) |
Aug
|
Sep
(4) |
Oct
(12) |
Nov
(45) |
Dec
(3) |
| 2012 |
Jan
|
Feb
|
Mar
(2) |
Apr
(65) |
May
(2) |
Jun
(19) |
Jul
(6) |
Aug
(19) |
Sep
(23) |
Oct
(11) |
Nov
(21) |
Dec
(16) |
| 2013 |
Jan
(21) |
Feb
(2) |
Mar
(2) |
Apr
|
May
|
Jun
(2) |
Jul
|
Aug
(2) |
Sep
|
Oct
|
Nov
|
Dec
|
| 2014 |
Jan
(4) |
Feb
(34) |
Mar
(10) |
Apr
|
May
|
Jun
(10) |
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
| S | M | T | W | T | F | S |
|---|---|---|---|---|---|---|
|
|
|
|
|
1
|
2
|
3
|
|
4
(1) |
5
|
6
|
7
|
8
|
9
|
10
|
|
11
|
12
(1) |
13
|
14
|
15
|
16
|
17
|
|
18
|
19
|
20
(4) |
21
(2) |
22
(4) |
23
(4) |
24
|
|
25
(1) |
26
(5) |
27
(2) |
28
(5) |
29
(5) |
30
(5) |
31
|
|
From: <nev...@us...> - 2010-07-30 19:15:05
|
details: http://hg.localdomain.org/vmm/rev/1ed85e696748 changeset: 333:1ed85e696748 user: Pascal Volk date: Fri Jul 30 19:14:49 2010 +0000 description: VMM/{account,handler}: Account delete, use the boolean keyword force too. diffstat: VirtualMailManager/account.py | 13 +++++++------ VirtualMailManager/handler.py | 14 ++++++-------- man/de/man1/vmm.1.rst | 4 ++-- man/man1/vmm.1.rst | 4 ++-- 4 files changed, 17 insertions(+), 18 deletions(-) diffs (108 lines): diff -r 352ca7f1b332 -r 1ed85e696748 VirtualMailManager/account.py --- a/VirtualMailManager/account.py Fri Jul 30 15:51:22 2010 +0000 +++ b/VirtualMailManager/account.py Fri Jul 30 19:14:49 2010 +0000 @@ -348,20 +348,21 @@ aliases = [alias[0] for alias in addresses] return aliases - def delete(self, delalias=False): + def delete(self, force=False): """Delete the Account from the database. Argument: - `delalias` : bool - if *delalias* is `True`, all aliases, which points to the Account, - will be also deleted. If there are aliases and *delalias* is + `force` : bool + if *force* is `True`, all aliases, which points to the Account, + will be also deleted. If there are aliases and *force* is `False`, an AccountError will be raised. """ - assert isinstance(delalias, bool) + if not isinstance(force, bool): + raise TypeError('force must be a bool') self._chk_state() dbc = self._dbh.cursor() - if delalias: + if force: dbc.execute('DELETE FROM users WHERE uid = %s', self._uid) # delete also all aliases where the destination address is the same # as for this account. diff -r 352ca7f1b332 -r 1ed85e696748 VirtualMailManager/handler.py --- a/VirtualMailManager/handler.py Fri Jul 30 15:51:22 2010 +0000 +++ b/VirtualMailManager/handler.py Fri Jul 30 19:14:49 2010 +0000 @@ -525,11 +525,10 @@ self._warnings.append(_(u"The destination account/alias '%s' " u"doesn't exist.") % destination) - def user_delete(self, emailaddress, force=None): + def user_delete(self, emailaddress, force=False): """Wrapper around Account.delete(...)""" - if force not in (None, 'delalias'): - raise VMMError(_(u"Invalid argument: '%s'") % force, - INVALID_ARGUMENT) + if not isinstance(force, bool): + raise TypeError('force must be a bool') acc = self._get_account(emailaddress) if not acc: raise VMMError(_(u"The account '%s' doesn't exist.") % @@ -538,7 +537,7 @@ gid = acc.gid dom_dir = acc.domain.directory acc_dir = acc.home - acc.delete(bool(force)) + acc.delete(force) if self._cfg.dget('account.delete_directory'): try: self._delete_home(dom_dir, uid, gid) @@ -548,9 +547,8 @@ warning = _(u"""\ The account has been successfully deleted from the database. But an error occurred while deleting the following directory: - “%(directory)s” - Reason: %(reason)s""") % \ - {'directory': acc_dir, 'reason': err.msg} + '%(directory)s' + Reason: %(reason)s""") % {'directory': acc_dir, 'reason': err.msg} self._warnings.append(warning) else: raise diff -r 352ca7f1b332 -r 1ed85e696748 man/de/man1/vmm.1.rst --- a/man/de/man1/vmm.1.rst Fri Jul 30 15:51:22 2010 +0000 +++ b/man/de/man1/vmm.1.rst Fri Jul 30 19:14:49 2010 +0000 @@ -358,14 +358,14 @@ .. _userdelete: -``userdelete (ud) Adresse [ delalias ]`` +``userdelete (ud) Adresse [ force ]`` Verwenden Sie diesen Unterbefehl um, das Konto mit der angegebenen *Adresse* zu löschen. Sollte es einen oder mehrere Aliase geben, deren Zieladresse mit der *Adresse* des zu löschenden Kontos identisch ist, wird **vmm** die Ausführung des Befehls mit einer entsprechenden Fehlermeldung beenden. Um - dieses zu umgehen, kann das optionale Schlüsselwort **delalias** + dieses zu umgehen, kann das optionale Schlüsselwort **force** angegebenen werden. diff -r 352ca7f1b332 -r 1ed85e696748 man/man1/vmm.1.rst --- a/man/man1/vmm.1.rst Fri Jul 30 15:51:22 2010 +0000 +++ b/man/man1/vmm.1.rst Fri Jul 30 19:14:49 2010 +0000 @@ -334,12 +334,12 @@ .. _userdelete: -``userdelete (ud) address [ delalias ]`` +``userdelete (ud) address [ force ]`` Use this subcommand to delete the account with the given *address*. If there are one or more aliases with an identical destination *address*, **vmm** will abort the requested operation and show an error message. To - prevent this, specify the optional keyword **delalias**. + prevent this, specify the optional keyword **force**. ALIAS SUBCOMMANDS |
|
From: <nev...@us...> - 2010-07-30 15:51:36
|
details: http://hg.localdomain.org/vmm/rev/352ca7f1b332 changeset: 332:352ca7f1b332 user: Pascal Volk date: Fri Jul 30 15:51:22 2010 +0000 description: man/{,de/}man1/vmm.1.rst: Updated domaindelete part. diffstat: man/de/man1/vmm.1.rst | 14 +++++++------- man/man1/vmm.1.rst | 10 +++++----- 2 files changed, 12 insertions(+), 12 deletions(-) diffs (53 lines): diff -r 270b57af85de -r 352ca7f1b332 man/de/man1/vmm.1.rst --- a/man/de/man1/vmm.1.rst Fri Jul 30 15:19:31 2010 +0000 +++ b/man/de/man1/vmm.1.rst Fri Jul 30 15:51:22 2010 +0000 @@ -194,20 +194,20 @@ .. _domaindelete: -``domaindelete (dd) Domain [ delalias | deluser | delall ]`` +``domaindelete (dd) Domain [ force ]`` Mit diesem Unterbefehl wird die angegebene *Domain* gelöscht. - Sollten der *Domain* Konten und/oder Aliase zugeordnet sein, wird **vmm** - die Ausführung des Befehls mit einer entsprechenden Fehlermeldung beenden. + Sollten der *Domain* Konten, Aliase und/oder relocated User zugeordnet + sein, wird **vmm** die Ausführung des Befehls mit einer entsprechenden + Fehlermeldung beenden. - Sollten Sie sich Ihres Vorhabens sicher sein, so kann optional eines der - folgenden Schlüsselwörter angegeben werden: **delalias**, **deluser** - oder **delall**. + Sollten Sie sich Ihres Vorhabens sicher sein, so kann optional das + Schlüsselwort **force** angegeben werden. Sollten Sie wirklich immer wissen was Sie tun, so editieren Sie Ihre *vmm.cfg* und setzen den Wert der Option |domain.force_deletion|_ auf true. Dann werden Sie beim Löschen von Domains nicht mehr wegen vorhanden - Konten/Aliase gewarnt. + Konten, Aliase und/oder relocated User gewarnt. ALIAS-DOMAIN UNTERBEFEHLE diff -r 270b57af85de -r 352ca7f1b332 man/man1/vmm.1.rst --- a/man/man1/vmm.1.rst Fri Jul 30 15:19:31 2010 +0000 +++ b/man/man1/vmm.1.rst Fri Jul 30 15:51:22 2010 +0000 @@ -183,13 +183,13 @@ .. _domaindelete: -``domaindelete (dd) domain [ delalias | deluser | delall ]`` +``domaindelete (dd) domain [ force ]`` This subcommand deletes the specified *domain*. - If there are accounts and/or aliases assigned to the given domain, **vmm** - will abort the requested operation and show an error message. If you know, - what you are doing, you can specify one of the following keywords: - **delalias**, **deluser** or **delall**. + If there are accounts, aliases and/or relocated users assigned to the given + domain, **vmm** will abort the requested operation and show an error + message. If you know, what you are doing, you can specify the keyword + **force**. If you really always know what you are doing, edit your *vmm.cfg* and set the option |domain.force_deletion|_ to true. |
|
From: <nev...@us...> - 2010-07-30 15:19:47
|
details: http://hg.localdomain.org/vmm/rev/270b57af85de changeset: 331:270b57af85de user: Pascal Volk date: Fri Jul 30 15:19:31 2010 +0000 description: VMM/domain: Simplified Domain.delete() related methods and their arguments, VMM/handler: Adjusted to the changes in the domain module. diffstat: VirtualMailManager/domain.py | 77 +++++++++++++++--------------------------- VirtualMailManager/handler.py | 17 +++------ 2 files changed, 34 insertions(+), 60 deletions(-) diffs (147 lines): diff -r 3fe8d6cdbe3a -r 270b57af85de VirtualMailManager/domain.py --- a/VirtualMailManager/domain.py Fri Jul 30 09:45:51 2010 +0000 +++ b/VirtualMailManager/domain.py Fri Jul 30 15:19:31 2010 +0000 @@ -13,10 +13,10 @@ from random import choice from VirtualMailManager.constants import \ - ACCOUNT_AND_ALIAS_PRESENT, ACCOUNT_PRESENT, ALIAS_PRESENT, \ - DOMAIN_ALIAS_EXISTS, DOMAIN_EXISTS, DOMAIN_INVALID, DOMAIN_TOO_LONG, \ - NO_SUCH_DOMAIN + ACCOUNT_AND_ALIAS_PRESENT, DOMAIN_ALIAS_EXISTS, DOMAIN_EXISTS, \ + DOMAIN_INVALID, DOMAIN_TOO_LONG, NO_SUCH_DOMAIN from VirtualMailManager.errors import DomainError as DomErr +from VirtualMailManager.pycompat import any from VirtualMailManager.transport import Transport @@ -83,49 +83,24 @@ self._gid = dbc.fetchone()[0] dbc.close() - def _has(self, what): - """Checks if aliases or accounts are assigned to the domain. - - If there are assigned accounts or aliases True will be returned, - otherwise False will be returned. - - Argument: - - `what` : basestring - "alias" or "users" + def _check_for_addresses(self): + """Checks dependencies for deletion. Raises a DomainError if there + are accounts, aliases and/or relocated users. """ - assert what in ('alias', 'users') dbc = self._dbh.cursor() - if what == 'users': - dbc.execute("SELECT count(gid) FROM users WHERE gid=%s", self._gid) - else: - dbc.execute("SELECT count(gid) FROM alias WHERE gid=%s", self._gid) - count = dbc.fetchone() + dbc.execute('SELECT count(gid) FROM users WHERE gid = %(gid)u ' + 'UNION SELECT count(gid) FROM alias WHERE gid = %(gid)u ' + 'UNION SELECT count(gid) FROM relocated WHERE gid = ' + '%(gid)u' % {'gid': self._gid}) + result = dbc.fetchall() dbc.close() - return count[0] > 0 - - def _chk_delete(self, deluser, delalias): - """Checks dependencies for deletion. - - Arguments: - deluser -- ignore available accounts (bool) - delalias -- ignore available aliases (bool) - """ - if not deluser: - hasuser = self._has('users') - else: - hasuser = False - if not delalias: - hasalias = self._has('alias') - else: - hasalias = False - if hasuser and hasalias: - raise DomErr(_(u'There are accounts and aliases.'), + result = [count[0] for count in result] + if any(result): + keys = ('account_count', 'alias_count', 'relocated_count') + raise DomErr(_(u'There are %(account_count)u accounts, ' + u'%(alias_count)u aliases and %(relocated_count)u ' + u'relocated users.') % dict(zip(keys, result)), ACCOUNT_AND_ALIAS_PRESENT) - elif hasuser: - raise DomErr(_(u'There are accounts.'), ACCOUNT_PRESENT) - elif hasalias: - raise DomErr(_(u'There are aliases.'), ALIAS_PRESENT) def _chk_state(self): """Throws a DomainError if the Domain is new - not saved in the @@ -193,22 +168,26 @@ dbc.close() self._new = False - def delete(self, deluser=False, delalias=False): + def delete(self, force=False): """Deletes the domain. Arguments: - `deluser` : bool - force deletion of all available accounts, default `False` - `delalias` : bool - force deletion of all available aliases, default `False` + `force` : bool + force the deletion of all available accounts, aliases and + relocated users. When *force* is `False` and there are accounts, + aliases and/or relocated users a DomainError will be raised. + Default `False` """ + if not isinstance(force, bool): + raise TypeError('force must be a bool') self._chk_state() - self._chk_delete(deluser, delalias) + if not force: + self._check_for_addresses() dbc = self._dbh.cursor() for tbl in ('alias', 'users', 'relocated', 'domain_name', 'domain_data'): - dbc.execute("DELETE FROM %s WHERE gid = %d" % (tbl, self._gid)) + dbc.execute("DELETE FROM %s WHERE gid = %u" % (tbl, self._gid)) self._dbh.commit() dbc.close() self._gid = 0 diff -r 3fe8d6cdbe3a -r 270b57af85de VirtualMailManager/handler.py --- a/VirtualMailManager/handler.py Fri Jul 30 09:45:51 2010 +0000 +++ b/VirtualMailManager/handler.py Fri Jul 30 15:19:31 2010 +0000 @@ -389,22 +389,17 @@ else: dom.update_transport(trsp, force=True) - def domain_delete(self, domainname, force=None): + def domain_delete(self, domainname, force=False): """Wrapper around Domain.delete()""" - if force and force not in ('deluser', 'delalias', 'delall'): - raise DomainError(_(u"Invalid argument: '%s'") % force, - INVALID_ARGUMENT) + if not isinstance(force, bool): + raise TypeError('force must be a bool') dom = self._get_domain(domainname) gid = dom.gid domdir = dom.directory - if self._cfg.dget('domain.force_deletion') or force == 'delall': - dom.delete(True, True) - elif force == 'deluser': - dom.delete(deluser=True) - elif force == 'delalias': - dom.delete(delalias=True) + if self._cfg.dget('domain.force_deletion') or force: + dom.delete(True) else: - dom.delete() + dom.delete(False) if self._cfg.dget('domain.delete_directory'): self._delete_domain_dir(domdir, gid) |
|
From: <nev...@us...> - 2010-07-30 09:46:03
|
details: http://hg.localdomain.org/vmm/rev/3fe8d6cdbe3a changeset: 330:3fe8d6cdbe3a user: Pascal Volk date: Fri Jul 30 09:45:51 2010 +0000 description: VMM/handler: _make_home() Create the domain directory if it doesn't exist for some reason. diffstat: VirtualMailManager/handler.py | 3 +-- 1 files changed, 1 insertions(+), 2 deletions(-) diffs (13 lines): diff -r 41789df75339 -r 3fe8d6cdbe3a VirtualMailManager/handler.py --- a/VirtualMailManager/handler.py Fri Jul 30 09:37:44 2010 +0000 +++ b/VirtualMailManager/handler.py Fri Jul 30 09:45:51 2010 +0000 @@ -264,8 +264,7 @@ """Create a home directory for the new Account *account*.""" domdir = account.domain.directory if not lisdir(domdir): - raise VMMError(_(u"No such directory: %s") % domdir, - NO_SUCH_DIRECTORY) + self._make_domain_dir(account.domain) os.umask(0007) uid = account.uid os.chdir(domdir) |
|
From: <nev...@us...> - 2010-07-30 09:38:02
|
details: http://hg.localdomain.org/vmm/rev/41789df75339 changeset: 329:41789df75339 user: Pascal Volk date: Fri Jul 30 09:37:44 2010 +0000 description: VMM/account: Replaced property domain_directory by domain. diffstat: VirtualMailManager/account.py | 6 +++--- VirtualMailManager/handler.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diffs (47 lines): diff -r 85972d3ba936 -r 41789df75339 VirtualMailManager/account.py --- a/VirtualMailManager/account.py Thu Jul 29 23:09:44 2010 +0000 +++ b/VirtualMailManager/account.py Fri Jul 30 09:37:44 2010 +0000 @@ -154,10 +154,10 @@ return self._addr @property - def domain_directory(self): - """The directory of the domain the Account belongs to.""" + def domain(self): + """The Domain to which the Account belongs to.""" if self._domain: - return self._domain.directory + return self._domain return None @property diff -r 85972d3ba936 -r 41789df75339 VirtualMailManager/handler.py --- a/VirtualMailManager/handler.py Thu Jul 29 23:09:44 2010 +0000 +++ b/VirtualMailManager/handler.py Fri Jul 30 09:37:44 2010 +0000 @@ -262,7 +262,7 @@ def _make_home(self, account): """Create a home directory for the new Account *account*.""" - domdir = account.domain_directory + domdir = account.domain.directory if not lisdir(domdir): raise VMMError(_(u"No such directory: %s") % domdir, NO_SUCH_DIRECTORY) @@ -279,7 +279,7 @@ `domdir` : basestring The directory of the domain the user belongs to - (commonly AccountObj.domain_directory) + (commonly AccountObj.domain.directory) `uid` : int/long The user's UID (commonly AccountObj.uid) `gid` : int/long @@ -542,7 +542,7 @@ acc.address, NO_SUCH_ACCOUNT) uid = acc.uid gid = acc.gid - dom_dir = acc.domain_directory + dom_dir = acc.domain.directory acc_dir = acc.home acc.delete(bool(force)) if self._cfg.dget('account.delete_directory'): |
|
From: <nev...@us...> - 2010-07-29 23:09:57
|
details: http://hg.localdomain.org/vmm/rev/85972d3ba936 changeset: 328:85972d3ba936 user: Pascal Volk date: Thu Jul 29 23:09:44 2010 +0000 description: VMM/common: Removed unused import. diffstat: VirtualMailManager/common.py | 3 +-- 1 files changed, 1 insertions(+), 2 deletions(-) diffs (13 lines): diff -r bb9ff81928f1 -r 85972d3ba936 VirtualMailManager/common.py --- a/VirtualMailManager/common.py Thu Jul 29 23:06:05 2010 +0000 +++ b/VirtualMailManager/common.py Thu Jul 29 23:09:44 2010 +0000 @@ -13,8 +13,7 @@ import stat from VirtualMailManager import ENCODING -from VirtualMailManager.constants import \ - NOT_EXECUTABLE, NO_SUCH_BINARY, NO_SUCH_DIRECTORY +from VirtualMailManager.constants import NOT_EXECUTABLE, NO_SUCH_BINARY from VirtualMailManager.errors import VMMError |
|
From: <nev...@us...> - 2010-07-29 23:06:20
|
details: http://hg.localdomain.org/vmm/rev/bb9ff81928f1 changeset: 327:bb9ff81928f1 user: Pascal Volk date: Thu Jul 29 23:06:05 2010 +0000 description: VMM/handler: Use more common.lisdir() in Handler's methods _chkenv, _delete_domain_dir, _delete_home, _get_disk_usage, _make_domain_dir, and _make_home. Handler._make_home(): Also check if the domain directory exists. diffstat: VirtualMailManager/handler.py | 38 +++++++++++++++++++++++--------------- 1 files changed, 23 insertions(+), 15 deletions(-) diffs (113 lines): diff -r 8f8d9c4c8332 -r bb9ff81928f1 VirtualMailManager/handler.py --- a/VirtualMailManager/handler.py Thu Jul 29 19:14:19 2010 +0000 +++ b/VirtualMailManager/handler.py Thu Jul 29 23:06:05 2010 +0000 @@ -14,7 +14,6 @@ import os import re -import stat from shutil import rmtree from subprocess import Popen, PIPE @@ -24,7 +23,7 @@ from VirtualMailManager.account import Account from VirtualMailManager.alias import Alias from VirtualMailManager.aliasdomain import AliasDomain -from VirtualMailManager.common import exec_ok +from VirtualMailManager.common import exec_ok, lisdir from VirtualMailManager.config import Config as Cfg from VirtualMailManager.constants import MIN_GID, MIN_UID, \ ACCOUNT_EXISTS, ALIAS_EXISTS, CONF_NOFILE, CONF_NOPERM, CONF_WRONGPERM, \ @@ -119,13 +118,15 @@ """Make sure our base_directory is a directory and that all required executables exists and are executable. If not, a VMMError will be raised""" + dir_created = False basedir = self._cfg.dget('misc.base_directory') if not os.path.exists(basedir): old_umask = os.umask(0006) os.makedirs(basedir, 0771) os.chown(basedir, 0, 0) os.umask(old_umask) - elif not os.path.isdir(basedir): + dir_created = True + if not dir_created and not lisdir(basedir): raise VMMError(_(u"'%(path)s' is not a directory.\n(%(cfg_file)s: " u"section 'misc', option 'base_directory')") % {'path': basedir, 'cfg_file': self._cfg_fname}, @@ -234,7 +235,7 @@ `directory` : basestring The directory to summarize recursively disk usage for """ - if os.path.isdir(directory): + if lisdir(directory): return Popen([self._cfg.dget('bin.du'), "-hs", directory], stdout=PIPE).communicate()[0].split('\t')[0] else: @@ -245,10 +246,15 @@ """Create a directory for the `domain` and its accounts.""" cwd = os.getcwd() hashdir, domdir = domain.directory.split(os.path.sep)[-2:] + dir_created = False os.chdir(self._cfg.dget('misc.base_directory')) - if not os.path.isdir(hashdir): + if not os.path.exists(hashdir): os.mkdir(hashdir, 0711) os.chown(hashdir, 0, 0) + dir_created = True + if not dir_created and not lisdir(hashdir): + raise VMMError(_(u"'%s' is not a directory.") % hashdir, + NO_SUCH_DIRECTORY) os.mkdir(os.path.join(hashdir, domdir), self._cfg.dget('domain.directory_mode')) os.chown(domain.directory, 0, domain.gid) @@ -256,10 +262,15 @@ def _make_home(self, account): """Create a home directory for the new Account *account*.""" + domdir = account.domain_directory + if not lisdir(domdir): + raise VMMError(_(u"No such directory: %s") % domdir, + NO_SUCH_DIRECTORY) os.umask(0007) - os.chdir(account.domain_directory) - os.mkdir('%s' % account.uid, self._cfg.dget('account.directory_mode')) - os.chown('%s' % account.uid, account.uid, account.gid) + uid = account.uid + os.chdir(domdir) + os.mkdir('%s' % uid, self._cfg.dget('account.directory_mode')) + os.chown('%s' % uid, uid, account.gid) def _delete_home(self, domdir, uid, gid): """Delete a user's home directory. @@ -284,12 +295,12 @@ if domdir.count('..'): raise VMMError(_(u'Found ".." in domain directory path: %s') % domdir, FOUND_DOTS_IN_PATH) - if not os.path.isdir(domdir): + if not lisdir(domdir): raise VMMError(_(u"No such directory: %s") % domdir, NO_SUCH_DIRECTORY) os.chdir(domdir) userdir = '%s' % uid - if not os.path.isdir(userdir): + if not lisdir(userdir): self._warnings.append(_(u"No such directory: %s") % os.path.join(domdir, userdir)) return @@ -317,13 +328,10 @@ if domdir.count('..'): raise VMMError(_(u'Found ".." in domain directory path: %s') % domdir, FOUND_DOTS_IN_PATH) - try: - dirst = os.lstat(domdir) - except OSError: - dirst = None - if not dirst or not stat.S_ISDIR(dirst.st_mode): + if not lisdir(domdir): self._warnings.append(_('No such directory: %s') % domdir) return + dirst = os.lstat(domdir) if dirst.st_gid != gid: raise VMMError(_(u'Detected group mismatch in domain directory: ' u'%s') % domdir, DOMAINDIR_GROUP_MISMATCH) |
|
From: <nev...@us...> - 2010-07-29 19:14:39
|
details: http://hg.localdomain.org/vmm/rev/8f8d9c4c8332 changeset: 326:8f8d9c4c8332 user: Pascal Volk date: Thu Jul 29 19:14:19 2010 +0000 description: VMM/common: Replaced function is_dir() by lisdir(). VMM/{config,mailbox}: Adjusted to the above change. diffstat: VirtualMailManager/common.py | 18 +++++++++--------- VirtualMailManager/config.py | 14 +++++++++++++- VirtualMailManager/mailbox.py | 5 ++--- 3 files changed, 24 insertions(+), 13 deletions(-) diffs (89 lines): diff -r 06c0457036a0 -r 8f8d9c4c8332 VirtualMailManager/common.py --- a/VirtualMailManager/common.py Thu Jul 29 04:01:43 2010 +0000 +++ b/VirtualMailManager/common.py Thu Jul 29 19:14:19 2010 +0000 @@ -10,6 +10,7 @@ import os import re +import stat from VirtualMailManager import ENCODING from VirtualMailManager.constants import \ @@ -39,16 +40,15 @@ return unicode(string, ENCODING, 'replace') -def is_dir(path): - """Checks if `path` is a directory. - - Throws a `VMMError` if `path` is not a directory. +def lisdir(path): + """Checks if `path` is a directory. Doesn't follow symbolic links. + Returns bool. """ - path = expand_path(path) - if not os.path.isdir(path): - raise VMMError(_(u"'%s' is not a directory") % get_unicode(path), - NO_SUCH_DIRECTORY) - return path + try: + lstat = os.lstat(path) + except OSError: + return False + return stat.S_ISDIR(lstat.st_mode) def exec_ok(binary): diff -r 06c0457036a0 -r 8f8d9c4c8332 VirtualMailManager/config.py --- a/VirtualMailManager/config.py Thu Jul 29 04:01:43 2010 +0000 +++ b/VirtualMailManager/config.py Thu Jul 29 19:14:19 2010 +0000 @@ -15,7 +15,8 @@ ParsingError, RawConfigParser from cStringIO import StringIO# TODO: move interactive stff to cli -from VirtualMailManager.common import exec_ok, get_unicode, is_dir, version_hex +from VirtualMailManager.common import \ + exec_ok, expand_path, get_unicode, lisdir, version_hex from VirtualMailManager.constants import CONF_ERROR from VirtualMailManager.errors import ConfigError, VMMError from VirtualMailManager.maillocation import known_format @@ -411,6 +412,17 @@ return not errors +def is_dir(path): + """Check if the expanded path is a directory. When the expanded path + is a directory the expanded path will be returned. Otherwise a + ConfigValueError will be raised. + """ + path = expand_path(path) + if lisdir(path): + return path + raise ConfigValueError(_(u"No such directory: %s") % get_unicode(path)) + + def check_mailbox_format(format): """ Check if the mailbox format *format* is supported. When the *format* diff -r 06c0457036a0 -r 8f8d9c4c8332 VirtualMailManager/mailbox.py --- a/VirtualMailManager/mailbox.py Thu Jul 29 04:01:43 2010 +0000 +++ b/VirtualMailManager/mailbox.py Thu Jul 29 19:14:19 2010 +0000 @@ -15,7 +15,7 @@ from subprocess import Popen, PIPE from VirtualMailManager.account import Account -from VirtualMailManager.common import is_dir +from VirtualMailManager.common import lisdir from VirtualMailManager.errors import VMMError from VirtualMailManager.constants import VMM_ERROR @@ -94,8 +94,7 @@ Creates a new mailbox instance. Use one of the `Maildir`, `SingleDbox` or `MultiDbox` classes. """ - assert isinstance(account, Account) - is_dir(account.home) + assert isinstance(account, Account) and lisdir(account.home) self._user = account self._boxes = [] self._root = self._user.mail_location.directory |
|
From: <nev...@us...> - 2010-07-29 04:01:57
|
details: http://hg.localdomain.org/vmm/rev/06c0457036a0 changeset: 325:06c0457036a0 user: Pascal Volk date: Thu Jul 29 04:01:43 2010 +0000 description: VMM/handler: Reworked methods _get_disk_usage, _delete_home and _delete_domain_dir. Deleted method _isdir. diffstat: VirtualMailManager/handler.py | 124 +++++++++++++++++++++++++---------------- 1 files changed, 74 insertions(+), 50 deletions(-) diffs (169 lines): diff -r 38e344ba3d0f -r 06c0457036a0 VirtualMailManager/handler.py --- a/VirtualMailManager/handler.py Thu Jul 29 01:48:25 2010 +0000 +++ b/VirtualMailManager/handler.py Thu Jul 29 04:01:43 2010 +0000 @@ -14,6 +14,7 @@ import os import re +import stat from shutil import rmtree from subprocess import Popen, PIPE @@ -25,7 +26,7 @@ from VirtualMailManager.aliasdomain import AliasDomain from VirtualMailManager.common import exec_ok from VirtualMailManager.config import Config as Cfg -from VirtualMailManager.constants import \ +from VirtualMailManager.constants import MIN_GID, MIN_UID, \ ACCOUNT_EXISTS, ALIAS_EXISTS, CONF_NOFILE, CONF_NOPERM, CONF_WRONGPERM, \ DATABASE_ERROR, DOMAINDIR_GROUP_MISMATCH, DOMAIN_INVALID, \ FOUND_DOTS_IN_PATH, INVALID_ARGUMENT, MAILDIR_PERM_MISMATCH, \ @@ -36,7 +37,7 @@ from VirtualMailManager.errors import \ DomainError, NotRootError, PermissionError, VMMError from VirtualMailManager.mailbox import new as new_mailbox -from VirtualMailManager.pycompat import any +from VirtualMailManager.pycompat import all, any from VirtualMailManager.relocated import Relocated from VirtualMailManager.transport import Transport @@ -228,24 +229,18 @@ def _get_disk_usage(self, directory): """Estimate file space usage for the given directory. - Keyword arguments: - directory -- the directory to summarize recursively disk usage for + Arguments: + + `directory` : basestring + The directory to summarize recursively disk usage for """ - if self._isdir(directory): + if os.path.isdir(directory): return Popen([self._cfg.dget('bin.du'), "-hs", directory], - stdout=PIPE).communicate()[0].split('\t')[0] + stdout=PIPE).communicate()[0].split('\t')[0] else: + self._warnings.append(_('No such directory: %s') % directory) return 0 - def _isdir(self, directory): - """Check if `directory` is a directory. Returns bool. - When `directory` isn't a directory, a warning will be appended to - _warnings.""" - isdir = os.path.isdir(directory) - if not isdir: - self._warnings.append(_('No such directory: %s') % directory) - return isdir - def _make_domain_dir(self, domain): """Create a directory for the `domain` and its accounts.""" cwd = os.getcwd() @@ -267,43 +262,72 @@ os.chown('%s' % account.uid, account.uid, account.gid) def _delete_home(self, domdir, uid, gid): - """Delete a user's home directory.""" - if uid > 0 and gid > 0: - userdir = '%s' % uid - if userdir.count('..') or domdir.count('..'): - raise VMMError(_(u'Found ".." in home directory path.'), - FOUND_DOTS_IN_PATH) - if os.path.isdir(domdir): - os.chdir(domdir) - if os.path.isdir(userdir): - mdstat = os.stat(userdir) - if (mdstat.st_uid, mdstat.st_gid) != (uid, gid): - raise VMMError(_(u'Detected owner/group mismatch in ' - u'home directory.'), - MAILDIR_PERM_MISMATCH) - rmtree(userdir, ignore_errors=True) - else: - raise VMMError(_(u"No such directory: %s") % - os.path.join(domdir, userdir), - NO_SUCH_DIRECTORY) + """Delete a user's home directory. + + Arguments: + + `domdir` : basestring + The directory of the domain the user belongs to + (commonly AccountObj.domain_directory) + `uid` : int/long + The user's UID (commonly AccountObj.uid) + `gid` : int/long + The user's GID (commonly AccountObj.gid) + """ + assert all(isinstance(xid, (long, int)) for xid in (uid, gid)) and \ + isinstance(domdir, basestring) + if uid < MIN_UID or gid < MIN_GID: + raise VMMError(_(u"UID '%(uid)u' and/or GID '%(gid)u' are less " + u"than %(min_uid)u/%(min_gid)u.") % {'uid': uid, + 'gid': gid, 'min_gid': MIN_GID, 'min_uid': MIN_UID}, + MAILDIR_PERM_MISMATCH) + if domdir.count('..'): + raise VMMError(_(u'Found ".." in domain directory path: %s') % + domdir, FOUND_DOTS_IN_PATH) + if not os.path.isdir(domdir): + raise VMMError(_(u"No such directory: %s") % domdir, + NO_SUCH_DIRECTORY) + os.chdir(domdir) + userdir = '%s' % uid + if not os.path.isdir(userdir): + self._warnings.append(_(u"No such directory: %s") % + os.path.join(domdir, userdir)) + return + mdstat = os.lstat(userdir) + if (mdstat.st_uid, mdstat.st_gid) != (uid, gid): + raise VMMError(_(u'Detected owner/group mismatch in home ' + u'directory.'), MAILDIR_PERM_MISMATCH) + rmtree(userdir, ignore_errors=True) def _delete_domain_dir(self, domdir, gid): - """Delete a domain's directory.""" - if gid > 0: - if not self._isdir(domdir): - return - basedir = self._cfg.dget('misc.base_directory') - domdirdirs = domdir.replace(basedir + '/', '').split('/') - domdirparent = os.path.join(basedir, domdirdirs[0]) - if basedir.count('..') or domdir.count('..'): - raise VMMError(_(u'Found ".." in domain directory path.'), - FOUND_DOTS_IN_PATH) - if os.path.isdir(domdirparent): - os.chdir(domdirparent) - if os.lstat(domdirdirs[1]).st_gid != gid: - raise VMMError(_(u'Detected group mismatch in domain ' - u'directory.'), DOMAINDIR_GROUP_MISMATCH) - rmtree(domdirdirs[1], ignore_errors=True) + """Delete a domain's directory. + + Arguments: + + `domdir` : basestring + The domain's directory (commonly DomainObj.directory) + `gid` : int/long + The domain's GID (commonly DomainObj.gid) + """ + assert isinstance(domdir, basestring) and isinstance(gid, (long, int)) + if gid < MIN_GID: + raise VMMError(_(u"GID '%(gid)u' is less than '%(min_gid)u'.") % + {'gid': gid, 'min_gid': MIN_GID}, + DOMAINDIR_GROUP_MISMATCH) + if domdir.count('..'): + raise VMMError(_(u'Found ".." in domain directory path: %s') % + domdir, FOUND_DOTS_IN_PATH) + try: + dirst = os.lstat(domdir) + except OSError: + dirst = None + if not dirst or not stat.S_ISDIR(dirst.st_mode): + self._warnings.append(_('No such directory: %s') % domdir) + return + if dirst.st_gid != gid: + raise VMMError(_(u'Detected group mismatch in domain directory: ' + u'%s') % domdir, DOMAINDIR_GROUP_MISMATCH) + rmtree(domdir, ignore_errors=True) def has_warnings(self): """Checks if warnings are present, returns bool.""" |
|
From: <nev...@us...> - 2010-07-29 02:04:52
|
details: http://hg.localdomain.org/vmm/rev/38e344ba3d0f changeset: 324:38e344ba3d0f user: Pascal Volk date: Thu Jul 29 01:48:25 2010 +0000 description: VMM/constants: Added MIN_GID and MIN_UID. diffstat: VirtualMailManager/constants.py | 7 +++++++ 1 files changed, 7 insertions(+), 0 deletions(-) diffs (24 lines): diff -r d58cc465dc61 -r 38e344ba3d0f VirtualMailManager/constants.py --- a/VirtualMailManager/constants.py Wed Jul 28 03:48:30 2010 +0000 +++ b/VirtualMailManager/constants.py Thu Jul 29 01:48:25 2010 +0000 @@ -7,6 +7,7 @@ VirtualMailManager's constants: * version information + * upper and lower limits MIN_* / MAX_* * exit codes * error codes """ @@ -22,6 +23,12 @@ __version__ = VERSION +# limits + +MIN_GID = 70000 +MIN_UID = 70000 + + # exit codes EX_SUCCESS = 0 |
|
From: <nev...@us...> - 2010-07-28 03:48:44
|
details: http://hg.localdomain.org/vmm/rev/d58cc465dc61 changeset: 323:d58cc465dc61 user: Pascal Volk date: Wed Jul 28 03:48:30 2010 +0000 description: VMM/mailbox: Removed accidentally committed debug print statement. diffstat: VirtualMailManager/mailbox.py | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diffs (11 lines): diff -r 94bd10e237e5 -r d58cc465dc61 VirtualMailManager/mailbox.py --- a/VirtualMailManager/mailbox.py Wed Jul 28 03:43:59 2010 +0000 +++ b/VirtualMailManager/mailbox.py Wed Jul 28 03:48:30 2010 +0000 @@ -249,7 +249,6 @@ if subscribe: cmd_args.append('-s') cmd_args.extend(mailboxes) - print '\n -> %r\n' % cmd_args process = Popen(cmd_args, stdout=PIPE, stderr=PIPE) stdout, stderr = process.communicate() if process.returncode: |
|
From: <nev...@us...> - 2010-07-28 03:44:14
|
details: http://hg.localdomain.org/vmm/rev/94bd10e237e5 changeset: 322:94bd10e237e5 user: Pascal Volk date: Wed Jul 28 03:43:59 2010 +0000 description: VMM/…: More PEP-8 fixes; eliminated __names. VMM/emailaddress: Fixed™ methods __eq__ and __ne__. (I'm not pylint's nanny.) diffstat: VirtualMailManager/alias.py | 14 +++++++------- VirtualMailManager/cli/config.py | 6 +++--- VirtualMailManager/config.py | 4 ++-- VirtualMailManager/emailaddress.py | 8 ++++---- VirtualMailManager/mailbox.py | 15 ++++++--------- VirtualMailManager/relocated.py | 4 ++-- 6 files changed, 24 insertions(+), 27 deletions(-) diffs (174 lines): diff -r 883d5cd66498 -r 94bd10e237e5 VirtualMailManager/alias.py --- a/VirtualMailManager/alias.py Wed Jul 28 02:52:08 2010 +0000 +++ b/VirtualMailManager/alias.py Wed Jul 28 03:43:59 2010 +0000 @@ -35,9 +35,9 @@ self._addr.domainname, NO_SUCH_DOMAIN) self._dests = [] - self.__load_dests() + self._load_dests() - def __load_dests(self): + def _load_dests(self): """Loads all known destination addresses into the _dests list.""" dbc = self._dbh.cursor() dbc.execute('SELECT destination FROM alias WHERE gid = %s AND ' @@ -47,7 +47,7 @@ self._dests.extend(EmailAddress(dest[0]) for dest in dests) dbc.close() - def __check_expansion(self, count_new): + def _check_expansion(self, count_new): """Checks the current expansion limit of the alias.""" postconf = Postconf(cfg_dget('bin.postconf')) limit = long(postconf.read('virtual_alias_expansion_limit')) @@ -72,7 +72,7 @@ 'limit': limit, 'count_new': count_new}, ALIAS_EXCEEDS_EXPANSION_LIMIT) - def __delete(self, destination=None): + def _delete(self, destination=None): """Deletes a destination from the alias, if ``destination`` is not ``None``. If ``destination`` is None, the alias with all its destination addresses will be deleted. @@ -123,7 +123,7 @@ warnings.extend(duplicates) if not destinations: return destinations - self.__check_expansion(len(destinations)) + self._check_expansion(len(destinations)) dbc = self._dbh.cursor() dbc.executemany("INSERT INTO alias VALUES (%d, '%s', %%s)" % (self._gid, self._addr.localpart), @@ -143,7 +143,7 @@ raise AErr(_(u"The address '%(addr)s' isn't a destination of " u"the alias '%(alias)s'.") % {'addr': self._addr, 'alias': destination}, NO_SUCH_ALIAS) - self.__delete(destination) + self._delete(destination) self._dests.remove(destination) def get_destinations(self): @@ -158,7 +158,7 @@ if not self._dests: raise AErr(_(u"The alias '%s' doesn't exist.") % self._addr, NO_SUCH_ALIAS) - self.__delete() + self._delete() del self._dests[:] del _, cfg_dget diff -r 883d5cd66498 -r 94bd10e237e5 VirtualMailManager/cli/config.py --- a/VirtualMailManager/cli/config.py Wed Jul 28 02:52:08 2010 +0000 +++ b/VirtualMailManager/cli/config.py Wed Jul 28 03:43:59 2010 +0000 @@ -57,7 +57,7 @@ break print if self._modified: - self.__save_changes() + self._save_changes() def set(self, option, value): """Set the value of an option. @@ -81,9 +81,9 @@ if not RawConfigParser.has_section(self, section): self.add_section(section) RawConfigParser.set(self, section, option_, val) - self.__save_changes() + self._save_changes() - def __save_changes(self): + def _save_changes(self): """Writes changes to the configuration file.""" copy2(self._cfg_filename, self._cfg_filename + '.bak') self._cfg_file = open(self._cfg_filename, 'w') diff -r 883d5cd66498 -r 94bd10e237e5 VirtualMailManager/config.py --- a/VirtualMailManager/config.py Wed Jul 28 02:52:08 2010 +0000 +++ b/VirtualMailManager/config.py Wed Jul 28 03:43:59 2010 +0000 @@ -370,7 +370,7 @@ """ # TODO: There are only two settings w/o defaults. # So there is no need for cStringIO - if not self.__chk_cfg(): + if not self._chk_cfg(): errmsg = StringIO() errmsg.write(_(u'Missing options, which have no default value.\n')) errmsg.write(_(u'Using configuration file: %s\n') % @@ -392,7 +392,7 @@ to Unicode.""" return get_unicode(self.get(section, option)) - def __chk_cfg(self): + def _chk_cfg(self): """Checks all section's options for settings w/o a default value. diff -r 883d5cd66498 -r 94bd10e237e5 VirtualMailManager/emailaddress.py --- a/VirtualMailManager/emailaddress.py Wed Jul 28 02:52:08 2010 +0000 +++ b/VirtualMailManager/emailaddress.py Wed Jul 28 03:43:59 2010 +0000 @@ -42,14 +42,14 @@ def __eq__(self, other): if isinstance(other, self.__class__): - return self._localpart == other.localpart and \ - self._domainname == other.domainname + return self._localpart == other._localpart and \ + self._domainname == other._domainname return NotImplemented def __ne__(self, other): if isinstance(other, self.__class__): - return self._localpart != other.localpart or \ - self._domainname != other.domainname + return self._localpart != other._localpart or \ + self._domainname != other._domainname return NotImplemented def __hash__(self): diff -r 883d5cd66498 -r 94bd10e237e5 VirtualMailManager/mailbox.py --- a/VirtualMailManager/mailbox.py Wed Jul 28 02:52:08 2010 +0000 +++ b/VirtualMailManager/mailbox.py Wed Jul 28 03:43:59 2010 +0000 @@ -275,18 +275,15 @@ __slots__ = () -def __get_mailbox_class(mbfmt): +def new(account): + """Create a new Mailbox instance for the given Account.""" + mbfmt = account.mail_location.mbformat if mbfmt == 'maildir': - return Maildir + return Maildir(account) elif mbfmt == 'mdbox': - return MultiDbox + return MultiDbox(account) elif mbfmt == 'sdbox': - return SingleDbox + return SingleDbox(account) raise ValueError('unsupported mailbox format: %r' % mbfmt) - -def new(account): - """Create a new Mailbox instance for the given Account.""" - return __get_mailbox_class(account.mail_location.mbformat)(account) - del cfg_dget diff -r 883d5cd66498 -r 94bd10e237e5 VirtualMailManager/relocated.py --- a/VirtualMailManager/relocated.py Wed Jul 28 02:52:08 2010 +0000 +++ b/VirtualMailManager/relocated.py Wed Jul 28 03:43:59 2010 +0000 @@ -39,13 +39,13 @@ self._addr.domainname, NO_SUCH_DOMAIN) self._dest = None - self.__load() + self._load() def __nonzero__(self): """Returns `True` if the Relocated is known, `False` if it's new.""" return self._dest is not None - def __load(self): + def _load(self): """Loads the destination address from the database into the `_dest` attribute. |
|
From: <nev...@us...> - 2010-07-28 02:52:21
|
details: http://hg.localdomain.org/vmm/rev/883d5cd66498 changeset: 321:883d5cd66498 user: Pascal Volk date: Wed Jul 28 02:52:08 2010 +0000 description: VMM/transport: Converted _mixedCase method names to _lower_case_with_underscores. Added missing docstrings. Fixed™ methods __eq__ and __ne__. (I'm not pylint's nanny.) diffstat: VirtualMailManager/transport.py | 19 +++++++++++++------ 1 files changed, 13 insertions(+), 6 deletions(-) diffs (73 lines): diff -r 011066435e6f -r 883d5cd66498 VirtualMailManager/transport.py --- a/VirtualMailManager/transport.py Wed Jul 28 02:08:03 2010 +0000 +++ b/VirtualMailManager/transport.py Wed Jul 28 02:52:08 2010 +0000 @@ -13,6 +13,8 @@ from VirtualMailManager.errors import TransportError from VirtualMailManager.pycompat import any +_ = lambda msg: msg + class Transport(object): """A wrapper class that provides access to the transport table""" @@ -35,11 +37,11 @@ if tid: assert not isinstance(tid, bool) and isinstance(tid, (int, long)) self._tid = tid - self._loadByID() + self._load_by_id() else: assert isinstance(transport, basestring) self._transport = transport - self._loadByName() + self._load_by_name() @property def tid(self): @@ -53,18 +55,19 @@ def __eq__(self, other): if isinstance(other, self.__class__): - return self._tid == other.tid + return self._tid == other._tid return NotImplemented def __ne__(self, other): if isinstance(other, self.__class__): - return self._tid != other.tid + return self._tid != other._tid return NotImplemented def __str__(self): return self._transport - def _loadByID(self): + def _load_by_id(self): + """load a transport by its id from the database""" dbc = self._dbh.cursor() dbc.execute('SELECT transport FROM transport WHERE tid=%s', self._tid) result = dbc.fetchone() @@ -75,7 +78,8 @@ raise TransportError(_(u'Unknown tid specified.'), UNKNOWN_TRANSPORT_ID) - def _loadByName(self): + def _load_by_name(self): + """Load a transport by its transport name from the database.""" dbc = self._dbh.cursor() dbc.execute('SELECT tid FROM transport WHERE transport = %s', self._transport) @@ -87,6 +91,7 @@ self._save() def _save(self): + """Save the new transport in the database.""" dbc = self._dbh.cursor() dbc.execute("SELECT nextval('transport_id')") self._tid = dbc.fetchone()[0] @@ -94,3 +99,5 @@ self._transport) self._dbh.commit() dbc.close() + +del _ |
|
From: <nev...@us...> - 2010-07-28 02:08:21
|
details: http://hg.localdomain.org/vmm/rev/011066435e6f changeset: 320:011066435e6f user: Pascal Volk date: Wed Jul 28 02:08:03 2010 +0000 description: VMM/*: Made all modules names lowercase, adjusted imports. diffstat: VirtualMailManager/Account.py | 421 ----------------------- VirtualMailManager/Alias.py | 165 --------- VirtualMailManager/AliasDomain.py | 144 -------- VirtualMailManager/Config.py | 452 ------------------------- VirtualMailManager/Domain.py | 409 ----------------------- VirtualMailManager/EmailAddress.py | 104 ----- VirtualMailManager/Handler.py | 657 ------------------------------------- VirtualMailManager/Relocated.py | 115 ------ VirtualMailManager/Transport.py | 97 ----- VirtualMailManager/__init__.py | 2 +- VirtualMailManager/account.py | 420 +++++++++++++++++++++++ VirtualMailManager/alias.py | 164 +++++++++ VirtualMailManager/aliasdomain.py | 143 ++++++++ VirtualMailManager/cli/Config.py | 94 ----- VirtualMailManager/cli/Handler.py | 84 ---- VirtualMailManager/cli/__init__.py | 1 - VirtualMailManager/cli/config.py | 93 +++++ VirtualMailManager/cli/handler.py | 84 ++++ VirtualMailManager/common.py | 2 +- VirtualMailManager/config.py | 451 +++++++++++++++++++++++++ VirtualMailManager/domain.py | 408 ++++++++++++++++++++++ VirtualMailManager/emailaddress.py | 103 +++++ VirtualMailManager/errors.py | 3 +- VirtualMailManager/ext/Postconf.py | 127 ------- VirtualMailManager/ext/postconf.py | 127 +++++++ VirtualMailManager/handler.py | 657 +++++++++++++++++++++++++++++++++++++ VirtualMailManager/mailbox.py | 3 +- VirtualMailManager/maillocation.py | 1 - VirtualMailManager/password.py | 4 +- VirtualMailManager/relocated.py | 114 ++++++ VirtualMailManager/transport.py | 96 +++++ 31 files changed, 2867 insertions(+), 2878 deletions(-) diffs (truncated from 5940 to 300 lines): diff -r f4956b4ceba1 -r 011066435e6f VirtualMailManager/Account.py --- a/VirtualMailManager/Account.py Wed Jul 28 01:03:56 2010 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,421 +0,0 @@ -# -*- coding: UTF-8 -*- -# Copyright (c) 2007 - 2010, Pascal Volk -# See COPYING for distribution information. - -""" - VirtualMailManager.Account - ~~~~~~~~~~~~~~~~~~~~~~~~~~ - - Virtual Mail Manager's Account class to manage e-mail accounts. -""" - -from VirtualMailManager.Domain import Domain -from VirtualMailManager.EmailAddress import EmailAddress -from VirtualMailManager.Transport import Transport -from VirtualMailManager.common import version_str -from VirtualMailManager.constants import \ - ACCOUNT_EXISTS, ACCOUNT_MISSING_PASSWORD, ALIAS_PRESENT, \ - INVALID_ARGUMENT, INVALID_MAIL_LOCATION, NO_SUCH_ACCOUNT, \ - NO_SUCH_DOMAIN, UNKNOWN_SERVICE -from VirtualMailManager.errors import AccountError as AErr -from VirtualMailManager.maillocation import MailLocation -from VirtualMailManager.password import pwhash - - -_ = lambda msg: msg -cfg_dget = lambda option: None - - -class Account(object): - """Class to manage e-mail accounts.""" - __slots__ = ('_addr', '_dbh', '_domain', '_mail', '_new', '_passwd', - '_transport', '_uid') - - def __init__(self, dbh, address): - """Creates a new Account instance. - - When an account with the given *address* could be found in the - database all relevant data will be loaded. - - Arguments: - - `dbh` : pyPgSQL.PgSQL.Connection - A database connection for the database access. - `address` : VirtualMailManager.EmailAddress.EmailAddress - The e-mail address of the (new) Account. - """ - if not isinstance(address, EmailAddress): - raise TypeError("Argument 'address' is not an EmailAddress") - self._addr = address - self._dbh = dbh - self._domain = Domain(self._dbh, self._addr.domainname) - if not self._domain.gid: - raise AErr(_(u"The domain '%s' doesn't exist.") % - self._addr.domainname, NO_SUCH_DOMAIN) - self._uid = 0 - self._mail = None - self._transport = self._domain.transport - self._passwd = None - self._new = True - self._load() - - def __nonzero__(self): - """Returns `True` if the Account is known, `False` if it's new.""" - return not self._new - - def _load(self): - """Load 'uid', 'mid' and 'tid' from the database and set _new to - `False` - if the user could be found. """ - dbc = self._dbh.cursor() - dbc.execute('SELECT uid, mid, tid FROM users WHERE gid = %s AND ' - 'local_part = %s', self._domain.gid, self._addr.localpart) - result = dbc.fetchone() - dbc.close() - if result: - self._uid, _mid, _tid = result - if _tid != self._transport.tid: - self._transport = Transport(self._dbh, tid=_tid) - self._mail = MailLocation(self._dbh, mid=_mid) - self._new = False - - def _set_uid(self): - """Set the unique ID for the new Account.""" - assert self._uid == 0 - dbc = self._dbh.cursor() - dbc.execute("SELECT nextval('users_uid')") - self._uid = dbc.fetchone()[0] - dbc.close() - - def _prepare(self, maillocation): - """Check and set different attributes - before we store the - information in the database. - """ - if maillocation.dovecot_version > cfg_dget('misc.dovecot_version'): - raise AErr(_(u"The mailbox format '%(mbfmt)s' requires Dovecot " - u">= v%(version)s") % {'mbfmt': maillocation.mbformat, - 'version': version_str(maillocation.dovecot_version)}, - INVALID_MAIL_LOCATION) - if not maillocation.postfix and \ - self._transport.transport.lower() in ('virtual:', 'virtual'): - raise AErr(_(u"Invalid transport '%(transport)s' for mailbox " - u"format '%(mbfmt)s'") % - {'transport': self._transport, - 'mbfmt': maillocation.mbformat}, INVALID_MAIL_LOCATION) - self._mail = maillocation - self._set_uid() - - def _switch_state(self, state, service): - """Switch the state of the Account's services on or off. See - Account.enable()/Account.disable() for more information.""" - self._chk_state() - if service not in (None, 'all', 'imap', 'pop3', 'sieve', 'smtp'): - raise AErr(_(u"Unknown service: '%s'.") % service, UNKNOWN_SERVICE) - if cfg_dget('misc.dovecot_version') >= 0x10200b02: - sieve_col = 'sieve' - else: - sieve_col = 'managesieve' - if service in ('smtp', 'pop3', 'imap'): - sql = 'UPDATE users SET %s = %s WHERE uid = %d' % (service, state, - self._uid) - elif service == 'sieve': - sql = 'UPDATE users SET %s = %s WHERE uid = %d' % (sieve_col, - state, - self._uid) - else: - sql = 'UPDATE users SET smtp = %(s)s, pop3 = %(s)s, imap = %(s)s,\ - %(col)s = %(s)s WHERE uid = %(uid)d' % \ - {'s': state, 'col': sieve_col, 'uid': self._uid} - dbc = self._dbh.cursor() - dbc.execute(sql) - if dbc.rowcount > 0: - self._dbh.commit() - dbc.close() - - def _count_aliases(self): - """Count all alias addresses where the destination address is the - address of the Account.""" - dbc = self._dbh.cursor() - sql = "SELECT COUNT(destination) FROM alias WHERE destination = '%s'"\ - % self._addr - dbc.execute(sql) - a_count = dbc.fetchone()[0] - dbc.close() - return a_count - - def _chk_state(self): - """Raise an AccountError if the Account is new - not yet saved in the - database.""" - if self._new: - raise AErr(_(u"The account '%s' doesn't exist.") % self._addr, - NO_SUCH_ACCOUNT) - - @property - def address(self): - """The Account's EmailAddress instance.""" - return self._addr - - @property - def domain_directory(self): - """The directory of the domain the Account belongs to.""" - if self._domain: - return self._domain.directory - return None - - @property - def gid(self): - """The Account's group ID.""" - if self._domain: - return self._domain.gid - return None - - @property - def home(self): - """The Account's home directory.""" - if not self._new: - return '%s/%s' % (self._domain.directory, self._uid) - return None - - @property - def mail_location(self): - """The Account's MailLocation.""" - return self._mail - - @property - def uid(self): - """The Account's unique ID.""" - return self._uid - - def set_password(self, password): - """Set a password for the new Account. - - If you want to update the password of an existing Account use - Account.modify(). - - Argument: - - `password` : basestring - The password for the new Account. - """ - if not isinstance(password, basestring) or not password: - raise AErr(_(u"Couldn't accept password: '%s'") % password, - ACCOUNT_MISSING_PASSWORD) - self._passwd = password - - def set_transport(self, transport): - """Set the transport for the new Account. - - If you want to update the transport of an existing Account use - Account.modify(). - - Argument: - - `transport` : basestring - The string representation of the transport, e.g.: 'dovecot:' - """ - self._transport = Transport(self._dbh, transport=transport) - - def enable(self, service=None): - """Enable a/all service/s for the Account. - - Possible values for the *service* are: 'imap', 'pop3', 'sieve' and - 'smtp'. When all services should be enabled, use 'all' or the - default value `None`. - - Arguments: - - `service` : basestring - The name of a service ('imap', 'pop3', 'smtp', 'sieve'), 'all' - or `None`. - """ - self._switch_state(True, service) - - def disable(self, service=None): - """Disable a/all service/s for the Account. - - For more information see: Account.enable().""" - self._switch_state(False, service) - - def save(self): - """Save the new Account in the database.""" - if not self._new: - raise AErr(_(u"The account '%s' already exists.") % self._addr, - ACCOUNT_EXISTS) - if not self._passwd: - raise AErr(_(u"No password set for '%s'.") % self._addr, - ACCOUNT_MISSING_PASSWORD) - if cfg_dget('misc.dovecot_version') >= 0x10200b02: - sieve_col = 'sieve' - else: - sieve_col = 'managesieve' - self._prepare(MailLocation(self._dbh, mbfmt=cfg_dget('mailbox.format'), - directory=cfg_dget('mailbox.root'))) - sql = "INSERT INTO users (local_part, passwd, uid, gid, mid, tid,\ - smtp, pop3, imap, %s) VALUES ('%s', '%s', %d, %d, %d, %d, %s, %s, %s, %s)" % ( - sieve_col, self._addr.localpart, pwhash(self._passwd, - user=self._addr), - self._uid, self._domain.gid, self._mail.mid, self._transport.tid, - cfg_dget('account.smtp'), cfg_dget('account.pop3'), - cfg_dget('account.imap'), cfg_dget('account.sieve')) - dbc = self._dbh.cursor() - dbc.execute(sql) - self._dbh.commit() - dbc.close() - self._new = False - - def modify(self, field, value): - """Update the Account's *field* to the new *value*. - - Possible values for *field* are: 'name', 'password' and - 'transport'. *value* is the *field*'s new value. - - Arguments: - - `field` : basestring - The attribute name: 'name', 'password' or 'transport' - `value` : basestring - The new value of the attribute. - """ - if field not in ('name', 'password', 'transport'): - raise AErr(_(u"Unknown field: '%s'") % field, INVALID_ARGUMENT) - self._chk_state() - dbc = self._dbh.cursor() - if field == 'password': - dbc.execute('UPDATE users SET passwd = %s WHERE uid = %s', - pwhash(value, user=self._addr), self._uid) - elif field == 'transport': - if value != self._transport.transport: - self._transport = Transport(self._dbh, transport=value) - dbc.execute('UPDATE users SET tid = %s WHERE uid = %s', - self._transport.tid, self._uid) - else: - dbc.execute('UPDATE users SET name = %s WHERE uid = %s', - value, self._uid) - if dbc.rowcount > 0: - self._dbh.commit() - dbc.close() - |
|
From: <nev...@us...> - 2010-07-28 01:04:17
|
details: http://hg.localdomain.org/vmm/rev/f4956b4ceba1 changeset: 319:f4956b4ceba1 user: Pascal Volk date: Wed Jul 28 01:03:56 2010 +0000 description: VMM//{,cli/}Handler: PEP-8-ified the Handler classes: * converted CamelCase method names to lower_case_with_underscores * eliminated __names * added missing docstrings diffstat: VirtualMailManager/Handler.py | 208 ++++++++++++++++++++----------------- VirtualMailManager/cli/Handler.py | 3 +- 2 files changed, 112 insertions(+), 99 deletions(-) diffs (truncated from 553 to 300 lines): diff -r 4dc2edf02d11 -r f4956b4ceba1 VirtualMailManager/Handler.py --- a/VirtualMailManager/Handler.py Tue Jul 27 19:29:44 2010 +0000 +++ b/VirtualMailManager/Handler.py Wed Jul 28 01:03:56 2010 +0000 @@ -59,7 +59,7 @@ class Handler(object): """Wrapper class to simplify the access on all the stuff from VirtualMailManager""" - __slots__ = ('_cfg', '_cfg_fname', '_dbh', '__warnings') + __slots__ = ('_cfg', '_cfg_fname', '_dbh', '_warnings') def __init__(self, skip_some_checks=False): """Creates a new Handler instance. @@ -72,21 +72,21 @@ Throws a NotRootError if your uid is greater 0. """ self._cfg_fname = '' - self.__warnings = [] + self._warnings = [] self._cfg = None self._dbh = None if os.geteuid(): raise NotRootError(_(u"You are not root.\n\tGood bye!\n"), CONF_NOPERM) - if self.__check_cfg_file(): + if self._check_cfg_file(): self._cfg = Cfg(self._cfg_fname) self._cfg.load() if not skip_some_checks: self._cfg.check() self._chkenv() - def __find_cfg_file(self): + def _find_cfg_file(self): """Search the CFG_FILE in CFG_PATH. Raise a VMMError when no vmm.cfg could be found. """ @@ -98,11 +98,11 @@ if not self._cfg_fname: raise VMMError(_(u"Could not find '%(cfg_file)s' in: " u"'%(cfg_path)s'") % {'cfg_file': CFG_FILE, - 'cfg_path' : CFG_PATH}, CONF_NOFILE) + 'cfg_path': CFG_PATH}, CONF_NOFILE) - def __check_cfg_file(self): + def _check_cfg_file(self): """Checks the configuration file, returns bool""" - self.__find_cfg_file() + self._find_cfg_file() fstat = os.stat(self._cfg_fname) fmode = int(oct(fstat.st_mode & 0777)) if fmode % 100 and fstat.st_uid != fstat.st_gid or \ @@ -148,7 +148,7 @@ else: raise - def __dbConnect(self): + def _db_connect(self): """Creates a pyPgSQL.PgSQL.connection instance.""" if self._dbh is None or (isinstance(self._dbh, PgSQL.Connection) and not self._dbh._isOpen): @@ -162,8 +162,8 @@ dbc = self._dbh.cursor() dbc.execute("SET NAMES 'UTF8'") dbc.close() - except PgSQL.libpq.DatabaseError, e: - raise VMMError(str(e), DATABASE_ERROR) + except PgSQL.libpq.DatabaseError, err: + raise VMMError(str(err), DATABASE_ERROR) def _chk_other_address_types(self, address, exclude): """Checks if the EmailAddress *address* is known as `TYPE_ACCOUNT`, @@ -202,44 +202,52 @@ raise VMMError(msg % {'a_type': OTHER_TYPES[other][0], 'address': address}, OTHER_TYPES[other][1]) - def __getAccount(self, address): + def _get_account(self, address): + """Return an Account instances for the given address (str).""" address = EmailAddress(address) - self.__dbConnect() + self._db_connect() return Account(self._dbh, address) - def __getAlias(self, address): + def _get_alias(self, address): + """Return an Alias instances for the given address (str).""" address = EmailAddress(address) - self.__dbConnect() + self._db_connect() return Alias(self._dbh, address) - def __getRelocated(self, address): + def _get_relocated(self, address): + """Return a Relocated instances for the given address (str).""" address = EmailAddress(address) - self.__dbConnect() + self._db_connect() return Relocated(self._dbh, address) - def __getDomain(self, domainname): - self.__dbConnect() + def _get_domain(self, domainname): + """Return a Domain instances for the given domain name (str).""" + self._db_connect() return Domain(self._dbh, domainname) - def __getDiskUsage(self, directory): + def _get_disk_usage(self, directory): """Estimate file space usage for the given directory. Keyword arguments: directory -- the directory to summarize recursively disk usage for """ - if self.__isdir(directory): + if self._isdir(directory): return Popen([self._cfg.dget('bin.du'), "-hs", directory], stdout=PIPE).communicate()[0].split('\t')[0] else: return 0 - def __isdir(self, directory): + def _isdir(self, directory): + """Check if `directory` is a directory. Returns bool. + When `directory` isn't a directory, a warning will be appended to + _warnings.""" isdir = os.path.isdir(directory) if not isdir: - self.__warnings.append(_('No such directory: %s') % directory) + self._warnings.append(_('No such directory: %s') % directory) return isdir - def __make_domain_dir(self, domain): + def _make_domain_dir(self, domain): + """Create a directory for the `domain` and its accounts.""" cwd = os.getcwd() hashdir, domdir = domain.directory.split(os.path.sep)[-2:] os.chdir(self._cfg.dget('misc.base_directory')) @@ -251,14 +259,15 @@ os.chown(domain.directory, 0, domain.gid) os.chdir(cwd) - def __make_home(self, account): + def _make_home(self, account): """Create a home directory for the new Account *account*.""" os.umask(0007) os.chdir(account.domain_directory) os.mkdir('%s' % account.uid, self._cfg.dget('account.directory_mode')) os.chown('%s' % account.uid, account.uid, account.gid) - def __userDirDelete(self, domdir, uid, gid): + def _delete_home(self, domdir, uid, gid): + """Delete a user's home directory.""" if uid > 0 and gid > 0: userdir = '%s' % uid if userdir.count('..') or domdir.count('..'): @@ -278,9 +287,10 @@ os.path.join(domdir, userdir), NO_SUCH_DIRECTORY) - def __domDirDelete(self, domdir, gid): + def _delete_domain_dir(self, domdir, gid): + """Delete a domain's directory.""" if gid > 0: - if not self.__isdir(domdir): + if not self._isdir(domdir): return basedir = self._cfg.dget('misc.base_directory') domdirdirs = domdir.replace(basedir + '/', '').split('/') @@ -295,17 +305,16 @@ u'directory.'), DOMAINDIR_GROUP_MISMATCH) rmtree(domdirdirs[1], ignore_errors=True) - def hasWarnings(self): + def has_warnings(self): """Checks if warnings are present, returns bool.""" - return bool(len(self.__warnings)) + return bool(len(self._warnings)) - def getWarnings(self): + def get_warnings(self): """Returns a list with all available warnings and resets all warnings. - """ - ret_val = self.__warnings[:] - del self.__warnings[:] + ret_val = self._warnings[:] + del self._warnings[:] return ret_val def cfg_dget(self, option): @@ -325,8 +334,9 @@ assert 'cfg_dget' not in __builtin__.__dict__ __builtin__.__dict__['cfg_dget'] = self._cfg.dget - def domainAdd(self, domainname, transport=None): - dom = self.__getDomain(domainname) + def domain_add(self, domainname, transport=None): + """Wrapper around Domain.set_transport() and Domain.save()""" + dom = self._get_domain(domainname) if transport is None: dom.set_transport(Transport(self._dbh, transport=self._cfg.dget('misc.transport'))) @@ -334,24 +344,26 @@ dom.set_transport(Transport(self._dbh, transport=transport)) dom.set_directory(self._cfg.dget('misc.base_directory')) dom.save() - self.__make_domain_dir(dom) + self._make_domain_dir(dom) - def domainTransport(self, domainname, transport, force=None): + def domain_transport(self, domainname, transport, force=None): + """Wrapper around Domain.update_transport()""" if force is not None and force != 'force': raise DomainError(_(u"Invalid argument: '%s'") % force, INVALID_ARGUMENT) - dom = self.__getDomain(domainname) + dom = self._get_domain(domainname) trsp = Transport(self._dbh, transport=transport) if force is None: dom.update_transport(trsp) else: dom.update_transport(trsp, force=True) - def domainDelete(self, domainname, force=None): + def domain_delete(self, domainname, force=None): + """Wrapper around Domain.delete()""" if force and force not in ('deluser', 'delalias', 'delall'): raise DomainError(_(u"Invalid argument: '%s'") % force, INVALID_ARGUMENT) - dom = self.__getDomain(domainname) + dom = self._get_domain(domainname) gid = dom.gid domdir = dom.directory if self._cfg.dget('domain.force_deletion') or force == 'delall': @@ -363,14 +375,17 @@ else: dom.delete() if self._cfg.dget('domain.delete_directory'): - self.__domDirDelete(domdir, gid) + self._delete_domain_dir(domdir, gid) - def domainInfo(self, domainname, details=None): + def domain_info(self, domainname, details=None): + """Wrapper around Domain.get_info(), Domain.get_accounts(), + Domain.get_aliase_names(), Domain.get_aliases() and + Domain.get_relocated.""" if details not in [None, 'accounts', 'aliasdomains', 'aliases', 'full', 'relocated']: raise VMMError(_(u'Invalid argument: “%s”') % details, INVALID_ARGUMENT) - dom = self.__getDomain(domainname) + dom = self._get_domain(domainname) dominfo = dom.get_info() if dominfo['domainname'].startswith('xn--'): dominfo['domainname'] += ' (%s)' % \ @@ -389,7 +404,7 @@ return (dominfo, dom.get_aliase_names(), dom.get_accounts(), dom.get_aliases(), dom.get_relocated()) - def aliasDomainAdd(self, aliasname, domainname): + def aliasdomain_add(self, aliasname, domainname): """Adds an alias domain to the domain. Arguments: @@ -399,19 +414,19 @@ `domainname` : basestring The name of the target domain """ - dom = self.__getDomain(domainname) - aliasDom = AliasDomain(self._dbh, aliasname) - aliasDom.set_destination(dom) - aliasDom.save() + dom = self._get_domain(domainname) + alias_dom = AliasDomain(self._dbh, aliasname) + alias_dom.set_destination(dom) + alias_dom.save() - def aliasDomainInfo(self, aliasname): + def aliasdomain_info(self, aliasname): """Returns a dict (keys: "alias" and "domain") with the names of the alias domain and its primary domain.""" - self.__dbConnect() - aliasDom = AliasDomain(self._dbh, aliasname) - return aliasDom.info() + self._db_connect() + alias_dom = AliasDomain(self._dbh, aliasname) + return alias_dom.info() - def aliasDomainSwitch(self, aliasname, domainname): + def aliasdomain_switch(self, aliasname, domainname): """Modifies the target domain of an existing alias domain. Arguments: @@ -421,12 +436,12 @@ `domainname` : basestring The name of the new target domain """ - dom = self.__getDomain(domainname) |
|
From: <nev...@us...> - 2010-07-27 19:30:00
|
details: http://hg.localdomain.org/vmm/rev/4dc2edf02d11 changeset: 318:4dc2edf02d11 user: Pascal Volk date: Tue Jul 27 19:29:44 2010 +0000 description: VMM//{,cli/}Handler: Reworked configuration related parts. Renamed attributes _Cfg -> _cfg; _cfgFileName -> _cfg_fname. Renamed methods __chkCfgFile -> __check_cfg_file; __findCfgFile -> __find_cfg_file. Added missing docstrings. diffstat: VirtualMailManager/Handler.py | 108 +++++++++++++++++++++---------------- VirtualMailManager/cli/Handler.py | 14 ++-- 2 files changed, 67 insertions(+), 55 deletions(-) diffs (truncated from 303 to 300 lines): diff -r d619e97a8f18 -r 4dc2edf02d11 VirtualMailManager/Handler.py --- a/VirtualMailManager/Handler.py Tue Jul 27 14:35:55 2010 +0000 +++ b/VirtualMailManager/Handler.py Tue Jul 27 19:29:44 2010 +0000 @@ -43,6 +43,8 @@ _ = lambda msg: msg +CFG_FILE = 'vmm.cfg' +CFG_PATH = '/root:/usr/local/etc:/etc' RE_DOMAIN_SEARCH = """^[a-z0-9-\.]+$""" TYPE_ACCOUNT = 0x1 TYPE_ALIAS = 0x2 @@ -57,7 +59,7 @@ class Handler(object): """Wrapper class to simplify the access on all the stuff from VirtualMailManager""" - __slots__ = ('_Cfg', '_cfgFileName', '_dbh', '__warnings') + __slots__ = ('_cfg', '_cfg_fname', '_dbh', '__warnings') def __init__(self, skip_some_checks=False): """Creates a new Handler instance. @@ -69,70 +71,80 @@ Throws a NotRootError if your uid is greater 0. """ - self._cfgFileName = '' + self._cfg_fname = '' self.__warnings = [] - self._Cfg = None + self._cfg = None self._dbh = None if os.geteuid(): raise NotRootError(_(u"You are not root.\n\tGood bye!\n"), CONF_NOPERM) - if self.__chkCfgFile(): - self._Cfg = Cfg(self._cfgFileName) - self._Cfg.load() + if self.__check_cfg_file(): + self._cfg = Cfg(self._cfg_fname) + self._cfg.load() if not skip_some_checks: - self._Cfg.check() + self._cfg.check() self._chkenv() - def __findCfgFile(self): - for path in ['/root', '/usr/local/etc', '/etc']: - tmp = os.path.join(path, 'vmm.cfg') + def __find_cfg_file(self): + """Search the CFG_FILE in CFG_PATH. + Raise a VMMError when no vmm.cfg could be found. + """ + for path in CFG_PATH.split(':'): + tmp = os.path.join(path, CFG_FILE) if os.path.isfile(tmp): - self._cfgFileName = tmp + self._cfg_fname = tmp break - if not len(self._cfgFileName): - raise VMMError(_(u"No 'vmm.cfg' found in: " - u"/root:/usr/local/etc:/etc"), CONF_NOFILE) + if not self._cfg_fname: + raise VMMError(_(u"Could not find '%(cfg_file)s' in: " + u"'%(cfg_path)s'") % {'cfg_file': CFG_FILE, + 'cfg_path' : CFG_PATH}, CONF_NOFILE) - def __chkCfgFile(self): + def __check_cfg_file(self): """Checks the configuration file, returns bool""" - self.__findCfgFile() - fstat = os.stat(self._cfgFileName) + self.__find_cfg_file() + fstat = os.stat(self._cfg_fname) fmode = int(oct(fstat.st_mode & 0777)) if fmode % 100 and fstat.st_uid != fstat.st_gid or \ fmode % 10 and fstat.st_uid == fstat.st_gid: raise PermissionError(_(u"wrong permissions for '%(file)s': " u"%(perms)s\n`chmod 0600 %(file)s` would " - u"be great.") % {'file': self._cfgFileName, + u"be great.") % {'file': self._cfg_fname, 'perms': fmode}, CONF_WRONGPERM) else: return True def _chkenv(self): - """""" - basedir = self._Cfg.dget('misc.base_directory') + """Make sure our base_directory is a directory and that all + required executables exists and are executable. + If not, a VMMError will be raised""" + basedir = self._cfg.dget('misc.base_directory') if not os.path.exists(basedir): old_umask = os.umask(0006) os.makedirs(basedir, 0771) os.chown(basedir, 0, 0) os.umask(old_umask) elif not os.path.isdir(basedir): - raise VMMError(_(u"'%s' is not a directory.\n(vmm.cfg: section " - u"'misc', option 'base_directory')") % basedir, + raise VMMError(_(u"'%(path)s' is not a directory.\n(%(cfg_file)s: " + u"section 'misc', option 'base_directory')") % + {'path': basedir, 'cfg_file': self._cfg_fname}, NO_SUCH_DIRECTORY) - for opt, val in self._Cfg.items('bin'): + for opt, val in self._cfg.items('bin'): try: exec_ok(val) except VMMError, err: if err.code is NO_SUCH_BINARY: - raise VMMError(_(u"'%(binary)s' doesn't exist.\n(vmm.cfg: " - u"section 'bin', option '%(option)s')") % - {'binary': val, 'option': opt}, err.code) + raise VMMError(_(u"'%(binary)s' doesn't exist.\n" + u"(%(cfg_file)s: section 'bin', option " + u"'%(option)s')") % {'binary': val, + 'cfg_file': self._cfg_fname, 'option': opt}, + err.code) elif err.code is NOT_EXECUTABLE: raise VMMError(_(u"'%(binary)s' is not executable.\n" - u"(vmm.cfg: section 'bin', option " + u"(%(cfg_file)s: section 'bin', option " u"'%(option)s')") % {'binary': val, - 'option': opt}, err.code) + 'cfg_file': self._cfg_fname, 'option': opt}, + err.code) else: raise @@ -142,10 +154,10 @@ not self._dbh._isOpen): try: self._dbh = PgSQL.connect( - database=self._Cfg.dget('database.name'), - user=self._Cfg.pget('database.user'), - host=self._Cfg.dget('database.host'), - password=self._Cfg.pget('database.pass'), + database=self._cfg.dget('database.name'), + user=self._cfg.pget('database.user'), + host=self._cfg.dget('database.host'), + password=self._cfg.pget('database.pass'), client_encoding='utf8', unicode_results=True) dbc = self._dbh.cursor() dbc.execute("SET NAMES 'UTF8'") @@ -216,7 +228,7 @@ directory -- the directory to summarize recursively disk usage for """ if self.__isdir(directory): - return Popen([self._Cfg.dget('bin.du'), "-hs", directory], + return Popen([self._cfg.dget('bin.du'), "-hs", directory], stdout=PIPE).communicate()[0].split('\t')[0] else: return 0 @@ -230,12 +242,12 @@ def __make_domain_dir(self, domain): cwd = os.getcwd() hashdir, domdir = domain.directory.split(os.path.sep)[-2:] - os.chdir(self._Cfg.dget('misc.base_directory')) + os.chdir(self._cfg.dget('misc.base_directory')) if not os.path.isdir(hashdir): os.mkdir(hashdir, 0711) os.chown(hashdir, 0, 0) os.mkdir(os.path.join(hashdir, domdir), - self._Cfg.dget('domain.directory_mode')) + self._cfg.dget('domain.directory_mode')) os.chown(domain.directory, 0, domain.gid) os.chdir(cwd) @@ -243,7 +255,7 @@ """Create a home directory for the new Account *account*.""" os.umask(0007) os.chdir(account.domain_directory) - os.mkdir('%s' % account.uid, self._Cfg.dget('account.directory_mode')) + os.mkdir('%s' % account.uid, self._cfg.dget('account.directory_mode')) os.chown('%s' % account.uid, account.uid, account.gid) def __userDirDelete(self, domdir, uid, gid): @@ -270,7 +282,7 @@ if gid > 0: if not self.__isdir(domdir): return - basedir = self._Cfg.dget('misc.base_directory') + basedir = self._cfg.dget('misc.base_directory') domdirdirs = domdir.replace(basedir + '/', '').split('/') domdirparent = os.path.join(basedir, domdirdirs[0]) if basedir.count('..') or domdir.count('..'): @@ -300,27 +312,27 @@ """Get the configured value of the *option* (section.option). When the option was not configured its default value will be returned.""" - return self._Cfg.dget(option) + return self._cfg.dget(option) def cfg_pget(self, option): """Get the configured value of the *option* (section.option).""" - return self._Cfg.pget(option) + return self._cfg.pget(option) def cfg_install(self): """Installs the cfg_dget method as ``cfg_dget`` into the built-in namespace.""" import __builtin__ assert 'cfg_dget' not in __builtin__.__dict__ - __builtin__.__dict__['cfg_dget'] = self._Cfg.dget + __builtin__.__dict__['cfg_dget'] = self._cfg.dget def domainAdd(self, domainname, transport=None): dom = self.__getDomain(domainname) if transport is None: dom.set_transport(Transport(self._dbh, - transport=self._Cfg.dget('misc.transport'))) + transport=self._cfg.dget('misc.transport'))) else: dom.set_transport(Transport(self._dbh, transport=transport)) - dom.set_directory(self._Cfg.dget('misc.base_directory')) + dom.set_directory(self._cfg.dget('misc.base_directory')) dom.save() self.__make_domain_dir(dom) @@ -342,7 +354,7 @@ dom = self.__getDomain(domainname) gid = dom.gid domdir = dom.directory - if self._Cfg.dget('domain.force_deletion') or force == 'delall': + if self._cfg.dget('domain.force_deletion') or force == 'delall': dom.delete(True, True) elif force == 'deluser': dom.delete(deluser=True) @@ -350,7 +362,7 @@ dom.delete(delalias=True) else: dom.delete() - if self._Cfg.dget('domain.delete_directory'): + if self._cfg.dget('domain.delete_directory'): self.__domDirDelete(domdir, gid) def domainInfo(self, domainname, details=None): @@ -446,10 +458,10 @@ self.__make_home(acc) mailbox = new_mailbox(acc) mailbox.create() - folders = self._Cfg.dget('mailbox.folders').split(':') + folders = self._cfg.dget('mailbox.folders').split(':') if any(folders): bad = mailbox.add_boxes(folders, - self._Cfg.dget('mailbox.subscribe')) + self._cfg.dget('mailbox.subscribe')) if bad: self.__warnings.append(_(u"Skipped mailbox folders:") + '\n\t- ' + '\n\t- '.join(bad)) @@ -485,7 +497,7 @@ dom_dir = acc.domain_directory acc_dir = acc.home acc.delete(bool(force)) - if self._Cfg.dget('account.delete_directory'): + if self._cfg.dget('account.delete_directory'): try: self.__userDirDelete(dom_dir, uid, gid) except VMMError, err: @@ -532,7 +544,7 @@ raise VMMError(_(u"The account '%s' doesn't exist.") % acc.address, NO_SUCH_ACCOUNT) info = acc.get_info() - if self._Cfg.dget('account.disk_usage') or details in ('du', 'full'): + if self._cfg.dget('account.disk_usage') or details in ('du', 'full'): path = os.path.join(acc.home, acc.mail_location.directory) info['disk usage'] = self.__getDiskUsage(path) if details in (None, 'du'): diff -r d619e97a8f18 -r 4dc2edf02d11 VirtualMailManager/cli/Handler.py --- a/VirtualMailManager/cli/Handler.py Tue Jul 27 14:35:55 2010 +0000 +++ b/VirtualMailManager/cli/Handler.py Tue Jul 27 19:29:44 2010 +0000 @@ -42,14 +42,14 @@ 'v', 'version') super(CliHandler, self).__init__(skip_some_checks) - self._Cfg = Cfg(self._cfgFileName) - self._Cfg.load() + self._cfg = Cfg(self._cfg_fname) + self._cfg.load() if not skip_some_checks: - self._Cfg.check() + self._cfg.check() self._chkenv() def cfgSet(self, option, value): - return self._Cfg.set(option, value) + return self._cfg.set(option, value) def configure(self, section=None): """Starts the interactive configuration. @@ -59,9 +59,9 @@ will be prompted. """ if section is None: - self._Cfg.configure(self._Cfg.sections()) - elif self._Cfg.has_section(section): - self._Cfg.configure([section]) + self._cfg.configure(self._cfg.sections()) + elif self._cfg.has_section(section): + self._cfg.configure([section]) |
|
From: <nev...@us...> - 2010-07-27 14:36:12
|
details: http://hg.localdomain.org/vmm/rev/d619e97a8f18 changeset: 317:d619e97a8f18 user: Pascal Volk date: Tue Jul 27 14:35:55 2010 +0000 description: VMM/constants: Added __copyright__. diffstat: VirtualMailManager/constants.py | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diffs (11 lines): diff -r 31d8931dc535 -r d619e97a8f18 VirtualMailManager/constants.py --- a/VirtualMailManager/constants.py Mon Jul 26 19:10:51 2010 +0000 +++ b/VirtualMailManager/constants.py Tue Jul 27 14:35:55 2010 +0000 @@ -17,6 +17,7 @@ RELDATE = '2009-09-09' VERSION = '0.5.2' __author__ = AUTHOR +__copyright__ = 'Copyright (c) 2007-2010 %s' % __author__ __date__ = RELDATE __version__ = VERSION |
|
From: <nev...@us...> - 2010-07-26 19:11:08
|
details: http://hg.localdomain.org/vmm/rev/31d8931dc535 changeset: 316:31d8931dc535 user: Pascal Volk date: Mon Jul 26 19:10:51 2010 +0000 description: VMM/constants: Replaced the constants subpackage by a module. diffstat: VirtualMailManager/Account.py | 12 ++-- VirtualMailManager/Alias.py | 2 +- VirtualMailManager/AliasDomain.py | 2 +- VirtualMailManager/Config.py | 2 +- VirtualMailManager/Domain.py | 2 +- VirtualMailManager/EmailAddress.py | 2 +- VirtualMailManager/Handler.py | 91 ++++++++++++++++--------------- VirtualMailManager/Relocated.py | 2 +- VirtualMailManager/Transport.py | 2 +- VirtualMailManager/__init__.py | 3 +- VirtualMailManager/cli/Config.py | 2 +- VirtualMailManager/cli/Handler.py | 2 +- VirtualMailManager/cli/__init__.py | 2 +- VirtualMailManager/common.py | 2 +- VirtualMailManager/constants.py | 84 +++++++++++++++++++++++++++++ VirtualMailManager/constants/ERROR.py | 55 ------------------- VirtualMailManager/constants/EXIT.py | 7 -- VirtualMailManager/constants/__init__.py | 6 -- VirtualMailManager/constants/version.py | 17 ----- VirtualMailManager/ext/Postconf.py | 2 +- VirtualMailManager/mailbox.py | 2 +- VirtualMailManager/maillocation.py | 2 +- VirtualMailManager/password.py | 2 +- 23 files changed, 154 insertions(+), 151 deletions(-) diffs (truncated from 716 to 300 lines): diff -r 81bccfd14355 -r 31d8931dc535 VirtualMailManager/Account.py --- a/VirtualMailManager/Account.py Mon Jul 26 16:08:15 2010 +0000 +++ b/VirtualMailManager/Account.py Mon Jul 26 19:10:51 2010 +0000 @@ -13,10 +13,10 @@ from VirtualMailManager.EmailAddress import EmailAddress from VirtualMailManager.Transport import Transport from VirtualMailManager.common import version_str -from VirtualMailManager.constants.ERROR import \ +from VirtualMailManager.constants import \ ACCOUNT_EXISTS, ACCOUNT_MISSING_PASSWORD, ALIAS_PRESENT, \ - INVALID_AGUMENT, INVALID_MAIL_LOCATION, NO_SUCH_ACCOUNT, NO_SUCH_DOMAIN, \ - UNKNOWN_SERVICE + INVALID_ARGUMENT, INVALID_MAIL_LOCATION, NO_SUCH_ACCOUNT, \ + NO_SUCH_DOMAIN, UNKNOWN_SERVICE from VirtualMailManager.errors import AccountError as AErr from VirtualMailManager.maillocation import MailLocation from VirtualMailManager.password import pwhash @@ -276,7 +276,7 @@ The new value of the attribute. """ if field not in ('name', 'password', 'transport'): - raise AErr(_(u"Unknown field: '%s'") % field, INVALID_AGUMENT) + raise AErr(_(u"Unknown field: '%s'") % field, INVALID_ARGUMENT) self._chk_state() dbc = self._dbh.cursor() if field == 'password': @@ -402,9 +402,9 @@ try: uid = long(uid) except ValueError: - raise AErr(_(u'UID must be an int/long.'), INVALID_AGUMENT) + raise AErr(_(u'UID must be an int/long.'), INVALID_ARGUMENT) if uid < 1: - raise AErr(_(u'UID must be greater than 0.'), INVALID_AGUMENT) + raise AErr(_(u'UID must be greater than 0.'), INVALID_ARGUMENT) dbc = dbh.cursor() dbc.execute("SELECT local_part||'@'|| domain_name.domainname AS address, " "uid, users.gid FROM users LEFT JOIN domain_name ON " diff -r 81bccfd14355 -r 31d8931dc535 VirtualMailManager/Alias.py --- a/VirtualMailManager/Alias.py Mon Jul 26 16:08:15 2010 +0000 +++ b/VirtualMailManager/Alias.py Mon Jul 26 19:10:51 2010 +0000 @@ -13,7 +13,7 @@ from VirtualMailManager.errors import AliasError as AErr from VirtualMailManager.ext.Postconf import Postconf from VirtualMailManager.pycompat import all -from VirtualMailManager.constants.ERROR import \ +from VirtualMailManager.constants import \ ALIAS_EXCEEDS_EXPANSION_LIMIT, NO_SUCH_ALIAS, NO_SUCH_DOMAIN diff -r 81bccfd14355 -r 31d8931dc535 VirtualMailManager/AliasDomain.py --- a/VirtualMailManager/AliasDomain.py Mon Jul 26 16:08:15 2010 +0000 +++ b/VirtualMailManager/AliasDomain.py Mon Jul 26 19:10:51 2010 +0000 @@ -9,7 +9,7 @@ """ from VirtualMailManager.Domain import Domain, check_domainname -from VirtualMailManager.constants.ERROR import \ +from VirtualMailManager.constants import \ ALIASDOMAIN_EXISTS, ALIASDOMAIN_ISDOMAIN, ALIASDOMAIN_NO_DOMDEST, \ NO_SUCH_ALIASDOMAIN, NO_SUCH_DOMAIN from VirtualMailManager.errors import AliasDomainError as ADErr diff -r 81bccfd14355 -r 31d8931dc535 VirtualMailManager/Config.py --- a/VirtualMailManager/Config.py Mon Jul 26 16:08:15 2010 +0000 +++ b/VirtualMailManager/Config.py Mon Jul 26 19:10:51 2010 +0000 @@ -17,7 +17,7 @@ from cStringIO import StringIO# TODO: move interactive stff to cli from VirtualMailManager.common import exec_ok, get_unicode, is_dir, version_hex -from VirtualMailManager.constants.ERROR import CONF_ERROR +from VirtualMailManager.constants import CONF_ERROR from VirtualMailManager.errors import ConfigError, VMMError from VirtualMailManager.maillocation import known_format from VirtualMailManager.password import verify_scheme as _verify_scheme diff -r 81bccfd14355 -r 31d8931dc535 VirtualMailManager/Domain.py --- a/VirtualMailManager/Domain.py Mon Jul 26 16:08:15 2010 +0000 +++ b/VirtualMailManager/Domain.py Mon Jul 26 19:10:51 2010 +0000 @@ -12,7 +12,7 @@ import re from random import choice -from VirtualMailManager.constants.ERROR import \ +from VirtualMailManager.constants import \ ACCOUNT_AND_ALIAS_PRESENT, ACCOUNT_PRESENT, ALIAS_PRESENT, \ DOMAIN_ALIAS_EXISTS, DOMAIN_EXISTS, DOMAIN_INVALID, DOMAIN_TOO_LONG, \ NO_SUCH_DOMAIN diff -r 81bccfd14355 -r 31d8931dc535 VirtualMailManager/EmailAddress.py --- a/VirtualMailManager/EmailAddress.py Mon Jul 26 16:08:15 2010 +0000 +++ b/VirtualMailManager/EmailAddress.py Mon Jul 26 19:10:51 2010 +0000 @@ -10,7 +10,7 @@ import re from VirtualMailManager.Domain import check_domainname -from VirtualMailManager.constants.ERROR import \ +from VirtualMailManager.constants import \ DOMAIN_NO_NAME, INVALID_ADDRESS, LOCALPART_INVALID, LOCALPART_TOO_LONG from VirtualMailManager.errors import EmailAddressError as EAErr diff -r 81bccfd14355 -r 31d8931dc535 VirtualMailManager/Handler.py --- a/VirtualMailManager/Handler.py Mon Jul 26 16:08:15 2010 +0000 +++ b/VirtualMailManager/Handler.py Mon Jul 26 19:10:51 2010 +0000 @@ -20,12 +20,17 @@ from pyPgSQL import PgSQL # python-pgsql - http://pypgsql.sourceforge.net -import VirtualMailManager.constants.ERROR as ERR from VirtualMailManager.Account import Account from VirtualMailManager.Alias import Alias from VirtualMailManager.AliasDomain import AliasDomain from VirtualMailManager.common import exec_ok from VirtualMailManager.Config import Config as Cfg +from VirtualMailManager.constants import \ + ACCOUNT_EXISTS, ALIAS_EXISTS, CONF_NOFILE, CONF_NOPERM, CONF_WRONGPERM, \ + DATABASE_ERROR, DOMAINDIR_GROUP_MISMATCH, DOMAIN_INVALID, \ + FOUND_DOTS_IN_PATH, INVALID_ARGUMENT, MAILDIR_PERM_MISMATCH, \ + NOT_EXECUTABLE, NO_SUCH_ACCOUNT, NO_SUCH_ALIAS, NO_SUCH_BINARY, \ + NO_SUCH_DIRECTORY, NO_SUCH_RELOCATED, RELOCATED_EXISTS from VirtualMailManager.Domain import Domain, get_gid from VirtualMailManager.EmailAddress import EmailAddress from VirtualMailManager.errors import \ @@ -43,9 +48,9 @@ TYPE_ALIAS = 0x2 TYPE_RELOCATED = 0x4 OTHER_TYPES = { - TYPE_ACCOUNT: (_(u'an account'), ERR.ACCOUNT_EXISTS), - TYPE_ALIAS: (_(u'an alias'), ERR.ALIAS_EXISTS), - TYPE_RELOCATED: (_(u'a relocated user'), ERR.RELOCATED_EXISTS), + TYPE_ACCOUNT: (_(u'an account'), ACCOUNT_EXISTS), + TYPE_ALIAS: (_(u'an alias'), ALIAS_EXISTS), + TYPE_RELOCATED: (_(u'a relocated user'), RELOCATED_EXISTS), } @@ -71,7 +76,7 @@ if os.geteuid(): raise NotRootError(_(u"You are not root.\n\tGood bye!\n"), - ERR.CONF_NOPERM) + CONF_NOPERM) if self.__chkCfgFile(): self._Cfg = Cfg(self._cfgFileName) self._Cfg.load() @@ -87,7 +92,7 @@ break if not len(self._cfgFileName): raise VMMError(_(u"No 'vmm.cfg' found in: " - u"/root:/usr/local/etc:/etc"), ERR.CONF_NOFILE) + u"/root:/usr/local/etc:/etc"), CONF_NOFILE) def __chkCfgFile(self): """Checks the configuration file, returns bool""" @@ -99,7 +104,7 @@ raise PermissionError(_(u"wrong permissions for '%(file)s': " u"%(perms)s\n`chmod 0600 %(file)s` would " u"be great.") % {'file': self._cfgFileName, - 'perms': fmode}, ERR.CONF_WRONGPERM) + 'perms': fmode}, CONF_WRONGPERM) else: return True @@ -114,16 +119,16 @@ elif not os.path.isdir(basedir): raise VMMError(_(u"'%s' is not a directory.\n(vmm.cfg: section " u"'misc', option 'base_directory')") % basedir, - ERR.NO_SUCH_DIRECTORY) + NO_SUCH_DIRECTORY) for opt, val in self._Cfg.items('bin'): try: exec_ok(val) except VMMError, err: - if err.code is ERR.NO_SUCH_BINARY: + if err.code is NO_SUCH_BINARY: raise VMMError(_(u"'%(binary)s' doesn't exist.\n(vmm.cfg: " u"section 'bin', option '%(option)s')") % {'binary': val, 'option': opt}, err.code) - elif err.code is ERR.NOT_EXECUTABLE: + elif err.code is NOT_EXECUTABLE: raise VMMError(_(u"'%(binary)s' is not executable.\n" u"(vmm.cfg: section 'bin', option " u"'%(option)s')") % {'binary': val, @@ -146,7 +151,7 @@ dbc.execute("SET NAMES 'UTF8'") dbc.close() except PgSQL.libpq.DatabaseError, e: - raise VMMError(str(e), ERR.DATABASE_ERROR) + raise VMMError(str(e), DATABASE_ERROR) def _chk_other_address_types(self, address, exclude): """Checks if the EmailAddress *address* is known as `TYPE_ACCOUNT`, @@ -246,19 +251,20 @@ userdir = '%s' % uid if userdir.count('..') or domdir.count('..'): raise VMMError(_(u'Found ".." in home directory path.'), - ERR.FOUND_DOTS_IN_PATH) + FOUND_DOTS_IN_PATH) if os.path.isdir(domdir): os.chdir(domdir) if os.path.isdir(userdir): mdstat = os.stat(userdir) if (mdstat.st_uid, mdstat.st_gid) != (uid, gid): - raise VMMError(_( - u'Detected owner/group mismatch in home directory.'), - ERR.MAILDIR_PERM_MISMATCH) + raise VMMError(_(u'Detected owner/group mismatch in ' + u'home directory.'), + MAILDIR_PERM_MISMATCH) rmtree(userdir, ignore_errors=True) else: raise VMMError(_(u"No such directory: %s") % - os.path.join(domdir, userdir), ERR.NO_SUCH_DIRECTORY) + os.path.join(domdir, userdir), + NO_SUCH_DIRECTORY) def __domDirDelete(self, domdir, gid): if gid > 0: @@ -269,13 +275,12 @@ domdirparent = os.path.join(basedir, domdirdirs[0]) if basedir.count('..') or domdir.count('..'): raise VMMError(_(u'Found ".." in domain directory path.'), - ERR.FOUND_DOTS_IN_PATH) + FOUND_DOTS_IN_PATH) if os.path.isdir(domdirparent): os.chdir(domdirparent) if os.lstat(domdirdirs[1]).st_gid != gid: - raise VMMError(_( - u'Detected group mismatch in domain directory.'), - ERR.DOMAINDIR_GROUP_MISMATCH) + raise VMMError(_(u'Detected group mismatch in domain ' + u'directory.'), DOMAINDIR_GROUP_MISMATCH) rmtree(domdirdirs[1], ignore_errors=True) def hasWarnings(self): @@ -321,8 +326,8 @@ def domainTransport(self, domainname, transport, force=None): if force is not None and force != 'force': - raise DomainError(_(u"Invalid argument: “%s”") % force, - ERR.INVALID_OPTION) + raise DomainError(_(u"Invalid argument: '%s'") % force, + INVALID_ARGUMENT) dom = self.__getDomain(domainname) trsp = Transport(self._dbh, transport=transport) if force is None: @@ -333,7 +338,7 @@ def domainDelete(self, domainname, force=None): if force and force not in ('deluser', 'delalias', 'delall'): raise DomainError(_(u"Invalid argument: '%s'") % force, - ERR.INVALID_OPTION) + INVALID_ARGUMENT) dom = self.__getDomain(domainname) gid = dom.gid domdir = dom.directory @@ -352,7 +357,7 @@ if details not in [None, 'accounts', 'aliasdomains', 'aliases', 'full', 'relocated']: raise VMMError(_(u'Invalid argument: “%s”') % details, - ERR.INVALID_AGUMENT) + INVALID_ARGUMENT) dom = self.__getDomain(domainname) dominfo = dom.get_info() if dominfo['domainname'].startswith('xn--'): @@ -428,7 +433,7 @@ like = True if not re.match(RE_DOMAIN_SEARCH, pattern.strip('%')): raise VMMError(_(u"The pattern '%s' contains invalid " - u"characters.") % pattern, ERR.DOMAIN_INVALID) + u"characters.") % pattern, DOMAIN_INVALID) self.__dbConnect() return search(self._dbh, pattern=pattern, like=like) @@ -470,11 +475,11 @@ """Wrapper around Account.delete(...)""" if force not in (None, 'delalias'): raise VMMError(_(u"Invalid argument: '%s'") % force, - ERR.INVALID_AGUMENT) + INVALID_ARGUMENT) acc = self.__getAccount(emailaddress) if not acc: raise VMMError(_(u"The account '%s' doesn't exist.") % - acc.address, ERR.NO_SUCH_ACCOUNT) + acc.address, NO_SUCH_ACCOUNT) uid = acc.uid gid = acc.gid dom_dir = acc.domain_directory @@ -484,8 +489,8 @@ try: self.__userDirDelete(dom_dir, uid, gid) except VMMError, err: - if err.code in (ERR.FOUND_DOTS_IN_PATH, - ERR.MAILDIR_PERM_MISMATCH, ERR.NO_SUCH_DIRECTORY): + if err.code in (FOUND_DOTS_IN_PATH, MAILDIR_PERM_MISMATCH, + NO_SUCH_DIRECTORY): warning = _(u"""\ The account has been successfully deleted from the database. But an error occurred while deleting the following directory: @@ -504,7 +509,7 @@ return alias.get_destinations() if not self._is_other_address(alias.address, TYPE_ALIAS): raise VMMError(_(u"The alias '%s' doesn't exist.") % - alias.address, ERR.NO_SUCH_ALIAS) |
|
From: <nev...@us...> - 2010-07-26 16:08:31
|
details: http://hg.localdomain.org/vmm/rev/81bccfd14355 changeset: 315:81bccfd14355 user: Pascal Volk date: Mon Jul 26 16:08:15 2010 +0000 description: VMM/cli: Forgot to remove string_io from __all__. diffstat: VirtualMailManager/cli/__init__.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff -r 0b4a6e9d9f27 -r 81bccfd14355 VirtualMailManager/cli/__init__.py --- a/VirtualMailManager/cli/__init__.py Mon Jul 26 16:02:58 2010 +0000 +++ b/VirtualMailManager/cli/__init__.py Mon Jul 26 16:08:15 2010 +0000 @@ -20,7 +20,7 @@ from VirtualMailManager.errors import VMMError -__all__ = ('get_winsize', 'read_pass', 'string_io', 'w_err', 'w_std') +__all__ = ('get_winsize', 'read_pass', 'w_err', 'w_std') _ = lambda msg: msg _std_write = os.sys.stdout.write |
|
From: <nev...@us...> - 2010-07-26 16:03:21
|
details: http://hg.localdomain.org/vmm/rev/0b4a6e9d9f27 changeset: 314:0b4a6e9d9f27 user: Pascal Volk date: Mon Jul 26 16:02:58 2010 +0000 description: VMM/cli: Removed misplaced function string_io. diffstat: VirtualMailManager/cli/__init__.py | 6 ------ 1 files changed, 0 insertions(+), 6 deletions(-) diffs (21 lines): diff -r c17c46d9e440 -r 0b4a6e9d9f27 VirtualMailManager/cli/__init__.py --- a/VirtualMailManager/cli/__init__.py Mon Jul 26 03:08:57 2010 +0000 +++ b/VirtualMailManager/cli/__init__.py Mon Jul 26 16:02:58 2010 +0000 @@ -11,7 +11,6 @@ import os from array import array -from cStringIO import StringIO from fcntl import ioctl from getpass import getpass from termios import TIOCGWINSZ @@ -98,9 +97,4 @@ mismatched = False return clear0 - -def string_io(): - """Returns a new `cStringIO.StringIO` instance.""" - return StringIO() - del _ |
|
From: <nev...@us...> - 2010-07-26 03:44:55
|
details: http://hg.localdomain.org/vmm/rev/6f39a1e56f4a changeset: 312:6f39a1e56f4a user: Pascal Volk date: Mon Jul 26 01:18:49 2010 +0000 description: VMM/cli: w_err() call os.sys.exit only if code != 0. read_pass() write errors to stderr. And a few other small fixes. diffstat: VirtualMailManager/cli/__init__.py | 43 ++++++++++++++++++------------------- 1 files changed, 21 insertions(+), 22 deletions(-) diffs (119 lines): diff -r a0a10100aee5 -r 6f39a1e56f4a VirtualMailManager/cli/__init__.py --- a/VirtualMailManager/cli/__init__.py Sun Jul 25 03:31:32 2010 +0000 +++ b/VirtualMailManager/cli/__init__.py Mon Jul 26 01:18:49 2010 +0000 @@ -4,20 +4,26 @@ """ VirtualMailManager.cli + ~~~~~~~~~~~~~~~~~~~~~~ VirtualMailManager's command line interface. """ import os +from array import array from cStringIO import StringIO +from fcntl import ioctl from getpass import getpass -from textwrap import TextWrapper +from termios import TIOCGWINSZ from VirtualMailManager import ENCODING +from VirtualMailManager.constants.ERROR import VMM_TOO_MANY_FAILURES +from VirtualMailManager.errors import VMMError __all__ = ('get_winsize', 'read_pass', 'string_io', 'w_err', 'w_std') +_ = lambda msg: msg _std_write = os.sys.stdout.write _err_write = os.sys.stderr.write @@ -25,23 +31,19 @@ def w_std(*args): """Writes a line for each arg of *args*, encoded in the current ENCODING, to stdout. - """ - _std_write('\n'.join(arg.encode(ENCODING, 'replace') for arg in args)) - _std_write('\n') + _std_write('\n'.join(a.encode(ENCODING, 'replace') for a in args) + '\n') def w_err(code, *args): """Writes a line for each arg of *args*, encoded in the current ENCODING, to stderr. - - This function additional interrupts the program execution and uses - *code* as the system exit status. - + This function optionally interrupts the program execution if *code* + does not equal to 0. *code* will be used as the system exit status. """ - _err_write('\n'.join(arg.encode(ENCODING, 'replace') for arg in args)) - _err_write('\n') - os.sys.exit(code) + _err_write('\n'.join(a.encode(ENCODING, 'replace') for a in args) + '\n') + if code: + os.sys.exit(code) def get_winsize(): @@ -52,7 +54,7 @@ if hasattr(dev, 'fileno') and os.isatty(dev.fileno()): fd = dev.fileno() break - if fd is None:# everything seems to be redirected + if fd is None: # everything seems to be redirected # fall back to environment or assume some common defaults ws_row, ws_col = 24, 80 try: @@ -61,11 +63,6 @@ except ValueError: pass return ws_row, ws_col - - from array import array - from fcntl import ioctl - from termios import TIOCGWINSZ - #"struct winsize" with the ``unsigned short int``s ws_{row,col,{x,y}pixel} ws = array('H', (0, 0, 0, 0)) ioctl(fd, TIOCGWINSZ, ws, True) @@ -76,7 +73,7 @@ def read_pass(): """Interactive 'password chat', returns the password in plain format. - Throws a VMMException after the third failure. + Throws a VMMError after the third failure. """ # TP: Please preserve the trailing space. readp_msg0 = _(u'Enter new password: ').encode(ENCODING, 'replace') @@ -86,17 +83,17 @@ failures = 0 while mismatched: if failures > 2: - raise VMMException(_(u'Too many failures - try again later.'), - ERR.VMM_TOO_MANY_FAILURES) + raise VMMError(_(u'Too many failures - try again later.'), + VMM_TOO_MANY_FAILURES) clear0 = getpass(prompt=readp_msg0) clear1 = getpass(prompt=readp_msg1) if clear0 != clear1: failures += 1 - w_std(_(u'Sorry, passwords do not match')) + w_err(0, _(u'Sorry, passwords do not match')) continue if not clear0: failures += 1 - w_std(_(u'Sorry, empty passwords are not permitted')) + w_err(0, _(u'Sorry, empty passwords are not permitted')) continue mismatched = False return clear0 @@ -105,3 +102,5 @@ def string_io(): """Returns a new `cStringIO.StringIO` instance.""" return StringIO() + +del _ |
|
From: <nev...@us...> - 2010-07-26 03:09:41
|
details: http://hg.localdomain.org/vmm/rev/c17c46d9e440 changeset: 313:c17c46d9e440 user: Pascal Volk date: Mon Jul 26 03:08:57 2010 +0000 description: VMM/cli/Config: Write warnings to stderr. Renamed method __saveChanges to __save_changes. diffstat: VirtualMailManager/cli/Config.py | 26 ++++++++++++++++---------- 1 files changed, 16 insertions(+), 10 deletions(-) diffs (76 lines): diff -r 6f39a1e56f4a -r c17c46d9e440 VirtualMailManager/cli/Config.py --- a/VirtualMailManager/cli/Config.py Mon Jul 26 01:18:49 2010 +0000 +++ b/VirtualMailManager/cli/Config.py Mon Jul 26 03:08:57 2010 +0000 @@ -4,6 +4,7 @@ """ VirtualMailManager.cli.CliConfig + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Adds some interactive stuff to the Config class. """ @@ -14,9 +15,11 @@ from VirtualMailManager import ENCODING from VirtualMailManager.Config import Config, ConfigValueError, LazyConfig from VirtualMailManager.errors import ConfigError -from VirtualMailManager.cli import w_std +from VirtualMailManager.cli import w_err, w_std from VirtualMailManager.constants.ERROR import VMM_TOO_MANY_FAILURES +_ = lambda msg: msg + class CliConfig(Config): """Adds the interactive ``configure`` method to the `Config` class @@ -32,19 +35,20 @@ failures = 0 w_std(_(u'Using configuration file: %s\n') % self._cfg_filename) - for s in sections: - w_std(_(u'* Configuration section: %r') % s) - for opt, val in self.items(s): + for section in sections: + w_std(_(u'* Configuration section: %r') % section) + for opt, val in self.items(section): failures = 0 while True: newval = raw_input(input_fmt.encode(ENCODING, 'replace') % {'option': opt, 'current_value': val}) if newval and newval != val: try: - LazyConfig.set(self, '%s.%s' % (s, opt), newval) + LazyConfig.set(self, '%s.%s' % (section, opt), + newval) break - except (ValueError, ConfigValueError), e: - w_std(_(u'Warning: %s') % e) + except (ValueError, ConfigValueError), err: + w_err(0, _(u'Warning: %s') % err) failures += 1 if failures > 2: raise ConfigError(_(u'Too many failures - try ' @@ -54,7 +58,7 @@ break print if self._modified: - self.__saveChanges() + self.__save_changes() def set(self, option, value): """Set the value of an option. @@ -78,11 +82,13 @@ if not RawConfigParser.has_section(self, section): self.add_section(section) RawConfigParser.set(self, section, option_, val) - self.__saveChanges() + self.__save_changes() - def __saveChanges(self): + def __save_changes(self): """Writes changes to the configuration file.""" copy2(self._cfg_filename, self._cfg_filename + '.bak') self._cfg_file = open(self._cfg_filename, 'w') self.write(self._cfg_file) self._cfg_file.close() + +del _ |
|
From: <nev...@us...> - 2010-07-25 03:31:56
|
details: http://hg.localdomain.org/vmm/rev/a0a10100aee5 changeset: 311:a0a10100aee5 user: Pascal Volk date: Sun Jul 25 03:31:32 2010 +0000 description: VMM/ext/Postconf: Reworked class Postconf. Added method edit(). diffstat: VirtualMailManager/ext/Postconf.py | 129 ++++++++++++++++++++++++------------ 1 files changed, 86 insertions(+), 43 deletions(-) diffs (174 lines): diff -r 644e2cc4a441 -r a0a10100aee5 VirtualMailManager/ext/Postconf.py --- a/VirtualMailManager/ext/Postconf.py Fri Jul 23 19:07:30 2010 +0000 +++ b/VirtualMailManager/ext/Postconf.py Sun Jul 25 03:31:32 2010 +0000 @@ -1,84 +1,127 @@ # -*- coding: UTF-8 -*- # Copyright (c) 2008 - 2010, Pascal Volk # See COPYING for distribution information. +""" + VirtualMailManager.ext.Postconf + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -"""A small - r/o - wrapper class for Postfix' postconf.""" + Wrapper class for Postfix's postconf. + Postconf instances can be used to read actual values of configuration + parameters or edit the value of a configuration parameter. + + postconf.read(parameter) -> value + postconf.edit(parameter, value) +""" import re from subprocess import Popen, PIPE -import VirtualMailManager.constants.ERROR as ERR from VirtualMailManager.errors import VMMError +from VirtualMailManager.constants.ERROR import VMM_ERROR -RE_PC_PARAMS = """^\w+$""" -RE_PC_VARIABLES = r"""\$\b\w+\b""" +_ = lambda msg: msg + class Postconf(object): - __slots__ = ('__bin', '__val', '__varFinder') + """Wrapper class for Postfix's postconf.""" + __slots__ = ('_bin', '_val') + _parameter_re = re.compile(r'^\w+$') + _variables_re = re.compile(r'\$\b\w+\b') + def __init__(self, postconf_bin): """Creates a new Postconf instance. - Keyword arguments: - postconf_bin -- absolute path to the Postfix postconf binary (str) + Argument: + + `postconf_bin` : str + absolute path to the Postfix postconf binary. """ - self.__bin = postconf_bin - self.__val = '' - self.__varFinder = re.compile(RE_PC_VARIABLES) + self._bin = postconf_bin + self._val = '' + + def edit(self, parameter, value): + """Set the `parameter`'s value to `value`. + + Arguments: + + `parameter` : str + the name of a Postfix configuration parameter + `value` : str + the parameter's new value. + """ + self._check_parameter(parameter) + stdout, stderr = Popen((self._bin, '-e', parameter + '=' + str(value)), + stderr=PIPE).communicate() + if stderr: + raise VMMError(stderr.strip(), VMM_ERROR) def read(self, parameter, expand_vars=True): """Returns the parameters value. If expand_vars is True (default), all variables in the value will be expanded: - e.g. mydestination -> mail.example.com, localhost.example.com, localhost + e.g. mydestination: mail.example.com, localhost.example.com, localhost Otherwise the value may contain one or more variables. - e.g. mydestination -> $myhostname, localhost.$mydomain, localhost + e.g. mydestination: $myhostname, localhost.$mydomain, localhost - Keyword arguments: - parameter -- the name of a Postfix configuration parameter (str) - expand_vars -- default True (bool) + Arguments: + + `parameter` : str + the name of a Postfix configuration parameter. + `expand_vars` : bool + indicates if variables should be expanded or not, default True """ - if not re.match(RE_PC_PARAMS, parameter): + self._check_parameter(parameter) + self._val = self._read(parameter) + if expand_vars: + self._expand_vars() + return self._val + + def _check_parameter(self, parameter): + """Check that the `parameter` looks like a configuration parameter. + If not, a VMMError will be raised.""" + if not self.__class__._parameter_re.match(parameter): raise VMMError(_(u"The value '%s' doesn't look like a valid " u"postfix configuration parameter name.") % - parameter, ERR.VMM_ERROR) - self.__val = self.__read(parameter) - if expand_vars: - self.__expandVars() - return self.__val + parameter, VMM_ERROR) - def __expandVars(self): + def _expand_vars(self): + """Expand the $variables in self._val to their values.""" while True: - pvars = set(self.__varFinder.findall(self.__val)) - pvars_len = len(pvars) - if pvars_len < 1: + pvars = set(self.__class__._variables_re.findall(self._val)) + if not pvars: break - if pvars_len > 1: - self.__expandMultiVars(self.__readMulti(pvars)) + if len(pvars) > 1: + self._expand_multi_vars(self._read_multi(pvars)) continue pvars = pvars.pop() - self.__val = self.__val.replace(pvars, self.__read(pvars[1:])) + self._val = self._val.replace(pvars, self._read(pvars[1:])) - def __expandMultiVars(self, old_new): - for old, new in old_new.items(): - self.__val = self.__val.replace('$'+old, new) + def _expand_multi_vars(self, old_new): + """Replace all $vars in self._val with their values.""" + for old, new in old_new.iteritems(): + self._val = self._val.replace('$' + old, new) - def __read(self, parameter): - out, err = Popen([self.__bin, '-h', parameter], stdout=PIPE, - stderr=PIPE).communicate() - if len(err): - raise VMMError(err.strip(), ERR.VMM_ERROR) - return out.strip() + def _read(self, parameter): + """Ask postconf for the value of a single configuration parameter.""" + stdout, stderr = Popen([self._bin, '-h', parameter], stdout=PIPE, + stderr=PIPE).communicate() + if stderr: + raise VMMError(stderr.strip(), VMM_ERROR) + return stdout.strip() - def __readMulti(self, parameters): - cmd = [self.__bin] + def _read_multi(self, parameters): + """Ask postconf for multiple configuration parameters. Returns a dict + parameter: value items.""" + cmd = [self._bin] cmd.extend(parameter[1:] for parameter in parameters) - out, err = Popen(cmd, stdout=PIPE, stderr=PIPE).communicate() - if len(err): - raise VMMError(err.strip(), ERR.VMM_ERROR) + stdout, stderr = Popen(cmd, stdout=PIPE, stderr=PIPE).communicate() + if stderr: + raise VMMError(stderr.strip(), VMM_ERROR) par_val = {} - for line in out.splitlines(): + for line in stdout.splitlines(): par, val = line.split(' = ') par_val[par] = val return par_val +del _ |
|
From: <nev...@us...> - 2010-07-23 19:07:47
|
details: http://hg.localdomain.org/vmm/rev/644e2cc4a441 changeset: 310:644e2cc4a441 user: Pascal Volk date: Fri Jul 23 19:07:30 2010 +0000 description: VMM/Handler: Reworked __domDirMake and reamed to __make_domain_dir. Removed the (now) unused method __makedir. diffstat: VirtualMailManager/Handler.py | 38 ++++++++++++-------------------------- 1 files changed, 12 insertions(+), 26 deletions(-) diffs (55 lines): diff -r d21423478803 -r 644e2cc4a441 VirtualMailManager/Handler.py --- a/VirtualMailManager/Handler.py Fri Jul 23 02:45:31 2010 +0000 +++ b/VirtualMailManager/Handler.py Fri Jul 23 19:07:30 2010 +0000 @@ -222,31 +222,17 @@ self.__warnings.append(_('No such directory: %s') % directory) return isdir - def __makedir(self, directory, mode=None, uid=None, gid=None): - if mode is None: - mode = self._Cfg.dget('account.directory_mode') - if uid is None: - uid = 0 - if gid is None: - gid = 0 - os.makedirs(directory, mode) - os.chown(directory, uid, gid) - - def __domDirMake(self, domdir, gid): - #TODO: clenaup! - os.umask(0006) - oldpwd = os.getcwd() - basedir = self._Cfg.dget('misc.base_directory') - domdirdirs = domdir.replace(basedir + '/', '').split('/') - - os.chdir(basedir) - if not os.path.isdir(domdirdirs[0]): - self.__makedir(domdirdirs[0], 489, 0, 0) - os.chdir(domdirdirs[0]) - os.umask(0007) - self.__makedir(domdirdirs[1], self._Cfg.dget('domain.directory_mode'), - 0, gid) - os.chdir(oldpwd) + def __make_domain_dir(self, domain): + cwd = os.getcwd() + hashdir, domdir = domain.directory.split(os.path.sep)[-2:] + os.chdir(self._Cfg.dget('misc.base_directory')) + if not os.path.isdir(hashdir): + os.mkdir(hashdir, 0711) + os.chown(hashdir, 0, 0) + os.mkdir(os.path.join(hashdir, domdir), + self._Cfg.dget('domain.directory_mode')) + os.chown(domain.directory, 0, domain.gid) + os.chdir(cwd) def __make_home(self, account): """Create a home directory for the new Account *account*.""" @@ -331,7 +317,7 @@ dom.set_transport(Transport(self._dbh, transport=transport)) dom.set_directory(self._Cfg.dget('misc.base_directory')) dom.save() - self.__domDirMake(dom.directory, dom.gid) + self.__make_domain_dir(dom) def domainTransport(self, domainname, transport, force=None): if force is not None and force != 'force': |
|
From: <nev...@us...> - 2010-07-23 02:45:44
|
details: http://hg.localdomain.org/vmm/rev/d21423478803 changeset: 309:d21423478803 user: Pascal Volk date: Fri Jul 23 02:45:31 2010 +0000 description: VMM/mailbox: Added to the repository. VMM/Handler: Integrated mailbox module. Code cleanups. diffstat: VirtualMailManager/Handler.py | 80 +++-------- VirtualMailManager/mailbox.py | 293 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 315 insertions(+), 58 deletions(-) diffs (truncated from 416 to 300 lines): diff -r aa4a9fc31e1b -r d21423478803 VirtualMailManager/Handler.py --- a/VirtualMailManager/Handler.py Fri Jul 23 02:01:57 2010 +0000 +++ b/VirtualMailManager/Handler.py Fri Jul 23 02:45:31 2010 +0000 @@ -30,6 +30,8 @@ from VirtualMailManager.EmailAddress import EmailAddress from VirtualMailManager.errors import \ DomainError, NotRootError, PermissionError, VMMError +from VirtualMailManager.mailbox import new as new_mailbox +from VirtualMailManager.pycompat import any from VirtualMailManager.Relocated import Relocated from VirtualMailManager.Transport import Transport @@ -37,7 +39,6 @@ _ = lambda msg: msg RE_DOMAIN_SEARCH = """^[a-z0-9-\.]+$""" -RE_MBOX_NAMES = """^[\x20-\x25\x27-\x7E]*$""" TYPE_ACCOUNT = 0x1 TYPE_ALIAS = 0x2 TYPE_RELOCATED = 0x4 @@ -247,58 +248,12 @@ 0, gid) os.chdir(oldpwd) - def __subscribe(self, folderlist, uid, gid): - """Creates a subscriptions file with the mailboxes from `folderlist`""" - fname = os.path.join(self._Cfg.dget('maildir.name'), 'subscriptions') - sf = open(fname, 'w') - sf.write('\n'.join(folderlist)) - sf.write('\n') - sf.flush() - sf.close() - os.chown(fname, uid, gid) - os.chmod(fname, 384) - - def __mailDirMake(self, domdir, uid, gid): - """Creates maildirs and maildir subfolders. - - Keyword arguments: - domdir -- the path to the domain directory - uid -- user id from the account - gid -- group id from the account - """ - # obsolete -> (mailbox / maillocation) - return + def __make_home(self, account): + """Create a home directory for the new Account *account*.""" os.umask(0007) - oldpwd = os.getcwd() - os.chdir(domdir) - - maildir = self._Cfg.dget('maildir.name') - folders = [maildir] - append = folders.append - for folder in self._Cfg.dget('maildir.folders').split(':'): - folder = folder.strip() - if len(folder) and not folder.count('..'): - if re.match(RE_MBOX_NAMES, folder): - append('%s/.%s' % (maildir, folder)) - else: - self.__warnings.append(_('Skipped mailbox folder: %r') % - folder) - else: - self.__warnings.append(_('Skipped mailbox folder: %r') % - folder) - - subdirs = ['cur', 'new', 'tmp'] - mode = self._Cfg.dget('account.directory_mode') - - self.__makedir('%s' % uid, mode, uid, gid) - os.chdir('%s' % uid) - for folder in folders: - self.__makedir(folder, mode, uid, gid) - for subdir in subdirs: - self.__makedir(os.path.join(folder, subdir), mode, uid, gid) - self.__subscribe((f.replace(maildir + '/.', '') for f in folders[1:]), - uid, gid) - os.chdir(oldpwd) + os.chdir(account.domain_directory) + os.mkdir('%s' % account.uid, self._Cfg.dget('account.directory_mode')) + os.chown('%s' % account.uid, account.uid, account.gid) def __userDirDelete(self, domdir, uid, gid): if uid > 0 and gid > 0: @@ -390,10 +345,9 @@ dom.update_transport(trsp, force=True) def domainDelete(self, domainname, force=None): - if not force is None and force not in ['deluser', 'delalias', - 'delall']: - raise DomainError(_(u'Invalid argument: “%s”') % - force, ERR.INVALID_OPTION) + if force and force not in ('deluser', 'delalias', 'delall'): + raise DomainError(_(u"Invalid argument: '%s'") % force, + ERR.INVALID_OPTION) dom = self.__getDomain(domainname) gid = dom.gid domdir = dom.directory @@ -497,8 +451,18 @@ acc = self.__getAccount(emailaddress) acc.set_password(password) acc.save() - # depends on modules mailbox and maillocation - # self.__mailDirMake(acc.domain_directory, acc.uid, acc.gid) + oldpwd = os.getcwd() + self.__make_home(acc) + mailbox = new_mailbox(acc) + mailbox.create() + folders = self._Cfg.dget('mailbox.folders').split(':') + if any(folders): + bad = mailbox.add_boxes(folders, + self._Cfg.dget('mailbox.subscribe')) + if bad: + self.__warnings.append(_(u"Skipped mailbox folders:") + + '\n\t- ' + '\n\t- '.join(bad)) + os.chdir(oldpwd) def aliasAdd(self, aliasaddress, *targetaddresses): """Creates a new `Alias` entry for the given *aliasaddress* with diff -r aa4a9fc31e1b -r d21423478803 VirtualMailManager/mailbox.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/VirtualMailManager/mailbox.py Fri Jul 23 02:45:31 2010 +0000 @@ -0,0 +1,293 @@ +# -*- coding: UTF-8 -*- +# Copyright (c) 2010, Pascal Volk +# See COPYING for distribution information. + +""" + VirtualMailManager.mailbox + ~~~~~~~~~~~~~~~~~~~~~~~~~~ + + VirtualMailManager's mailbox classes for the Maildir, single dbox + (sdbox) and multi dbox (mdbox) mailbox formats. +""" + +import os +import re +from binascii import a2b_base64, b2a_base64 +from subprocess import Popen, PIPE + +from VirtualMailManager.Account import Account +from VirtualMailManager.common import is_dir +from VirtualMailManager.errors import VMMError +from VirtualMailManager.constants.ERROR import VMM_ERROR + + +__all__ = ('new', 'Maildir', 'SingleDbox', 'MultiDbox', + 'utf8_to_mutf7', 'mutf7_to_utf8') + +cfg_dget = lambda option: None + + +def _mbase64_encode(inp, dest): + if inp: + mb64 = b2a_base64(''.join(inp).encode('utf-16be')) + dest.append('&%s-' % mb64.rstrip('\n=').replace('/', ',')) + del inp[:] + + +def _mbase64_to_unicode(mb64): + return unicode(a2b_base64(mb64.replace(',', '/') + '==='), 'utf-16be') + + +def utf8_to_mutf7(src): + """ + Converts the international mailbox name `src` into a modified + version version of the UTF-7 encoding. + """ + ret = [] + tmp = [] + for c in src: + ordc = ord(c) + if 0x20 <= ordc <= 0x25 or 0x27 <= ordc <= 0x7E: + _mbase64_encode(tmp, ret) + ret.append(c) + elif ordc == 0x26: + _mbase64_encode(tmp, ret) + ret.append('&-') + else: + tmp.append(c) + _mbase64_encode(tmp, ret) + return ''.join(ret) + + +def mutf7_to_utf8(src): + """ + Converts the mailbox name `src` from modified UTF-7 encoding to UTF-8. + """ + ret = [] + tmp = [] + for c in src: + if c == '&' and not tmp: + tmp.append(c) + elif c == '-' and tmp: + if len(tmp) is 1: + ret.append('&') + else: + ret.append(_mbase64_to_unicode(''.join(tmp[1:]))) + tmp = [] + elif tmp: + tmp.append(c) + else: + ret.append(c) + if tmp: + ret.append(_mbase64_to_unicode(''.join(tmp[1:]))) + return ''.join(ret) + + +class Mailbox(object): + """Base class of all mailbox classes.""" + __slots__ = ('_boxes', '_root', '_sep', '_user') + FILE_MODE = 0600 + _ctrl_chr_re = re.compile('[\x00-\x1F\x7F-\x9F]') + _box_name_re = re.compile('^[\x20-\x25\x27-\x7E]+$') + + def __init__(self, account): + """ + Creates a new mailbox instance. + Use one of the `Maildir`, `SingleDbox` or `MultiDbox` classes. + """ + assert isinstance(account, Account) + is_dir(account.home) + self._user = account + self._boxes = [] + self._root = self._user.mail_location.directory + self._sep = '/' + os.chdir(self._user.home) + + def _add_boxes(self, mailboxes, subscribe): + raise NotImplementedError + + def _validate_box_name(self, name, good, bad): + """ + Validates the mailboxes name `name`. When the name is valid, it + will be added to the `good` set. Invalid mailbox names will be + appended to the `bad` list. + """ + name = name.strip() + if not name: + return + if self.__class__._ctrl_chr_re.search(name): # no control chars + bad.append(name) + return + if name[0] in (self._sep, '~'): + bad.append(name) + return + if self._sep == '/': + if '//' in name or '/./' in name or '/../' in name or \ + name.startswith('../'): + bad.append(name) + return + if '/' in name or '..' in name: + bad.append(name) + return + if not self.__class__._box_name_re.match(name): + tmp = utf8_to_mutf7(name) + if name == mutf7_to_utf8(tmp): + if self._user.mail_location.mbformat == 'maildir': + good.add(tmp) + else: + good.add(name) + return + else: + bad.append(name) + return + good.add(name) + + def add_boxes(self, mailboxes, subscribe): + """ + Create all mailboxes from the `mailboxes` list in the user's + mail directory. When `subscribe` is ``True`` all created mailboxes + will be listed in the subscriptions file. + Returns a list of invalid mailbox names, if any. + """ + assert isinstance(mailboxes, list) and isinstance(subscribe, bool) + good = set() + bad = [] + for box in mailboxes: + self._validate_box_name(box, good, bad) + self._add_boxes(good, subscribe) + return bad + + def create(self): + """Create the INBOX in the user's mail directory.""" + raise NotImplementedError + + +class Maildir(Mailbox): + """Class for Maildir++ mailboxes.""" + + __slots__ = ('_subdirs') + + def __init__(self, account): + """ + Create a new Maildir++ instance. + Call the instance's create() method, in order to create the INBOX. + For additional mailboxes use the add_boxes() method. + """ + super(self.__class__, self).__init__(account) + self._sep = '.' |