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
(3) |
2
(1) |
3
|
4
(1) |
5
(2) |
6
(3) |
|
7
(3) |
8
(1) |
9
(2) |
10
(3) |
11
(2) |
12
(3) |
13
(2) |
|
14
|
15
|
16
|
17
|
18
|
19
|
20
(1) |
|
21
|
22
(5) |
23
|
24
(3) |
25
(1) |
26
(1) |
27
(5) |
|
28
(1) |
|
|
|
|
|
|
|
From: <nev...@us...> - 2010-02-10 07:38:33
|
details: http://hg.localdomain.org/vmm/rev/d2712e8c724e changeset: 197:d2712e8c724e user: Pascal Volk date: Wed Feb 10 07:38:19 2010 +0000 description: VMM/{Relocated,Handler}: reworked Relocated class, adjusted Handler. diffstat: VirtualMailManager/Handler.py | 23 +++-- VirtualMailManager/Relocated.py | 162 +++++++++++++++++++++------------------ 2 files changed, 101 insertions(+), 84 deletions(-) diffs (249 lines): diff -r 65a3163bd113 -r d2712e8c724e VirtualMailManager/Handler.py --- a/VirtualMailManager/Handler.py Wed Feb 10 02:13:35 2010 +0000 +++ b/VirtualMailManager/Handler.py Wed Feb 10 07:38:19 2010 +0000 @@ -177,23 +177,21 @@ relocatedExists = staticmethod(relocatedExists) def __getAccount(self, address, password=None): - self.__dbConnect() address = EmailAddress(address) if not password is None: password = self.__pwhash(password) + self.__dbConnect() return Account(self._dbh, address, password) def __getAlias(self, address): + address = EmailAddress(address) self.__dbConnect() - address = EmailAddress(address) return Alias(self._dbh, address) - def __getRelocated(self, address, destination=None): + def __getRelocated(self, address): + address = EmailAddress(address) self.__dbConnect() - address = EmailAddress(address) - if destination is not None: - destination = EmailAddress(destination) - return Relocated(self._dbh, address, destination) + return Relocated(self._dbh, address) def __getDomain(self, domainname, transport=None): if transport is None: @@ -659,14 +657,21 @@ acc.enable(self._Cfg.dget('misc.dovecot_version'), service) def relocatedAdd(self, emailaddress, targetaddress): - relocated = self.__getRelocated(emailaddress, targetaddress) - relocated.save() + """Creates a new `Relocated` entry in the database. If there is + already a relocated user with the given *emailaddress*, only the + *targetaddress* for the relocated user will be updated.""" + relocated = self.__getRelocated(emailaddress) + relocated.setDestination(EmailAddress(targetaddress)) def relocatedInfo(self, emailaddress): + """Returns the target address of the relocated user with the given + *emailaddress*.""" relocated = self.__getRelocated(emailaddress) return relocated.getInfo() def relocatedDelete(self, emailaddress): + """Deletes the relocated user with the given *emailaddress* from + the database.""" relocated = self.__getRelocated(emailaddress) relocated.delete() diff -r 65a3163bd113 -r d2712e8c724e VirtualMailManager/Relocated.py --- a/VirtualMailManager/Relocated.py Wed Feb 10 02:13:35 2010 +0000 +++ b/VirtualMailManager/Relocated.py Wed Feb 10 07:38:19 2010 +0000 @@ -2,102 +2,114 @@ # Copyright (c) 2008 - 2010, Pascal Volk # See COPYING for distribution information. -"""Virtual Mail Manager's Relocated class to manage relocated users.""" +""" + VirtualMailManager.Relocated -import VirtualMailManager.constants.ERROR as ERR + Virtual Mail Manager's Relocated class to handle relocated users. +""" + from VirtualMailManager.Domain import Domain from VirtualMailManager.EmailAddress import EmailAddress from VirtualMailManager.Exceptions import VMMRelocatedException as VMMRE -import VirtualMailManager as VMM +from VirtualMailManager.constants.ERROR import NO_SUCH_DOMAIN, \ + NO_SUCH_RELOCATED, RELOCATED_ADDR_DEST_IDENTICAL, RELOCATED_EXISTS + + +_ = lambda msg: msg + class Relocated(object): - """Class to manage e-mail addresses of relocated users.""" - __slots__ = ('_addr', '_dest', '_gid', '_isNew', '_dbh') - def __init__(self, dbh, address, destination=None): + """Class to handle e-mail addresses of relocated users.""" + __slots__ = ('_addr', '_dest', '_gid', '_dbh') + + def __init__(self, dbh, address): + """Creates a new *Relocated* instance. The ``address`` is the + old e-mail address of the user. + + Use `setDestination()` to set/update the new address, where the + user has moved to.""" if isinstance(address, EmailAddress): self._addr = address else: raise TypeError("Argument 'address' is not an EmailAddress") - if destination is None: - self._dest = None - elif isinstance(destination, EmailAddress): - self._dest = destination + self._dbh = dbh + self._gid = 0 + self._dest = None + + self.__set_gid() + self.__load() + + def __set_gid(self): + """Sets the `_gid` attribute, based on the `_addr.domainname`.""" + dom = Domain(self._dbh, self._addr.domainname) + self._gid = dom.getID() + if self._gid == 0: + raise VMMRE(_(u"The domain “%s” doesn't exist.") % + self._addr.domainname, NO_SUCH_DOMAIN) + + def __load(self): + """Loads the destination address from the database into the + `_dest` attribute.""" + dbc = self._dbh.cursor() + dbc.execute( + 'SELECT destination FROM relocated WHERE gid=%s AND address=%s', + self._gid, self._addr.localpart) + destination = dbc.fetchone() + dbc.close() + if destination: + self._dest = EmailAddress(destination[0]) + + def setDestination(self, destination): + """Sets/updates the new address of the relocated user.""" + update = False + if isinstance(destination, EmailAddress): + if self._addr == destination: + raise VMMRE(_(u'Address and destination are identical.'), + RELOCATED_ADDR_DEST_IDENTICAL) + if self._dest: + if self._dest == destination: + raise VMMRE( + _(u'The relocated user “%s” already exists.') % + self._addr, RELOCATED_EXISTS) + else: + self._dest = destination + update = True + else: + self._dest = destination else: raise TypeError("Argument 'destination' is not an EmailAddress") - if address == destination: - raise VMMRE(_(u"Address and destination are identical."), - ERR.RELOCATED_ADDR_DEST_IDENTICAL) - self._dbh = dbh - self._gid = 0 - self._isNew = False - self._setAddr() - self._exists() - if self._isNew and VMM.VirtualMailManager.accountExists(self._dbh, - self._addr): - raise VMMRE(_(u"There is already an account with address “%s”.") %\ - self._addr, ERR.ACCOUNT_EXISTS) - if self._isNew and VMM.VirtualMailManager.aliasExists(self._dbh, - self._addr): - raise VMMRE( - _(u"There is already an alias with the address “%s”.") %\ - self._addr, ERR.ALIAS_EXISTS) - def _exists(self): dbc = self._dbh.cursor() - dbc.execute("SELECT gid FROM relocated WHERE gid = %s AND address = %s", - self._gid, self._addr._localpart) - gid = dbc.fetchone() + if not update: + dbc.execute('INSERT INTO relocated VALUES (%s, %s, %s)', + self._gid, self._addr.localpart, str(self._dest)) + else: + dbc.execute('UPDATE relocated SET destination=%s \ +WHERE gid=%s AND address=%s', + str(self._dest), self._gid, self._addr.localpart) + self._dbh.commit() dbc.close() - if gid is None: - self._isNew = True - - def _setAddr(self): - dom = Domain(self._dbh, self._addr._domainname) - self._gid = dom.getID() - if self._gid == 0: - raise VMMRE(_(u"The domain “%s” doesn't exist.") %\ - self._addr._domainname, ERR.NO_SUCH_DOMAIN) - - def save(self): - if self._dest is None: - raise VMMRE( - _(u"No destination address specified for relocated user."), - ERR.RELOCATED_MISSING_DEST) - if self._isNew: - dbc = self._dbh.cursor() - dbc.execute("INSERT INTO relocated VALUES (%s, %s, %s)", - self._gid, self._addr._localpart, str(self._dest)) - self._dbh.commit() - dbc.close() - else: - raise VMMRE( - _(u"The relocated user “%s” already exists.") % self._addr, - ERR.RELOCATED_EXISTS) def getInfo(self): - dbc = self._dbh.cursor() - dbc.execute('SELECT destination FROM relocated WHERE gid=%s\ - AND address=%s', - self._gid, self._addr._localpart) - destination = dbc.fetchone() - dbc.close() - if destination is not None: - return destination[0] + """Returns the address to which mails should be sent.""" + if self._dest: + return self._dest else: - raise VMMRE( - _(u"The relocated user “%s” doesn't exist.") % self._addr, - ERR.NO_SUCH_RELOCATED) + raise VMMRE(_(u"The relocated user “%s” doesn't exist.") % + self._addr, NO_SUCH_RELOCATED) def delete(self): + """Deletes the relocated entry from the database.""" + if not self._dest: + raise VMMRE(_(u"The relocated user “%s” doesn't exist.") % + self._addr, NO_SUCH_RELOCATED) dbc = self._dbh.cursor() dbc.execute("DELETE FROM relocated WHERE gid = %s AND address = %s", - self._gid, self._addr._localpart) - rowcount = dbc.rowcount + self._gid, self._addr.localpart) + if dbc.rowcount > 0: + self._dbh.commit() dbc.close() - if rowcount > 0: - self._dbh.commit() - else: - raise VMMRE( - _(u"The relocated user “%s” doesn't exist.") % self._addr, - ERR.NO_SUCH_RELOCATED) + self._dest = None + +del _ |
|
From: <nev...@us...> - 2010-02-10 02:13:59
|
details: http://hg.localdomain.org/vmm/rev/65a3163bd113 changeset: 196:65a3163bd113 user: Pascal Volk date: Wed Feb 10 02:13:35 2010 +0000 description: VMM/{Alias,Handler}: reworked Alias class, adjusted Handler class. Handler: - attribute _dbh is no longer private, the VMM/cli/Handler uses it also. - adjusted to changes in Alias and EmailAddress classes. diffstat: VirtualMailManager/Alias.py | 202 ++++++++++++++++++++++++----------------- VirtualMailManager/Handler.py | 92 ++++++++++++------- 2 files changed, 175 insertions(+), 119 deletions(-) diffs (truncated from 466 to 300 lines): diff -r 05dd49fc3ea1 -r 65a3163bd113 VirtualMailManager/Alias.py --- a/VirtualMailManager/Alias.py Tue Feb 09 22:14:08 2010 +0000 +++ b/VirtualMailManager/Alias.py Wed Feb 10 02:13:35 2010 +0000 @@ -2,121 +2,153 @@ # Copyright (c) 2007 - 2010, Pascal Volk # See COPYING for distribution information. -"""Virtual Mail Manager's Alias class to manage e-mail aliases.""" +""" + VirtualMailManager.Alias -import VirtualMailManager.constants.ERROR as ERR + Virtual Mail Manager's Alias class to manage e-mail aliases. +""" + from VirtualMailManager.Domain import Domain from VirtualMailManager.EmailAddress import EmailAddress from VirtualMailManager.Exceptions import VMMAliasException as VMMAE -import VirtualMailManager as VMM +from VirtualMailManager.constants.ERROR import ALIAS_ADDR_DEST_IDENTICAL, \ + ALIAS_EXCEEDS_EXPANSION_LIMIT, ALIAS_EXISTS, NO_SUCH_ALIAS, NO_SUCH_DOMAIN + + +_ = lambda msg: msg + class Alias(object): """Class to manage e-mail aliases.""" - __slots__ = ('_addr', '_dest', '_gid', '_isNew', '_dbh') - def __init__(self, dbh, address, destination=None): + __slots__ = ('_addr', '_dests', '_gid', '_dbh') + + def __init__(self, dbh, address): if isinstance(address, EmailAddress): self._addr = address else: raise TypeError("Argument 'address' is not an EmailAddress") - if destination is None: - self._dest = None - elif isinstance(destination, EmailAddress): - self._dest = destination - else: - raise TypeError("Argument 'destination' is not an EmailAddress") - if address == destination: - raise VMMAE(_(u"Address and destination are identical."), - ERR.ALIAS_ADDR_DEST_IDENTICAL) self._dbh = dbh self._gid = 0 - self._isNew = False - self._setAddr() - if not self._dest is None: - self._exists() - if VMM.VirtualMailManager.accountExists(self._dbh, self._addr): - raise VMMAE(_(u"There is already an account with address “%s”.") %\ - self._addr, ERR.ACCOUNT_EXISTS) - if VMM.VirtualMailManager.relocatedExists(self._dbh, self._addr): - raise VMMAE( - _(u"There is already a relocated user with the address “%s”.") %\ - self._addr, ERR.RELOCATED_EXISTS) + self._dests = [] - def _exists(self): - dbc = self._dbh.cursor() - dbc.execute("SELECT gid FROM alias WHERE gid=%s AND address=%s\ - AND destination=%s", self._gid, self._addr._localpart, str(self._dest)) - gid = dbc.fetchone() - dbc.close() - if gid is None: - self._isNew = True + self.__set_gid() + self.__load_dests() - def _setAddr(self): - dom = Domain(self._dbh, self._addr._domainname) + def __set_gid(self): + """Sets the alias' _gid based on its _addr.domainname.""" + dom = Domain(self._dbh, self._addr.domainname) self._gid = dom.getID() if self._gid == 0: - raise VMMAE(_(u"The domain “%s” doesn't exist.") %\ - self._addr._domainname, ERR.NO_SUCH_DOMAIN) + raise VMMAE(_(u"The domain “%s” doesn't exist.") % + self._addr.domainname, NO_SUCH_DOMAIN) - def _checkExpansion(self, limit): + def __load_dests(self): + """Loads all known destination addresses into the _dests list.""" dbc = self._dbh.cursor() - dbc.execute('SELECT count(gid) FROM alias where gid=%s AND address=%s', - self._gid, self._addr._localpart) - curEx = dbc.fetchone()[0] + dbc.execute( + 'SELECT destination FROM alias WHERE gid=%s AND address=%s', + self._gid, self._addr.localpart) + dests = iter(dbc.fetchall()) + if dbc.rowcount > 0: + dest_add = self._dests.append + for dest in dests: + dest_add(EmailAddress(dest[0])) dbc.close() - if curEx == limit: - errmsg = _(u"""Can't add new destination to alias “%(address)s”. -Currently this alias expands into %(count)i recipients. + + def __check_expansion(self, limit): + """Checks the current expansion limit of the alias.""" + dcount = len(self._dests) + failed = False + if dcount == limit: + failed = True + errmsg = _( +u"""Can't add new destination to alias “%(address)s”. +Currently this alias expands into %(count)i/%(limit)i recipients. One more destination will render this alias unusable. -Hint: Increase Postfix' virtual_alias_expansion_limit -""") % {'address': self._addr, 'count': curEx} - raise VMMAE(errmsg, ERR.ALIAS_EXCEEDS_EXPANSION_LIMIT) +Hint: Increase Postfix' virtual_alias_expansion_limit""") + elif dcount > limit: + failed = True + errmsg = _( +u"""Can't add new destination to alias “%(address)s”. +This alias already exceeds it's expansion limit (%(count)i/%(limit)i). +So its unusable, all messages addressed to this alias will be bounced. +Hint: Delete some destination addresses.""") + if failed: + raise VMMAE(errmsg % {'address': self._addr, 'count': dcount, + 'limit': limit}, + ALIAS_EXCEEDS_EXPANSION_LIMIT) - def save(self, expansion_limit): - if self._dest is None: - raise VMMAE(_(u"No destination address specified for alias."), - ERR.ALIAS_MISSING_DEST) - if self._isNew: - self._checkExpansion(expansion_limit) + def __delete(self, destination=None): + """Deletes a destination from the alias, if ``destination`` is not + ``None``. If ``destination`` is None, the alias with all it's + destination addresses will be deleted.""" + dbc = self._dbh.cursor() + if destination is None: + dbc.execute("DELETE FROM alias WHERE gid=%s AND address=%s", + self._gid, self._addr.localpart) + else: + dbc.execute("DELETE FROM alias WHERE gid=%s AND address=%s AND \ + destination=%s", + self._gid, self._addr.localpart, str(destination)) + if dbc.rowcount > 0: + self._dbh.commit() + dbc.close() + + def __len__(self): + """Returns the number of destinations of the alias.""" + return len(self._dests) + + def addDestination(self, destination, expansion_limit): + """Adds the ``destination`` `EmailAddress` to the alias.""" + if not isinstance(destination, EmailAddress): + raise TypeError("Argument 'destination' is not an EmailAddress") + if self._addr == destination: + raise VMMAE(_(u"Address and destination are identical."), + ALIAS_ADDR_DEST_IDENTICAL) + if not destination in self._dests: + self.__check_expansion(expansion_limit) dbc = self._dbh.cursor() - dbc.execute("INSERT INTO alias (gid, address, destination) VALUES\ - (%s, %s, %s)", self._gid, self._addr._localpart, str(self._dest)) + dbc.execute('INSERT INTO alias (gid, address, destination) \ +VALUES (%s, %s, %s)', + self._gid, self._addr.localpart, str(destination)) self._dbh.commit() dbc.close() + self._dests.append(destination) else: - raise VMMAE( - _(u"The alias “%(a)s” with destination “%(d)s” already exists.")\ - % {'a': self._addr, 'd': self._dest}, ERR.ALIAS_EXISTS) + raise VMMAE(_( + u'The alias “%(a)s” has already the destination “%(d)s”.') % + {'a': self._addr, 'd': destination}, ALIAS_EXISTS) - def getInfo(self): - dbc = self._dbh.cursor() - dbc.execute('SELECT destination FROM alias WHERE gid=%s AND address=%s', - self._gid, self._addr._localpart) - destinations = dbc.fetchall() - dbc.close() - if len(destinations) > 0: - targets = [destination[0] for destination in destinations] - return targets + def delDestination(self, destination): + """Deletes the specified ``destination`` address from the alias.""" + if not isinstance(destination, EmailAddress): + raise TypeError("Argument 'destination' is not an EmailAddress") + if not self._dests: + raise VMMAE(_(u"The alias “%s” doesn't exist.") % self._addr, + NO_SUCH_ALIAS) + if not destination in self._dests: + raise VMMAE(_(u"The address “%(d)s” isn't a destination of \ +the alias “%(a)s”.") % + {'a': self._addr, 'd': destination}, NO_SUCH_ALIAS) + self.__delete(destination) + self._dests.remove(destination) + + def getDestinations(self): + """Returns an iterator for all destinations of the alias.""" + if self._dests: + return iter(self._dests) else: raise VMMAE(_(u"The alias “%s” doesn't exist.") % self._addr, - ERR.NO_SUCH_ALIAS) + NO_SUCH_ALIAS) def delete(self): - dbc = self._dbh.cursor() - if self._dest is None: - dbc.execute("DELETE FROM alias WHERE gid=%s AND address=%s", - self._gid, self._addr._localpart) + """Deletes the alias with all it's destinations.""" + if self._dests: + self.__delete() + del self._dests[:] else: - dbc.execute("DELETE FROM alias WHERE gid=%s AND address=%s AND \ - destination=%s", self._gid, self._addr._localpart, str(self._dest)) - rowcount = dbc.rowcount - dbc.close() - if rowcount > 0: - self._dbh.commit() - else: - if self._dest is None: - msg = _(u"The alias “%s” doesn't exist.") % self._addr - else: - msg = _(u"The alias “%(a)s” with destination “%(d)s” doesn't\ - exist.") % {'a': self._addr, 'd': self._dest} - raise VMMAE(msg, ERR.NO_SUCH_ALIAS) + raise VMMAE(_(u"The alias “%s” doesn't exist.") % self._addr, + NO_SUCH_ALIAS) + +del _ diff -r 05dd49fc3ea1 -r 65a3163bd113 VirtualMailManager/Handler.py --- a/VirtualMailManager/Handler.py Tue Feb 09 22:14:08 2010 +0000 +++ b/VirtualMailManager/Handler.py Wed Feb 10 02:13:35 2010 +0000 @@ -42,7 +42,7 @@ class Handler(object): """Wrapper class to simplify the access on all the stuff from VirtualMailManager""" - __slots__ = ('_Cfg', '_cfgFileName', '__dbh', '_scheme', '__warnings', + __slots__ = ('_Cfg', '_cfgFileName', '_dbh', '_scheme', '__warnings', '_postconf') def __init__(self, skip_some_checks=False): @@ -58,7 +58,7 @@ self._cfgFileName = '' self.__warnings = [] self._Cfg = None - self.__dbh = None + self._dbh = None if os.geteuid(): raise VMMNotRootException(_(u"You are not root.\n\tGood bye!\n"), @@ -129,16 +129,16 @@ def __dbConnect(self): """Creates a pyPgSQL.PgSQL.connection instance.""" - if self.__dbh is None or (isinstance(self.__dbh, PgSQL.Connection) and - not self.__dbh._isOpen): + if self._dbh is None or (isinstance(self._dbh, PgSQL.Connection) and + not self._dbh._isOpen): try: - self.__dbh = PgSQL.connect( + 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'), client_encoding='utf8', unicode_results=True) - dbc = self.__dbh.cursor() + dbc = self._dbh.cursor() dbc.execute("SET NAMES 'UTF8'") dbc.close() except PgSQL.libpq.DatabaseError, e: @@ -157,22 +157,22 @@ def accountExists(dbh, address): sql = "SELECT gid FROM users WHERE gid = (SELECT gid FROM domain_name\ - WHERE domainname = '%s') AND local_part = '%s'" % (address._domainname, - address._localpart) + WHERE domainname = '%s') AND local_part = '%s'" % (address.domainname, + address.localpart) return Handler._exists(dbh, sql) accountExists = staticmethod(accountExists) def aliasExists(dbh, address): sql = "SELECT DISTINCT gid FROM alias WHERE gid = (SELECT gid FROM\ domain_name WHERE domainname = '%s') AND address = '%s'" % ( - address._domainname, address._localpart) + address.domainname, address.localpart) |
|
From: <nev...@us...> - 2010-02-09 22:14:34
|
details: http://hg.localdomain.org/vmm/rev/05dd49fc3ea1 changeset: 195:05dd49fc3ea1 user: Pascal Volk date: Tue Feb 09 22:14:08 2010 +0000 description: VMM/EmailAddress: reworked class EmailAddress again. The attributes domainname and localpart are now read-only. diffstat: VirtualMailManager/EmailAddress.py | 34 ++++++++++++++++++++++------------ 1 files changed, 22 insertions(+), 12 deletions(-) diffs (73 lines): diff -r 6c06edb5b2d2 -r 05dd49fc3ea1 VirtualMailManager/EmailAddress.py --- a/VirtualMailManager/EmailAddress.py Tue Feb 09 04:59:40 2010 +0000 +++ b/VirtualMailManager/EmailAddress.py Tue Feb 09 22:14:08 2010 +0000 @@ -21,34 +21,44 @@ class EmailAddress(object): """Simple class for validated e-mail addresses.""" - __slots__ = ('localpart', 'domainname') + __slots__ = ('_localpart', '_domainname') def __init__(self, address): """Creates a new instance from the string/unicode ``address``.""" if not isinstance(address, basestring): raise TypeError('address is not a str/unicode object: %r' % address) - self.localpart = None - self.domainname = None + self._localpart = None + self._domainname = None self._chk_address(address) + @property + def localpart(self): + """The local-part of the address *local-part@domain*""" + return self._localpart + + @property + def domainname(self): + """The domain part of the address *local-part@domain*""" + return self._domainname + 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 __repr__(self): - return "EmailAddress('%s@%s')" % (self.localpart, self.domainname) + return "EmailAddress('%s@%s')" % (self._localpart, self._domainname) def __str__(self): - return "%s@%s" % (self.localpart, self.domainname) + return "%s@%s" % (self._localpart, self._domainname) def _chk_address(self, address): """Checks if the string ``address`` could be used for an e-mail @@ -56,12 +66,12 @@ parts = address.split('@') p_len = len(parts) if p_len is 2: - self.localpart = check_localpart(parts[0]) + self._localpart = check_localpart(parts[0]) if len(parts[1]) > 0: - self.domainname = chk_domainname(parts[1]) + self._domainname = chk_domainname(parts[1]) else: raise VMMEAE(_(u"Missing domain name after “%s@”.") % - self.localpart, DOMAIN_NO_NAME) + self._localpart, DOMAIN_NO_NAME) elif p_len < 2: raise VMMEAE(_(u"Missing '@' sign in e-mail address “%s”.") % address, INVALID_ADDRESS) |
|
From: <nev...@us...> - 2010-02-09 05:00:34
|
details: http://hg.localdomain.org/vmm/rev/6c06edb5b2d2 changeset: 194:6c06edb5b2d2 user: Pascal Volk date: Tue Feb 09 04:59:40 2010 +0000 description: VMM/EmailAddress: reworked once more. - moved EmailAddress.__chkLocalpart() -> __module__.check_localpart() - renamed EmailAddress.__chkAddress() -> EmailAddress._chk_address() - attributes domainname and localpart are no longer protected - added missing doc strings. diffstat: VirtualMailManager/EmailAddress.py | 78 ++++++++++++++++++++++--------------- 1 files changed, 46 insertions(+), 32 deletions(-) diffs (124 lines): diff -r a259bdeaab5c -r 6c06edb5b2d2 VirtualMailManager/EmailAddress.py --- a/VirtualMailManager/EmailAddress.py Mon Feb 08 03:14:59 2010 +0000 +++ b/VirtualMailManager/EmailAddress.py Tue Feb 09 04:59:40 2010 +0000 @@ -2,7 +2,11 @@ # Copyright (c) 2008 - 2010, Pascal Volk # See COPYING for distribution information. -"""Virtual Mail Manager's EmailAddress class to handle e-mail addresses.""" +""" + VirtualMailManager.EmailAddress + + Virtual Mail Manager's EmailAddress class to handle e-mail addresses. +""" import re @@ -16,44 +20,48 @@ class EmailAddress(object): - __slots__ = ('_localpart', '_domainname') + """Simple class for validated e-mail addresses.""" + __slots__ = ('localpart', 'domainname') def __init__(self, address): + """Creates a new instance from the string/unicode ``address``.""" if not isinstance(address, basestring): raise TypeError('address is not a str/unicode object: %r' % address) - self._localpart = None - self._domainname = None - self.__chkAddress(address) + self.localpart = None + self.domainname = None + self._chk_address(address) 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 __repr__(self): - return "EmailAddress('%s@%s')" % (self._localpart, self._domainname) + return "EmailAddress('%s@%s')" % (self.localpart, self.domainname) def __str__(self): - return "%s@%s" % (self._localpart, self._domainname) + return "%s@%s" % (self.localpart, self.domainname) - def __chkAddress(self, address): + def _chk_address(self, address): + """Checks if the string ``address`` could be used for an e-mail + address.""" parts = address.split('@') p_len = len(parts) if p_len is 2: - self._localpart = self.__chkLocalpart(parts[0]) + self.localpart = check_localpart(parts[0]) if len(parts[1]) > 0: - self._domainname = chk_domainname(parts[1]) + self.domainname = chk_domainname(parts[1]) else: raise VMMEAE(_(u"Missing domain name after “%s@”.") % - self._localpart, DOMAIN_NO_NAME) + self.localpart, DOMAIN_NO_NAME) elif p_len < 2: raise VMMEAE(_(u"Missing '@' sign in e-mail address “%s”.") % address, INVALID_ADDRESS) @@ -61,21 +69,27 @@ raise VMMEAE(_(u"Too many '@' signs in e-mail address “%s”.") % address, INVALID_ADDRESS) - def __chkLocalpart(self, localpart): - """Validates the local-part of an e-mail address. - Arguments: - localpart -- local-part of the e-mail address that should be validated - """ - if len(localpart) < 1: - raise VMMEAE(_(u'No local-part specified.'), LOCALPART_INVALID) - if len(localpart) > 64: - raise VMMEAE(_(u'The local-part “%s” is too long') % localpart, - LOCALPART_TOO_LONG) - ic = set(re.findall(RE_LOCALPART, localpart)) - if len(ic): - ichrs = u''.join((u'“%s” ' % c for c in ic)) - raise VMMEAE(_(u"The local-part “%(lpart)s” contains invalid\ - characters: %(ichrs)s") % {'lpart': localpart, 'ichrs': ichrs}, - LOCALPART_INVALID) - return localpart +_ = lambda msg: msg + + +def check_localpart(localpart): + """Validates the local-part of an e-mail address. + + Argument: + localpart -- local-part of the e-mail address that should be validated + """ + if len(localpart) < 1: + raise VMMEAE(_(u'No local-part specified.'), LOCALPART_INVALID) + if len(localpart) > 64: + raise VMMEAE(_(u'The local-part “%s” is too long') % localpart, + LOCALPART_TOO_LONG) + invalid_chars = set(re.findall(RE_LOCALPART, localpart)) + if invalid_chars: + i_chrs = u''.join((u'“%s” ' % c for c in invalid_chars)) + raise VMMEAE(_(u"The local-part “%(l_part)s” contains invalid\ + characters: %(i_chrs)s") % {'l_part': localpart, 'i_chrs': i_chrs}, + LOCALPART_INVALID) + return localpart + +del _ |
|
From: <nev...@us...> - 2010-02-08 03:15:13
|
details: http://hg.localdomain.org/vmm/rev/a259bdeaab5c changeset: 193:a259bdeaab5c user: Pascal Volk date: Mon Feb 08 03:14:59 2010 +0000 description: VMM/EmailAddress: rework EmailAddress class. diffstat: VirtualMailManager/EmailAddress.py | 61 +++++++++++++++++++------------------ 1 files changed, 32 insertions(+), 29 deletions(-) diffs (107 lines): diff -r 0854fb9f3bc5 -r a259bdeaab5c VirtualMailManager/EmailAddress.py --- a/VirtualMailManager/EmailAddress.py Sun Feb 07 06:28:35 2010 +0000 +++ b/VirtualMailManager/EmailAddress.py Mon Feb 08 03:14:59 2010 +0000 @@ -6,29 +6,36 @@ import re -import VirtualMailManager.constants.ERROR as ERR from VirtualMailManager import chk_domainname +from VirtualMailManager.constants.ERROR import \ + DOMAIN_NO_NAME, INVALID_ADDRESS, LOCALPART_INVALID, LOCALPART_TOO_LONG from VirtualMailManager.Exceptions import VMMEmailAddressException as VMMEAE + RE_LOCALPART = """[^\w!#$%&'\*\+-\.\/=?^_`{\|}~]""" + class EmailAddress(object): __slots__ = ('_localpart', '_domainname') + def __init__(self, address): + if not isinstance(address, basestring): + raise TypeError('address is not a str/unicode object: %r' % + address) self._localpart = None self._domainname = None self.__chkAddress(address) 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 __repr__(self): @@ -38,41 +45,37 @@ return "%s@%s" % (self._localpart, self._domainname) def __chkAddress(self, address): - try: - localpart, domain = address.split('@') - except ValueError: + parts = address.split('@') + p_len = len(parts) + if p_len is 2: + self._localpart = self.__chkLocalpart(parts[0]) + if len(parts[1]) > 0: + self._domainname = chk_domainname(parts[1]) + else: + raise VMMEAE(_(u"Missing domain name after “%s@”.") % + self._localpart, DOMAIN_NO_NAME) + elif p_len < 2: raise VMMEAE(_(u"Missing '@' sign in e-mail address “%s”.") % - address, ERR.INVALID_ADDRESS) - except AttributeError: - raise VMMEAE(_(u"“%s” doesn't look like an e-mail address.") % - address, ERR.INVALID_ADDRESS) - if len(domain) > 0: - domain = chk_domainname(domain) - else: - raise VMMEAE(_(u"Missing domain name after “%s@”.") % localpart, - ERR.DOMAIN_NO_NAME) - localpart = self.__chkLocalpart(localpart) - self._localpart, self._domainname = localpart, domain + address, INVALID_ADDRESS) + elif p_len > 2: + raise VMMEAE(_(u"Too many '@' signs in e-mail address “%s”.") % + address, INVALID_ADDRESS) def __chkLocalpart(self, localpart): """Validates the local-part of an e-mail address. Arguments: - localpart -- local-part of the e-mail address that should be validated (str) + localpart -- local-part of the e-mail address that should be validated """ if len(localpart) < 1: - raise VMMEAE(_(u'No local-part specified.'), - ERR.LOCALPART_INVALID) + raise VMMEAE(_(u'No local-part specified.'), LOCALPART_INVALID) if len(localpart) > 64: - raise VMMEAE(_(u'The local-part “%s” is too long') % - localpart, ERR.LOCALPART_TOO_LONG) + raise VMMEAE(_(u'The local-part “%s” is too long') % localpart, + LOCALPART_TOO_LONG) ic = set(re.findall(RE_LOCALPART, localpart)) if len(ic): - ichrs = '' - for c in ic: - ichrs += u"“%s” " % c + ichrs = u''.join((u'“%s” ' % c for c in ic)) raise VMMEAE(_(u"The local-part “%(lpart)s” contains invalid\ characters: %(ichrs)s") % {'lpart': localpart, 'ichrs': ichrs}, - ERR.LOCALPART_INVALID) + LOCALPART_INVALID) return localpart - |
|
From: <nev...@us...> - 2010-02-07 06:28:51
|
details: http://hg.localdomain.org/vmm/rev/0854fb9f3bc5 changeset: 192:0854fb9f3bc5 user: Pascal Volk date: Sun Feb 07 06:28:35 2010 +0000 description: VMM/Handler: fixed a SyntaxError. Oops diffstat: VirtualMailManager/Handler.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff -r db77501aeaed -r 0854fb9f3bc5 VirtualMailManager/Handler.py --- a/VirtualMailManager/Handler.py Sun Feb 07 06:12:48 2010 +0000 +++ b/VirtualMailManager/Handler.py Sun Feb 07 06:28:35 2010 +0000 @@ -563,7 +563,7 @@ The account has been successfully deleted from the database. But an error occurred while deleting the following directory: “%(directory)s” - Reason: %(reason)s""") % + Reason: %(reason)s""") % \ {'directory': acc.getDir('home'), 'reason': e.msg()} self.__warnings.append(warning) else: |
|
From: <nev...@us...> - 2010-02-07 06:13:05
|
details: http://hg.localdomain.org/vmm/rev/db77501aeaed changeset: 191:db77501aeaed user: Pascal Volk date: Sun Feb 07 06:12:48 2010 +0000 description: VMM/Handler: __mailDirMake() add warning for skipped mailboxes. - domainInfo() removed old deprecated warning. - fixed PEP8 warnings. diffstat: VirtualMailManager/Handler.py | 86 ++++++++++++++++++++++++------------------- 1 files changed, 48 insertions(+), 38 deletions(-) diffs (231 lines): diff -r 1903d4ce97d7 -r db77501aeaed VirtualMailManager/Handler.py --- a/VirtualMailManager/Handler.py Sun Feb 07 03:44:04 2010 +0000 +++ b/VirtualMailManager/Handler.py Sun Feb 07 06:12:48 2010 +0000 @@ -44,6 +44,7 @@ VirtualMailManager""" __slots__ = ('_Cfg', '_cfgFileName', '__dbh', '_scheme', '__warnings', '_postconf') + def __init__(self, skip_some_checks=False): """Creates a new Handler instance. @@ -89,7 +90,7 @@ 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 VMMPermException(_( + raise VMMPermException(_( u'fix permissions (%(perms)s) for “%(file)s”\n\ `chmod 0600 %(file)s` would be great.') % {'file': self._cfgFileName, 'perms': fmode}, ERR.CONF_WRONGPERM) @@ -115,11 +116,13 @@ code = e.code() if code is ERR.NO_SUCH_BINARY: raise VMMException(_(u'“%(binary)s” doesn\'t exist.\n\ -(vmm.cfg: section "bin", option "%(option)s")') %{'binary': val,'option': opt}, +(vmm.cfg: section "bin", option "%(option)s")') % + {'binary': val, 'option': opt}, ERR.NO_SUCH_BINARY) elif code is ERR.NOT_EXECUTABLE: - raise VMMException(_(u'“%(binary)s” is not executable.\n\ -(vmm.cfg: section "bin", option "%(option)s")') %{'binary': val,'option': opt}, + raise VMMException(_(u'“%(binary)s” is not executable.\ +\n(vmm.cfg: section "bin", option "%(option)s")') % + {'binary': val, 'option': opt}, ERR.NOT_EXECUTABLE) else: raise @@ -162,18 +165,17 @@ def aliasExists(dbh, address): sql = "SELECT DISTINCT gid FROM alias WHERE gid = (SELECT gid FROM\ domain_name WHERE domainname = '%s') AND address = '%s'" % ( - address._domainname, address._localpart) + address._domainname, address._localpart) return Handler._exists(dbh, sql) aliasExists = staticmethod(aliasExists) def relocatedExists(dbh, address): sql = "SELECT gid FROM relocated WHERE gid = (SELECT gid FROM\ domain_name WHERE domainname = '%s') AND address = '%s'" % ( - address._domainname, address._localpart) + address._domainname, address._localpart) return Handler._exists(dbh, sql) relocatedExists = staticmethod(relocatedExists) - def __getAccount(self, address, password=None): self.__dbConnect() address = EmailAddress(address) @@ -188,7 +190,7 @@ destination = EmailAddress(destination) return Alias(self.__dbh, address, destination) - def __getRelocated(self,address, destination=None): + def __getRelocated(self, address, destination=None): self.__dbConnect() address = EmailAddress(address) if destination is not None: @@ -234,7 +236,7 @@ os.umask(0006) oldpwd = os.getcwd() basedir = self._Cfg.dget('misc.base_directory') - domdirdirs = domdir.replace(basedir+'/', '').split('/') + domdirdirs = domdir.replace(basedir + '/', '').split('/') os.chdir(basedir) if not os.path.isdir(domdirdirs[0]): @@ -246,11 +248,12 @@ 0, gid) os.chdir(oldpwd) - def __subscribeFL(self, folderlist, uid, gid): + 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 = file(fname, 'w') + sf = open(fname, 'w') for f in folderlist: - sf.write(f+'\n') + sf.write('%s\n' % f) sf.flush() sf.close() os.chown(fname, uid, gid) @@ -270,11 +273,19 @@ 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('..')\ - and re.match(RE_MBOX_NAMES, folder): - folders.append('%s/.%s' % (maildir, folder)) + 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') @@ -284,8 +295,8 @@ self.__makedir(folder, mode, uid, gid) for subdir in subdirs: self.__makedir(os.path.join(folder, subdir), mode, uid, gid) - self.__subscribeFL([f.replace(maildir+'/.', '') for f in folders[1:]], - uid, gid) + self.__subscribe((f.replace(maildir + '/.', '') for f in folders[1:]), + uid, gid) os.chdir(oldpwd) def __userDirDelete(self, domdir, uid, gid): @@ -293,15 +304,15 @@ userdir = '%s' % uid if userdir.count('..') or domdir.count('..'): raise VMMException(_(u'Found ".." in home directory path.'), - ERR.FOUND_DOTS_IN_PATH) + ERR.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 VMMException( - _(u'Detected owner/group mismatch in home directory.'), - ERR.MAILDIR_PERM_MISMATCH) + raise VMMException(_( + u'Detected owner/group mismatch in home directory.'), + ERR.MAILDIR_PERM_MISMATCH) rmtree(userdir, ignore_errors=True) else: raise VMMException(_(u"No such directory: %s") % @@ -312,7 +323,7 @@ if not self.__isdir(domdir): return basedir = self._Cfg.dget('misc.base_directory') - domdirdirs = domdir.replace(basedir+'/', '').split('/') + domdirdirs = domdir.replace(basedir + '/', '').split('/') domdirparent = os.path.join(basedir, domdirdirs[0]) if basedir.count('..') or domdir.count('..'): raise VMMException(_(u'Found ".." in domain directory path.'), @@ -378,8 +389,9 @@ return '{%s}%s' % (self._scheme, self.__pwMD4(password)) elif self._scheme in ['SMD5', 'SSHA', 'CRAM-MD5', 'HMAC-MD5', 'LANMAN', 'NTLM', 'RPA']: - return Popen([self._Cfg.dget('bin.dovecotpw'), '-s', - self._scheme,'-p',password],stdout=PIPE).communicate()[0][:-1] + return Popen([self._Cfg.dget('bin.dovecotpw'), + '-s', self._scheme, '-p', password], + stdout=PIPE).communicate()[0][:-1] else: return '{%s}%s' % (self._scheme, password) @@ -413,9 +425,10 @@ dom.updateTransport(transport, force=True) def domainDelete(self, domainname, force=None): - if not force is None and force not in ['deluser','delalias','delall']: - raise VMMDomainException(_(u"Invalid argument: “%s”") % force, - ERR.INVALID_OPTION) + if not force is None and force not in ['deluser', 'delalias', + 'delall']: + raise VMMDomainException(_(u'Invalid argument: “%s”') % + force, ERR.INVALID_OPTION) dom = self.__getDomain(domainname) gid = dom.getID() domdir = dom.getDir() @@ -432,14 +445,9 @@ def domainInfo(self, domainname, details=None): if details not in [None, 'accounts', 'aliasdomains', 'aliases', 'full', - 'relocated', 'detailed']: + 'relocated']: raise VMMException(_(u'Invalid argument: “%s”') % details, - ERR.INVALID_AGUMENT) - if details == 'detailed': - details = 'full' - self.__warnings.append(_(u'\ -The keyword “detailed” is deprecated and will be removed in a future release.\n\ - Please use the keyword “full” to get full details.')) + ERR.INVALID_AGUMENT) dom = self.__getDomain(domainname) dominfo = dom.getInfo() if dominfo['domainname'].startswith('xn--'): @@ -534,7 +542,7 @@ if gid > 0 and (not Handler.accountExists(self.__dbh, alias._dest) and not Handler.aliasExists(self.__dbh, alias._dest)): self.__warnings.append( - _(u"The destination account/alias “%s” doesn't exist.") % + _(u"The destination account/alias “%s” doesn't exist.") % alias._dest) def userDelete(self, emailaddress, force=None): @@ -555,10 +563,11 @@ 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.getDir('home'),'reason': e.msg()} + Reason: %(reason)s""") % + {'directory': acc.getDir('home'), 'reason': e.msg()} self.__warnings.append(warning) else: - raise e + raise def aliasInfo(self, aliasaddress): alias = self.__getAlias(aliasaddress) @@ -593,7 +602,8 @@ raise ValueError('could not accept password: %r' % password) acc = self.__getAccount(emailaddress) if acc.getUID() == 0: - raise VMMException(_(u"Account doesn't exist"), ERR.NO_SUCH_ACCOUNT) + raise VMMException(_(u"Account doesn't exist"), + ERR.NO_SUCH_ACCOUNT) acc.modify('password', self.__pwhash(password, user=emailaddress)) def userName(self, emailaddress, name): |
|
From: <nev...@us...> - 2010-02-07 03:45:02
|
details: http://hg.localdomain.org/vmm/rev/1903d4ce97d7 changeset: 190:1903d4ce97d7 user: Pascal Volk date: Sun Feb 07 03:44:04 2010 +0000 description: VMM/{,cli/}Handler: reverted most of cs cf1b5f22dbd2 added a cli handler. Moved the interactive stuff from VMM/Handler to the derived VMM/cli/Handler. diffstat: VirtualMailManager/Handler.py | 186 ++++++++++++++++--------------------- VirtualMailManager/cli/Handler.py | 78 +++++++++++++++ 2 files changed, 160 insertions(+), 104 deletions(-) diffs (truncated from 499 to 300 lines): diff -r e63853509ad0 -r 1903d4ce97d7 VirtualMailManager/Handler.py --- a/VirtualMailManager/Handler.py Sat Feb 06 18:42:05 2010 +0000 +++ b/VirtualMailManager/Handler.py Sun Feb 07 03:44:04 2010 +0000 @@ -25,61 +25,59 @@ from VirtualMailManager.Account import Account from VirtualMailManager.Alias import Alias from VirtualMailManager.AliasDomain import AliasDomain +from VirtualMailManager.Config import Config as Cfg from VirtualMailManager.Domain import Domain from VirtualMailManager.EmailAddress import EmailAddress from VirtualMailManager.Exceptions import * from VirtualMailManager.Relocated import Relocated from VirtualMailManager.ext.Postconf import Postconf + SALTCHARS = './0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' RE_DOMAIN_SRCH = """^[a-z0-9-\.]+$""" RE_LOCALPART = """[^\w!#$%&'\*\+-\.\/=?^_`{\|}~]""" RE_MBOX_NAMES = """^[\x20-\x25\x27-\x7E]*$""" + class Handler(object): """Wrapper class to simplify the access on all the stuff from VirtualMailManager""" - __slots__ = ('__Cfg', '__cfgFileName', '__dbh', '__scheme', '__warnings', + __slots__ = ('_Cfg', '_cfgFileName', '__dbh', '_scheme', '__warnings', '_postconf') - def __init__(self, config_type='default'): + def __init__(self, skip_some_checks=False): """Creates a new Handler instance. - Accepted ``config_type``s are 'default' and 'cli'. + ``skip_some_checks`` : bool + When a derived class knows how to handle all checks this + argument may be ``True``. By default it is ``False`` and + all checks will be performed. Throws a VMMNotRootException if your uid is greater 0. """ - self.__cfgFileName = '' + self._cfgFileName = '' self.__warnings = [] - self.__Cfg = None + self._Cfg = None self.__dbh = None - if config_type == 'default': - from VirtualMailManager.Config import Config as Cfg - elif config_type == 'cli': - from VirtualMailManager.cli.CliConfig import CliConfig as Cfg - from VirtualMailManager.cli import read_pass - else: - raise ValueError('invalid config_type: %r' % config_type) - if os.geteuid(): raise VMMNotRootException(_(u"You are not root.\n\tGood bye!\n"), ERR.CONF_NOPERM) if self.__chkCfgFile(): - self.__Cfg = Cfg(self.__cfgFileName) - self.__Cfg.load() - if not os.sys.argv[1] in ('cf','configure','h','help','v','version'): - self.__Cfg.check() - self.__chkenv() - self.__scheme = self.__Cfg.dget('misc.password_scheme') - self._postconf = Postconf(self.__Cfg.dget('bin.postconf')) + self._Cfg = Cfg(self._cfgFileName) + self._Cfg.load() + if not skip_some_checks: + self._Cfg.check() + self._chkenv() + self._scheme = self._Cfg.dget('misc.password_scheme') + self._postconf = Postconf(self._Cfg.dget('bin.postconf')) def __findCfgFile(self): for path in ['/root', '/usr/local/etc', '/etc']: tmp = os.path.join(path, 'vmm.cfg') if os.path.isfile(tmp): - self.__cfgFileName = tmp + self._cfgFileName = tmp break - if not len(self.__cfgFileName): + if not len(self._cfgFileName): raise VMMException( _(u"No “vmm.cfg” found in: /root:/usr/local/etc:/etc"), ERR.CONF_NOFILE) @@ -87,30 +85,30 @@ def __chkCfgFile(self): """Checks the configuration file, returns bool""" self.__findCfgFile() - fstat = os.stat(self.__cfgFileName) + fstat = os.stat(self._cfgFileName) 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 VMMPermException(_( u'fix permissions (%(perms)s) for “%(file)s”\n\ `chmod 0600 %(file)s` would be great.') % {'file': - self.__cfgFileName, 'perms': fmode}, ERR.CONF_WRONGPERM) + self._cfgFileName, 'perms': fmode}, ERR.CONF_WRONGPERM) else: return True - def __chkenv(self): + def _chkenv(self): """""" - basedir = self.__Cfg.dget('misc.base_directory') + 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, self.__Cfg.dget('misc.gid_mail')) + os.chown(basedir, 0, self._Cfg.dget('misc.gid_mail')) os.umask(old_umask) elif not os.path.isdir(basedir): raise VMMException(_(u'“%s” is not a directory.\n\ (vmm.cfg: section "misc", option "base_directory")') % basedir, ERR.NO_SUCH_DIRECTORY) - for opt, val in self.__Cfg.items('bin'): + for opt, val in self._Cfg.items('bin'): try: exec_ok(val) except VMMException, e: @@ -132,10 +130,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'") @@ -199,10 +197,10 @@ def __getDomain(self, domainname, transport=None): if transport is None: - transport = self.__Cfg.dget('misc.transport') + transport = self._Cfg.dget('misc.transport') self.__dbConnect() return Domain(self.__dbh, domainname, - self.__Cfg.dget('misc.base_directory'), transport) + self._Cfg.dget('misc.base_directory'), transport) def __getDiskUsage(self, directory): """Estimate file space usage for the given directory. @@ -211,7 +209,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 @@ -224,7 +222,7 @@ def __makedir(self, directory, mode=None, uid=None, gid=None): if mode is None: - mode = self.__Cfg.dget('account.directory_mode') + mode = self._Cfg.dget('account.directory_mode') if uid is None: uid = 0 if gid is None: @@ -235,21 +233,21 @@ def __domDirMake(self, domdir, gid): os.umask(0006) oldpwd = os.getcwd() - basedir = self.__Cfg.dget('misc.base_directory') + 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, - self.__Cfg.dget('misc.gid_mail')) + self._Cfg.dget('misc.gid_mail')) os.chdir(domdirdirs[0]) os.umask(0007) - self.__makedir(domdirdirs[1], self.__Cfg.dget('domain.directory_mode'), + self.__makedir(domdirdirs[1], self._Cfg.dget('domain.directory_mode'), 0, gid) os.chdir(oldpwd) def __subscribeFL(self, folderlist, uid, gid): - fname = os.path.join(self.__Cfg.dget('maildir.name'), 'subscriptions') + fname = os.path.join(self._Cfg.dget('maildir.name'), 'subscriptions') sf = file(fname, 'w') for f in folderlist: sf.write(f+'\n') @@ -270,15 +268,15 @@ oldpwd = os.getcwd() os.chdir(domdir) - maildir = self.__Cfg.dget('maildir.name') + maildir = self._Cfg.dget('maildir.name') folders = [maildir] - for folder in self.__Cfg.dget('maildir.folders').split(':'): + for folder in self._Cfg.dget('maildir.folders').split(':'): folder = folder.strip() if len(folder) and not folder.count('..')\ and re.match(RE_MBOX_NAMES, folder): folders.append('%s/.%s' % (maildir, folder)) subdirs = ['cur', 'new', 'tmp'] - mode = self.__Cfg.dget('account.directory_mode') + mode = self._Cfg.dget('account.directory_mode') self.__makedir('%s' % uid, mode, uid, gid) os.chdir('%s' % uid) @@ -313,7 +311,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('..'): @@ -330,9 +328,9 @@ def __getSalt(self): from random import choice salt = None - if self.__scheme == 'CRYPT': + if self._scheme == 'CRYPT': salt = '%s%s' % (choice(SALTCHARS), choice(SALTCHARS)) - elif self.__scheme in ['MD5', 'MD5-CRYPT']: + elif self._scheme in ['MD5', 'MD5-CRYPT']: salt = '$1$%s$' % ''.join([choice(SALTCHARS) for x in xrange(8)]) return salt @@ -351,12 +349,12 @@ def __pwMD5(self, password, emailaddress=None): import md5 _md5 = md5.new(password) - if self.__scheme == 'LDAP-MD5': + if self._scheme == 'LDAP-MD5': from base64 import standard_b64encode return standard_b64encode(_md5.digest()) - elif self.__scheme == 'PLAIN-MD5': + elif self._scheme == 'PLAIN-MD5': return _md5.hexdigest() - elif self.__scheme == 'DIGEST-MD5' and emailaddress is not None: + elif self._scheme == 'DIGEST-MD5' and emailaddress is not None: # use an empty realm - works better with usenames like user@dom _md5 = md5.new('%s::%s' % (emailaddress, password)) return _md5.hexdigest() @@ -369,21 +367,21 @@ def __pwhash(self, password, scheme=None, user=None): if scheme is not None: - self.__scheme = scheme - if self.__scheme in ['CRYPT', 'MD5', 'MD5-CRYPT']: - return '{%s}%s' % (self.__scheme, self.__pwCrypt(password)) - elif self.__scheme in ['SHA', 'SHA1']: - return '{%s}%s' % (self.__scheme, self.__pwSHA1(password)) - elif self.__scheme in ['PLAIN-MD5', 'LDAP-MD5', 'DIGEST-MD5']: - return '{%s}%s' % (self.__scheme, self.__pwMD5(password, user)) - elif self.__scheme == 'MD4': - return '{%s}%s' % (self.__scheme, self.__pwMD4(password)) - elif self.__scheme in ['SMD5', 'SSHA', 'CRAM-MD5', 'HMAC-MD5', + self._scheme = scheme + if self._scheme in ['CRYPT', 'MD5', 'MD5-CRYPT']: + return '{%s}%s' % (self._scheme, self.__pwCrypt(password)) + elif self._scheme in ['SHA', 'SHA1']: + return '{%s}%s' % (self._scheme, self.__pwSHA1(password)) + elif self._scheme in ['PLAIN-MD5', 'LDAP-MD5', 'DIGEST-MD5']: + return '{%s}%s' % (self._scheme, self.__pwMD5(password, user)) + elif self._scheme == 'MD4': + return '{%s}%s' % (self._scheme, self.__pwMD4(password)) + elif self._scheme in ['SMD5', 'SSHA', 'CRAM-MD5', 'HMAC-MD5', 'LANMAN', 'NTLM', 'RPA']: - return Popen([self.__Cfg.dget('bin.dovecotpw'), '-s', - self.__scheme,'-p',password],stdout=PIPE).communicate()[0][:-1] + return Popen([self._Cfg.dget('bin.dovecotpw'), '-s', + self._scheme,'-p',password],stdout=PIPE).communicate()[0][:-1] else: - return '{%s}%s' % (self.__scheme, password) + return '{%s}%s' % (self._scheme, password) def hasWarnings(self): """Checks if warnings are present, returns bool.""" @@ -394,31 +392,10 @@ return self.__warnings def cfgDget(self, option): - return self.__Cfg.dget(option) + return self._Cfg.dget(option) def cfgPget(self, option): - return self.__Cfg.pget(option) - - def cfgSet(self, option, value): - return self.__Cfg.set(option, value) - - def configure(self, section=None): - """Starts interactive configuration. |
|
From: <nev...@us...> - 2010-02-06 18:42:24
|
details: http://hg.localdomain.org/vmm/rev/e63853509ad0 changeset: 189:e63853509ad0 user: Pascal Volk date: Sat Feb 06 18:42:05 2010 +0000 description: moved VMM/cli/CliConfig to VMM/cli/Config diffstat: VirtualMailManager/cli/CliConfig.py | 82 ------------------------------------- VirtualMailManager/cli/Config.py | 82 +++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 82 deletions(-) diffs (172 lines): diff -r cf1b5f22dbd2 -r e63853509ad0 VirtualMailManager/cli/CliConfig.py --- a/VirtualMailManager/cli/CliConfig.py Sat Feb 06 04:09:17 2010 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,82 +0,0 @@ -# -*- coding: UTF-8 -*- -# Copyright (c) 2010, Pascal Volk -# See COPYING for distribution information. - -""" - VirtualMailManager.cli.CliConfig - - Adds some interactive stuff to the Config class. -""" - -from VirtualMailManager import ENCODING -from VirtualMailManager.Config import Config -from VirtualMailManager.cli import w_std -from VirtualMailManager.constants.ERROR import VMM_TOO_MANY_FAILURES - -class CliConfig(Config): - """Adds the interactive ``configure`` method to the `Config` class - and overwrites `LazyConfig.set(), in order to update a single option - in the configuration file with a single command line command. - """ - def configure(self, sections): - """Interactive method for configuring all options of the given - iterable ``sections`` object.""" - input_fmt = _(u'Enter new value for option %(option)s \ -[%(current_value)s]: ') - failures = 0 - - w_std(_(u'Using configuration file: %s\n') % self._cfgFileName) - for s in sections: - w_std(_(u'* Configuration section: “%s”') % s ) - for opt, val in self.items(s): - 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('%s.%s' % (s, opt), newval) - break - except (ValueError, ConfigValueError), e: - w_std(_(u'Warning: %s') % e) - failures += 1 - if failures > 2: - raise VMMConfigException( - _(u'Too many failures - try again later.'), - VMM_TOO_MANY_FAILURES) - else: - break - print - if self._modified: - self.__saveChanges() - - def set(self, option, value): - """Set the value of an option. - - If the new `value` has been set, the configuration file will be - immediately updated. - - Throws a ``ValueError`` if `value` couldn't be converted to - ``LazyConfigOption.cls``""" - section, option_ = self._get_section_option(option) - val = self._cfg[section][option_].cls(value) - if not self._cfg[section][option_].validate is None: - val = self._cfg[section][option_].validate(val) - # Do not write default values also skip identical values - if not self._cfg[section][option_].default is None: - old_val = self.dget(option) - else: - old_val = self.pget(option) - if val == old_val: - return - if not RawConfigParser.has_section(self, section): - self.add_section(section) - RawConfigParser.set(self, section, option_, val) - self.__saveChanges() - - def __saveChanges(self): - """Writes changes to the configuration file.""" - copy2(self._cfgFileName, self._cfgFileName+'.bak') - self._cfgFile = open(self._cfgFileName, 'w') - self.write(self._cfgFile) - self._cfgFile.close() diff -r cf1b5f22dbd2 -r e63853509ad0 VirtualMailManager/cli/Config.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/VirtualMailManager/cli/Config.py Sat Feb 06 18:42:05 2010 +0000 @@ -0,0 +1,82 @@ +# -*- coding: UTF-8 -*- +# Copyright (c) 2010, Pascal Volk +# See COPYING for distribution information. + +""" + VirtualMailManager.cli.CliConfig + + Adds some interactive stuff to the Config class. +""" + +from VirtualMailManager import ENCODING +from VirtualMailManager.Config import Config +from VirtualMailManager.cli import w_std +from VirtualMailManager.constants.ERROR import VMM_TOO_MANY_FAILURES + +class CliConfig(Config): + """Adds the interactive ``configure`` method to the `Config` class + and overwrites `LazyConfig.set(), in order to update a single option + in the configuration file with a single command line command. + """ + def configure(self, sections): + """Interactive method for configuring all options of the given + iterable ``sections`` object.""" + input_fmt = _(u'Enter new value for option %(option)s \ +[%(current_value)s]: ') + failures = 0 + + w_std(_(u'Using configuration file: %s\n') % self._cfgFileName) + for s in sections: + w_std(_(u'* Configuration section: “%s”') % s ) + for opt, val in self.items(s): + 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('%s.%s' % (s, opt), newval) + break + except (ValueError, ConfigValueError), e: + w_std(_(u'Warning: %s') % e) + failures += 1 + if failures > 2: + raise VMMConfigException( + _(u'Too many failures - try again later.'), + VMM_TOO_MANY_FAILURES) + else: + break + print + if self._modified: + self.__saveChanges() + + def set(self, option, value): + """Set the value of an option. + + If the new `value` has been set, the configuration file will be + immediately updated. + + Throws a ``ValueError`` if `value` couldn't be converted to + ``LazyConfigOption.cls``""" + section, option_ = self._get_section_option(option) + val = self._cfg[section][option_].cls(value) + if not self._cfg[section][option_].validate is None: + val = self._cfg[section][option_].validate(val) + # Do not write default values also skip identical values + if not self._cfg[section][option_].default is None: + old_val = self.dget(option) + else: + old_val = self.pget(option) + if val == old_val: + return + if not RawConfigParser.has_section(self, section): + self.add_section(section) + RawConfigParser.set(self, section, option_, val) + self.__saveChanges() + + def __saveChanges(self): + """Writes changes to the configuration file.""" + copy2(self._cfgFileName, self._cfgFileName+'.bak') + self._cfgFile = open(self._cfgFileName, 'w') + self.write(self._cfgFile) + self._cfgFile.close() |
|
From: <nev...@us...> - 2010-02-06 04:09:30
|
details: http://hg.localdomain.org/vmm/rev/cf1b5f22dbd2 changeset: 188:cf1b5f22dbd2 user: Pascal Volk date: Sat Feb 06 04:09:17 2010 +0000 description: VMM/Handler: __init__ accepts now a config_type ('default'||'cli'). - fixed syntax errors, introduced with the last commit. VMM/Config: added Config.configure() -> NotImplementedError. VMM/__init__: install gettext global, everything depends on it. diffstat: VirtualMailManager/Config.py | 5 ++++- VirtualMailManager/Handler.py | 25 +++++++++++++++++-------- VirtualMailManager/__init__.py | 3 +++ vmm | 2 -- 4 files changed, 24 insertions(+), 11 deletions(-) diffs (128 lines): diff -r 38b9a9859749 -r cf1b5f22dbd2 VirtualMailManager/Config.py --- a/VirtualMailManager/Config.py Sat Feb 06 02:11:55 2010 +0000 +++ b/VirtualMailManager/Config.py Sat Feb 06 04:09:17 2010 +0000 @@ -261,7 +261,7 @@ class Config(LazyConfig): - """This class is for reading and modifying vmm's configuration file.""" + """This class is for reading vmm's configuration file.""" def __init__(self, filename): """Creates a new Config instance @@ -321,6 +321,9 @@ }, } + def configure(self, sections): + raise NotImplementedError + def load(self): """Loads the configuration, read only. diff -r 38b9a9859749 -r cf1b5f22dbd2 VirtualMailManager/Handler.py --- a/VirtualMailManager/Handler.py Sat Feb 06 02:11:55 2010 +0000 +++ b/VirtualMailManager/Handler.py Sat Feb 06 04:09:17 2010 +0000 @@ -21,11 +21,10 @@ from pyPgSQL import PgSQL # python-pgsql - http://pypgsql.sourceforge.net import VirtualMailManager.constants.ERROR as ERR -from VirtualMailManager import ENCODING, ace2idna, exec_ok, read_pass +from VirtualMailManager import ENCODING, ace2idna, exec_ok from VirtualMailManager.Account import Account from VirtualMailManager.Alias import Alias from VirtualMailManager.AliasDomain import AliasDomain -from VirtualMailManager.Config import Config as Cfg from VirtualMailManager.Domain import Domain from VirtualMailManager.EmailAddress import EmailAddress from VirtualMailManager.Exceptions import * @@ -40,11 +39,13 @@ class Handler(object): """Wrapper class to simplify the access on all the stuff from VirtualMailManager""" - # TODO: accept a LazyConfig object as argument __slots__ = ('__Cfg', '__cfgFileName', '__dbh', '__scheme', '__warnings', '_postconf') - def __init__(self): + def __init__(self, config_type='default'): """Creates a new Handler instance. + + Accepted ``config_type``s are 'default' and 'cli'. + Throws a VMMNotRootException if your uid is greater 0. """ self.__cfgFileName = '' @@ -52,6 +53,14 @@ self.__Cfg = None self.__dbh = None + if config_type == 'default': + from VirtualMailManager.Config import Config as Cfg + elif config_type == 'cli': + from VirtualMailManager.cli.CliConfig import CliConfig as Cfg + from VirtualMailManager.cli import read_pass + else: + raise ValueError('invalid config_type: %r' % config_type) + if os.geteuid(): raise VMMNotRootException(_(u"You are not root.\n\tGood bye!\n"), ERR.CONF_NOPERM) @@ -154,15 +163,15 @@ def aliasExists(dbh, address): sql = "SELECT DISTINCT gid FROM alias WHERE gid = (SELECT gid FROM\ - domain_name WHERE domainname = '%s') AND address = '%s'" % - (address._domainname, address._localpart) + domain_name WHERE domainname = '%s') AND address = '%s'" % ( + address._domainname, address._localpart) return Handler._exists(dbh, sql) aliasExists = staticmethod(aliasExists) def relocatedExists(dbh, address): sql = "SELECT gid FROM relocated WHERE gid = (SELECT gid FROM\ - domain_name WHERE domainname = '%s') AND address = '%s'" % - (address._domainname, address._localpart) + domain_name WHERE domainname = '%s') AND address = '%s'" % ( + address._domainname, address._localpart) return Handler._exists(dbh, sql) relocatedExists = staticmethod(relocatedExists) diff -r 38b9a9859749 -r cf1b5f22dbd2 VirtualMailManager/__init__.py --- a/VirtualMailManager/__init__.py Sat Feb 06 02:11:55 2010 +0000 +++ b/VirtualMailManager/__init__.py Sat Feb 06 04:09:17 2010 +0000 @@ -4,6 +4,7 @@ # package initialization code # +import gettext import os import re import locale @@ -40,6 +41,8 @@ RE_DOMAIN = """^(?:[a-z0-9-]{1,63}\.){1,}[a-z]{2,6}$""" +gettext.install('vmm', '/usr/local/share/locale', unicode=1) + def get_unicode(string): """Converts `string` to `unicode`, if necessary.""" if isinstance(string, unicode): diff -r 38b9a9859749 -r cf1b5f22dbd2 vmm --- a/vmm Sat Feb 06 02:11:55 2010 +0000 +++ b/vmm Sat Feb 06 04:09:17 2010 +0000 @@ -5,7 +5,6 @@ """This is the vmm main script.""" -import gettext from time import strftime, strptime from VirtualMailManager import * @@ -490,7 +489,6 @@ if __name__ == '__main__': __prog__ = os.path.basename(os.sys.argv[0]) - gettext.install(__prog__, '/usr/local/share/locale', unicode=1) argv = [unicode(arg, ENCODING) for arg in os.sys.argv] argc = len(os.sys.argv) plan_a_b =_(u'Plan A failed ... trying Plan B: %(subcommand)s %(object)s') |
|
From: <nev...@us...> - 2010-02-06 02:12:37
|
details: http://hg.localdomain.org/vmm/rev/38b9a9859749 changeset: 187:38b9a9859749 user: Pascal Volk date: Sat Feb 06 02:11:55 2010 +0000 description: VMM/{,cli/Cli}Config: Moved interactive stuff to new CliConfig class. Renamed Config.getsections() to Config.sections(). Small cosmetics. diffstat: VirtualMailManager/Config.py | 99 +++++++++--------------------------- VirtualMailManager/Handler.py | 25 ++++---- VirtualMailManager/__init__.py | 2 +- VirtualMailManager/cli/CliConfig.py | 82 ++++++++++++++++++++++++++++++ 4 files changed, 121 insertions(+), 87 deletions(-) diffs (truncated from 365 to 300 lines): diff -r 18757fd45e60 -r 38b9a9859749 VirtualMailManager/Config.py --- a/VirtualMailManager/Config.py Fri Feb 05 20:16:44 2010 +0000 +++ b/VirtualMailManager/Config.py Sat Feb 06 02:11:55 2010 +0000 @@ -34,14 +34,13 @@ from shutil import copy2 -from ConfigParser import (Error, MissingSectionHeaderError, NoOptionError, - NoSectionError, ParsingError, RawConfigParser) +from ConfigParser import \ + Error, MissingSectionHeaderError, NoOptionError, NoSectionError, \ + ParsingError, RawConfigParser from cStringIO import StringIO# TODO: move interactive stff to cli -import VirtualMailManager.constants.ERROR as ERR - from VirtualMailManager import ENCODING, exec_ok, get_unicode, is_dir -from VirtualMailManager.cli import w_std# move to cli +from VirtualMailManager.constants.ERROR import CONF_ERROR from VirtualMailManager.Exceptions import VMMConfigException @@ -105,7 +104,7 @@ if value.lower() in self._boolean_states: return self._boolean_states[value.lower()] else: - raise ConfigValueError(_(u'Not a boolean: “%s”') % \ + raise ConfigValueError(_(u'Not a boolean: “%s”') % get_unicode(value)) def get_boolean(self, section, option): @@ -117,7 +116,7 @@ return tmp return self.getboolean(section, option) - def __get_section_option(self, section_option): + def _get_section_option(self, section_option): """splits ``section_option`` (section\ **.**\ option) in two parts and returns them as list ``[section, option]``, if: @@ -134,7 +133,7 @@ sect_opt = section_option.lower().split('.') if len(sect_opt) != 2:# do we need a regexp to check the format? raise BadOptionError( - _(u'Bad format: “%s” - expected: section.option') % \ + _(u'Bad format: “%s” - expected: section.option') % get_unicode(section_option)) if not sect_opt[0] in self._cfg: raise NoSectionError(sect_opt[0]) @@ -175,7 +174,7 @@ Throws a `NoDefaultError`, if no default value was passed to `LazyConfigOption.__init__()` for the `option`. """ - section, option = self.__get_section_option(option) + section, option = self._get_section_option(option) try: return self._cfg[section][option].getter(section, option) except (NoSectionError, NoOptionError): @@ -186,7 +185,7 @@ def pget(self, option): """Returns the value of the `option`.""" - section, option = self.__get_section_option(option) + section, option = self._get_section_option(option) return self._cfg[section][option].getter(section, option) def set(self, option, value): @@ -194,7 +193,7 @@ Throws a ``ValueError`` if `value` couldn't be converted to ``LazyConfigOption.cls``""" - section, option = self.__get_section_option(option) + section, option = self._get_section_option(option) val = self._cfg[section][option].cls(value) if not self._cfg[section][option].validate is None: val = self._cfg[section][option].validate(val) @@ -211,7 +210,7 @@ """Checks if the option (section\ **.**\ option) is a known configuration option.""" try: - self.__get_section_option(option) + self._get_section_option(option) return True except(BadOptionError, NoSectionError, NoOptionError): return False @@ -273,8 +272,8 @@ path to the configuration file """ LazyConfig.__init__(self) - self.__cfgFileName = filename - self.__cfgFile = None + self._cfgFileName = filename + self._cfgFile = None self.__missing = {} LCO = LazyConfigOption @@ -328,13 +327,13 @@ Raises a VMMConfigException if the configuration syntax is invalid. """ try: - self.__cfgFile = open(self.__cfgFileName, 'r') - self.readfp(self.__cfgFile) + self._cfgFile = open(self._cfgFileName, 'r') + self.readfp(self._cfgFile) except (MissingSectionHeaderError, ParsingError), e: - raise VMMConfigException(str(e), ERR.CONF_ERROR) + raise VMMConfigException(str(e), CONF_ERROR) finally: - if not self.__cfgFile is None and not self.__cfgFile.closed: - self.__cfgFile.close() + if not self._cfgFile is None and not self._cfgFile.closed: + self._cfgFile.close() def check(self): """Performs a configuration check. @@ -346,15 +345,15 @@ if not self.__chkCfg(): errmsg = StringIO() errmsg.write(_(u'Missing options, which have no default value.\n')) - errmsg.write(_(u'Using configuration file: %s\n') %\ - self.__cfgFileName) + errmsg.write(_(u'Using configuration file: %s\n') % + self._cfgFileName) for section, options in self.__missing.iteritems(): errmsg.write(_(u'* Section: %s\n') % section) for option in options: errmsg.write((u' %s\n') % option) - raise VMMConfigException(errmsg.getvalue(), ERR.CONF_ERROR) + raise VMMConfigException(errmsg.getvalue(), CONF_ERROR) - def getsections(self): + def sections(self): """Returns an iterator object for all configuration sections.""" return self._cfg.iterkeys() @@ -374,51 +373,6 @@ """ return get_unicode(self.get(section, option)) - def configure(self, sections): - """Interactive method for configuring all options in the given sections - - Arguments: - sections -- list of strings with section names - """ - # TODO: Derivate CliConfig from Config an move the interactive - # stuff to CliConfig - input_fmt = _(u'Enter new value for option %(option)s \ -[%(current_value)s]: ') - failures = 0 - - w_std(_(u'Using configuration file: %s\n') % self.__cfgFileName) - for s in sections: - w_std(_(u'* Configuration section: “%s”') % s ) - for opt, val in self.items(s): - failures = 0 - while True: - newval = raw_input(input_fmt.encode(ENCODING,'replace') %{ - 'option': opt, 'current_value': val}) - if newval and newval != val: - try: - self.set('%s.%s' % (s, opt), newval) - break - except (ValueError, ConfigValueError), e: - w_std(_(u'Warning: %s') % e) - failures += 1 - if failures > 2: - raise VMMConfigException( - _(u'Too many failures - try again later.'), - ERR.VMM_TOO_MANY_FAILURES) - else: - break - print - if self._modified: - self.__saveChanges() - - def __saveChanges(self): - """Writes changes to the configuration file.""" - # TODO: Move interactive stuff to CliConfig - copy2(self.__cfgFileName, self.__cfgFileName+'.bak') - self.__cfgFile = open(self.__cfgFileName, 'w') - self.write(self.__cfgFile) - self.__cfgFile.close() - def __chkCfg(self): """Checks all section's options for settings w/o default values. @@ -427,11 +381,10 @@ for section in self._cfg.iterkeys(): missing = [] for option, value in self._cfg[section].iteritems(): - if (value.default is None - and not RawConfigParser.has_option(self, section, option)): - missing.append(option) - errors = True + if (value.default is None and + not RawConfigParser.has_option(self, section, option)): + missing.append(option) + errors = True if len(missing): self.__missing[section] = missing return not errors - diff -r 18757fd45e60 -r 38b9a9859749 VirtualMailManager/Handler.py --- a/VirtualMailManager/Handler.py Fri Feb 05 20:16:44 2010 +0000 +++ b/VirtualMailManager/Handler.py Sat Feb 06 02:11:55 2010 +0000 @@ -80,12 +80,12 @@ self.__findCfgFile() fstat = os.stat(self.__cfgFileName) 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 VMMPermException(_( - u'fix permissions (%(perms)s) for “%(file)s”\n\ + if fmode % 100 and fstat.st_uid != fstat.st_gid or \ + fmode % 10 and fstat.st_uid == fstat.st_gid: + raise VMMPermException(_( + u'fix permissions (%(perms)s) for “%(file)s”\n\ `chmod 0600 %(file)s` would be great.') % {'file': - self.__cfgFileName, 'perms': fmode}, ERR.CONF_WRONGPERM) + self.__cfgFileName, 'perms': fmode}, ERR.CONF_WRONGPERM) else: return True @@ -154,14 +154,14 @@ def aliasExists(dbh, address): sql = "SELECT DISTINCT gid FROM alias WHERE gid = (SELECT gid FROM\ - domain_name WHERE domainname = '%s') AND address = '%s'" %\ + domain_name WHERE domainname = '%s') AND address = '%s'" % (address._domainname, address._localpart) return Handler._exists(dbh, sql) aliasExists = staticmethod(aliasExists) def relocatedExists(dbh, address): sql = "SELECT gid FROM relocated WHERE gid = (SELECT gid FROM\ - domain_name WHERE domainname = '%s') AND address = '%s'" %\ + domain_name WHERE domainname = '%s') AND address = '%s'" % (address._domainname, address._localpart) return Handler._exists(dbh, sql) relocatedExists = staticmethod(relocatedExists) @@ -404,7 +404,7 @@ section -- the section to configure (default None): """ if section is None: - self.__Cfg.configure(self.__Cfg.getsections()) + self.__Cfg.configure(self.__Cfg.sections()) elif self.__Cfg.has_section(section): self.__Cfg.configure([section]) else: @@ -545,12 +545,11 @@ alias = self.__getAlias(aliasaddress, targetaddress) alias.save(long(self._postconf.read('virtual_alias_expansion_limit'))) gid = self.__getDomain(alias._dest._domainname).getID() - if gid > 0 and not Handler.accountExists(self.__dbh, - alias._dest) and not Handler.aliasExists(self.__dbh, - alias._dest): + if gid > 0 and (not Handler.accountExists(self.__dbh, alias._dest) and + not Handler.aliasExists(self.__dbh, alias._dest)): self.__warnings.append( - _(u"The destination account/alias “%s” doesn't exist.")%\ - alias._dest) + _(u"The destination account/alias “%s” doesn't exist.") % + alias._dest) def userDelete(self, emailaddress, force=None): if force not in [None, 'delalias']: diff -r 18757fd45e60 -r 38b9a9859749 VirtualMailManager/__init__.py --- a/VirtualMailManager/__init__.py Fri Feb 05 20:16:44 2010 +0000 +++ b/VirtualMailManager/__init__.py Sat Feb 06 02:11:55 2010 +0000 @@ -76,7 +76,7 @@ raise VMMException(_(u'“%s” is not a file') % get_unicode(binary), NO_SUCH_BINARY) if not os.access(binary, os.X_OK): - raise VMMException(_(u'File is not executable: “%s”') % \ + raise VMMException(_(u'File is not executable: “%s”') % get_unicode(binary), NOT_EXECUTABLE) return binary diff -r 18757fd45e60 -r 38b9a9859749 VirtualMailManager/cli/CliConfig.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/VirtualMailManager/cli/CliConfig.py Sat Feb 06 02:11:55 2010 +0000 @@ -0,0 +1,82 @@ +# -*- coding: UTF-8 -*- +# Copyright (c) 2010, Pascal Volk +# See COPYING for distribution information. + +""" + VirtualMailManager.cli.CliConfig + + Adds some interactive stuff to the Config class. +""" + +from VirtualMailManager import ENCODING +from VirtualMailManager.Config import Config +from VirtualMailManager.cli import w_std +from VirtualMailManager.constants.ERROR import VMM_TOO_MANY_FAILURES + +class CliConfig(Config): + """Adds the interactive ``configure`` method to the `Config` class |
|
From: <nev...@us...> - 2010-02-05 20:17:02
|
details: http://hg.localdomain.org/vmm/rev/18757fd45e60 changeset: 186:18757fd45e60 user: Pascal Volk date: Fri Feb 05 20:16:44 2010 +0000 description: moved VMM/cli/handler to VMM/Handler diffstat: VirtualMailManager/Handler.py | 655 ++++++++++++++++++++++++++++++++++++++ VirtualMailManager/cli/handler.py | 655 -------------------------------------- 2 files changed, 655 insertions(+), 655 deletions(-) diffs (truncated from 1318 to 300 lines): diff -r 6e1ef32fbd82 -r 18757fd45e60 VirtualMailManager/Handler.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/VirtualMailManager/Handler.py Fri Feb 05 20:16:44 2010 +0000 @@ -0,0 +1,655 @@ +# -*- coding: UTF-8 -*- +# Copyright (c) 2007 - 2010, Pascal Volk +# See COPYING for distribution information. + +""" + VirtualMailManager.Handler + + A wrapper class. It wraps round all other classes and does some + dependencies checks. + + Additionally it communicates with the PostgreSQL database, creates + or deletes directories of domains or users. +""" + +import os +import re + +from shutil import rmtree +from subprocess import Popen, PIPE + +from pyPgSQL import PgSQL # python-pgsql - http://pypgsql.sourceforge.net + +import VirtualMailManager.constants.ERROR as ERR +from VirtualMailManager import ENCODING, ace2idna, exec_ok, read_pass +from VirtualMailManager.Account import Account +from VirtualMailManager.Alias import Alias +from VirtualMailManager.AliasDomain import AliasDomain +from VirtualMailManager.Config import Config as Cfg +from VirtualMailManager.Domain import Domain +from VirtualMailManager.EmailAddress import EmailAddress +from VirtualMailManager.Exceptions import * +from VirtualMailManager.Relocated import Relocated +from VirtualMailManager.ext.Postconf import Postconf + +SALTCHARS = './0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' +RE_DOMAIN_SRCH = """^[a-z0-9-\.]+$""" +RE_LOCALPART = """[^\w!#$%&'\*\+-\.\/=?^_`{\|}~]""" +RE_MBOX_NAMES = """^[\x20-\x25\x27-\x7E]*$""" + +class Handler(object): + """Wrapper class to simplify the access on all the stuff from + VirtualMailManager""" + # TODO: accept a LazyConfig object as argument + __slots__ = ('__Cfg', '__cfgFileName', '__dbh', '__scheme', '__warnings', + '_postconf') + def __init__(self): + """Creates a new Handler instance. + Throws a VMMNotRootException if your uid is greater 0. + """ + self.__cfgFileName = '' + self.__warnings = [] + self.__Cfg = None + self.__dbh = None + + if os.geteuid(): + raise VMMNotRootException(_(u"You are not root.\n\tGood bye!\n"), + ERR.CONF_NOPERM) + if self.__chkCfgFile(): + self.__Cfg = Cfg(self.__cfgFileName) + self.__Cfg.load() + if not os.sys.argv[1] in ('cf','configure','h','help','v','version'): + self.__Cfg.check() + self.__chkenv() + self.__scheme = self.__Cfg.dget('misc.password_scheme') + self._postconf = Postconf(self.__Cfg.dget('bin.postconf')) + + def __findCfgFile(self): + for path in ['/root', '/usr/local/etc', '/etc']: + tmp = os.path.join(path, 'vmm.cfg') + if os.path.isfile(tmp): + self.__cfgFileName = tmp + break + if not len(self.__cfgFileName): + raise VMMException( + _(u"No “vmm.cfg” found in: /root:/usr/local/etc:/etc"), + ERR.CONF_NOFILE) + + def __chkCfgFile(self): + """Checks the configuration file, returns bool""" + self.__findCfgFile() + fstat = os.stat(self.__cfgFileName) + 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 VMMPermException(_( + u'fix permissions (%(perms)s) for “%(file)s”\n\ +`chmod 0600 %(file)s` would be great.') % {'file': + self.__cfgFileName, 'perms': fmode}, ERR.CONF_WRONGPERM) + else: + return True + + def __chkenv(self): + """""" + 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, self.__Cfg.dget('misc.gid_mail')) + os.umask(old_umask) + elif not os.path.isdir(basedir): + raise VMMException(_(u'“%s” is not a directory.\n\ +(vmm.cfg: section "misc", option "base_directory")') % + basedir, ERR.NO_SUCH_DIRECTORY) + for opt, val in self.__Cfg.items('bin'): + try: + exec_ok(val) + except VMMException, e: + code = e.code() + if code is ERR.NO_SUCH_BINARY: + raise VMMException(_(u'“%(binary)s” doesn\'t exist.\n\ +(vmm.cfg: section "bin", option "%(option)s")') %{'binary': val,'option': opt}, + ERR.NO_SUCH_BINARY) + elif code is ERR.NOT_EXECUTABLE: + raise VMMException(_(u'“%(binary)s” is not executable.\n\ +(vmm.cfg: section "bin", option "%(option)s")') %{'binary': val,'option': opt}, + ERR.NOT_EXECUTABLE) + else: + raise + + def __dbConnect(self): + """Creates a pyPgSQL.PgSQL.connection instance.""" + if self.__dbh is None or (isinstance(self.__dbh, PgSQL.Connection) and + 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'), + client_encoding='utf8', unicode_results=True) + dbc = self.__dbh.cursor() + dbc.execute("SET NAMES 'UTF8'") + dbc.close() + except PgSQL.libpq.DatabaseError, e: + raise VMMException(str(e), ERR.DATABASE_ERROR) + + def _exists(dbh, query): + dbc = dbh.cursor() + dbc.execute(query) + gid = dbc.fetchone() + dbc.close() + if gid is None: + return False + else: + return True + _exists = staticmethod(_exists) + + def accountExists(dbh, address): + sql = "SELECT gid FROM users WHERE gid = (SELECT gid FROM domain_name\ + WHERE domainname = '%s') AND local_part = '%s'" % (address._domainname, + address._localpart) + return Handler._exists(dbh, sql) + accountExists = staticmethod(accountExists) + + def aliasExists(dbh, address): + sql = "SELECT DISTINCT gid FROM alias WHERE gid = (SELECT gid FROM\ + domain_name WHERE domainname = '%s') AND address = '%s'" %\ + (address._domainname, address._localpart) + return Handler._exists(dbh, sql) + aliasExists = staticmethod(aliasExists) + + def relocatedExists(dbh, address): + sql = "SELECT gid FROM relocated WHERE gid = (SELECT gid FROM\ + domain_name WHERE domainname = '%s') AND address = '%s'" %\ + (address._domainname, address._localpart) + return Handler._exists(dbh, sql) + relocatedExists = staticmethod(relocatedExists) + + + def __getAccount(self, address, password=None): + self.__dbConnect() + address = EmailAddress(address) + if not password is None: + password = self.__pwhash(password) + return Account(self.__dbh, address, password) + + def __getAlias(self, address, destination=None): + self.__dbConnect() + address = EmailAddress(address) + if destination is not None: + destination = EmailAddress(destination) + return Alias(self.__dbh, address, destination) + + def __getRelocated(self,address, destination=None): + self.__dbConnect() + address = EmailAddress(address) + if destination is not None: + destination = EmailAddress(destination) + return Relocated(self.__dbh, address, destination) + + def __getDomain(self, domainname, transport=None): + if transport is None: + transport = self.__Cfg.dget('misc.transport') + self.__dbConnect() + return Domain(self.__dbh, domainname, + self.__Cfg.dget('misc.base_directory'), transport) + + def __getDiskUsage(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): + return Popen([self.__Cfg.dget('bin.du'), "-hs", directory], + stdout=PIPE).communicate()[0].split('\t')[0] + else: + return 0 + + def __isdir(self, directory): + isdir = os.path.isdir(directory) + if not isdir: + 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): + 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, + self.__Cfg.dget('misc.gid_mail')) + os.chdir(domdirdirs[0]) + os.umask(0007) + self.__makedir(domdirdirs[1], self.__Cfg.dget('domain.directory_mode'), + 0, gid) + os.chdir(oldpwd) + + def __subscribeFL(self, folderlist, uid, gid): + fname = os.path.join(self.__Cfg.dget('maildir.name'), 'subscriptions') + sf = file(fname, 'w') + for f in folderlist: + sf.write(f+'\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 + """ + os.umask(0007) + oldpwd = os.getcwd() + os.chdir(domdir) + + maildir = self.__Cfg.dget('maildir.name') + folders = [maildir] + for folder in self.__Cfg.dget('maildir.folders').split(':'): + folder = folder.strip() + if len(folder) and not folder.count('..')\ + and re.match(RE_MBOX_NAMES, folder): + folders.append('%s/.%s' % (maildir, 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.__subscribeFL([f.replace(maildir+'/.', '') for f in folders[1:]], + uid, gid) + os.chdir(oldpwd) + + def __userDirDelete(self, domdir, uid, gid): + if uid > 0 and gid > 0: + userdir = '%s' % uid + if userdir.count('..') or domdir.count('..'): + raise VMMException(_(u'Found ".." in home directory path.'), + ERR.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 VMMException( + _(u'Detected owner/group mismatch in home directory.'), |
|
From: <nev...@us...> - 2010-02-05 20:13:56
|
details: http://hg.localdomain.org/vmm/rev/6e1ef32fbd82 changeset: 185:6e1ef32fbd82 user: Pascal Volk date: Fri Feb 05 20:13:32 2010 +0000 description: VMM/*: Moved some methods from classes to modules __init__. - Adjusted many import statements. - Small adjustments and whitespace cosmetics in Config.py diffstat: VirtualMailManager/Account.py | 12 +- VirtualMailManager/Alias.py | 8 +- VirtualMailManager/AliasDomain.py | 8 +- VirtualMailManager/Config.py | 80 ++++++------------- VirtualMailManager/Domain.py | 36 ++++---- VirtualMailManager/EmailAddress.py | 18 ++-- VirtualMailManager/MailLocation.py | 6 +- VirtualMailManager/Relocated.py | 8 +- VirtualMailManager/Transport.py | 4 +- VirtualMailManager/__init__.py | 109 ++++++++++++++++++++------- VirtualMailManager/cli/handler.py | 146 ++++++++++++------------------------ VirtualMailManager/ext/Postconf.py | 3 +- vmm | 10 +- 13 files changed, 218 insertions(+), 230 deletions(-) diffs (truncated from 898 to 300 lines): diff -r d0425225ce52 -r 6e1ef32fbd82 VirtualMailManager/Account.py --- a/VirtualMailManager/Account.py Thu Feb 04 19:08:01 2010 +0000 +++ b/VirtualMailManager/Account.py Fri Feb 05 20:13:32 2010 +0000 @@ -4,12 +4,12 @@ """Virtual Mail Manager's Account class to manage e-mail accounts.""" -from __main__ import ERR -from Exceptions import VMMAccountException as AccE -from Domain import Domain -from Transport import Transport -from MailLocation import MailLocation -from EmailAddress import EmailAddress +import VirtualMailManager.constants.ERROR as ERR +from VirtualMailManager.Domain import Domain +from VirtualMailManager.EmailAddress import EmailAddress +from VirtualMailManager.Exceptions import VMMAccountException as AccE +from VirtualMailManager.MailLocation import MailLocation +from VirtualMailManager.Transport import Transport import VirtualMailManager as VMM class Account(object): diff -r d0425225ce52 -r 6e1ef32fbd82 VirtualMailManager/Alias.py --- a/VirtualMailManager/Alias.py Thu Feb 04 19:08:01 2010 +0000 +++ b/VirtualMailManager/Alias.py Fri Feb 05 20:13:32 2010 +0000 @@ -4,10 +4,10 @@ """Virtual Mail Manager's Alias class to manage e-mail aliases.""" -from __main__ import ERR -from Exceptions import VMMAliasException as VMMAE -from Domain import Domain -from EmailAddress import EmailAddress +import VirtualMailManager.constants.ERROR as ERR +from VirtualMailManager.Domain import Domain +from VirtualMailManager.EmailAddress import EmailAddress +from VirtualMailManager.Exceptions import VMMAliasException as VMMAE import VirtualMailManager as VMM class Alias(object): diff -r d0425225ce52 -r 6e1ef32fbd82 VirtualMailManager/AliasDomain.py --- a/VirtualMailManager/AliasDomain.py Thu Feb 04 19:08:01 2010 +0000 +++ b/VirtualMailManager/AliasDomain.py Fri Feb 05 20:13:32 2010 +0000 @@ -4,16 +4,16 @@ """Virtual Mail Manager's AliasDomain class to manage alias domains.""" -from __main__ import ERR -from Exceptions import VMMAliasDomainException as VADE -import VirtualMailManager as VMM +import VirtualMailManager.constants.ERROR as ERR +from VirtualMailManager import chk_domainname +from VirtualMailManager.Exceptions import VMMAliasDomainException as VADE class AliasDomain(object): """Class to manage e-mail alias domains.""" __slots__ = ('__gid', '__name', '_domain', '_dbh') def __init__(self, dbh, domainname, targetDomain=None): self._dbh = dbh - self.__name = VMM.VirtualMailManager.chkDomainname(domainname) + self.__name = chk_domainname(domainname) self.__gid = 0 self._domain = targetDomain self._exists() diff -r d0425225ce52 -r 6e1ef32fbd82 VirtualMailManager/Config.py --- a/VirtualMailManager/Config.py Thu Feb 04 19:08:01 2010 +0000 +++ b/VirtualMailManager/Config.py Fri Feb 05 20:13:32 2010 +0000 @@ -36,10 +36,13 @@ from shutil import copy2 from ConfigParser import (Error, MissingSectionHeaderError, NoOptionError, NoSectionError, ParsingError, RawConfigParser) -from cStringIO import StringIO +from cStringIO import StringIO# TODO: move interactive stff to cli -from __main__ import os, ENCODING, ERR, get_unicode, w_std -from Exceptions import VMMConfigException +import VirtualMailManager.constants.ERROR as ERR + +from VirtualMailManager import ENCODING, exec_ok, get_unicode, is_dir +from VirtualMailManager.cli import w_std# move to cli +from VirtualMailManager.Exceptions import VMMConfigException class BadOptionError(Error): @@ -62,9 +65,9 @@ class LazyConfig(RawConfigParser): """The **lazy** derivate of the `RawConfigParser`. - + There are two additional getters: - + `LazyConfig.pget()` The polymorphic getter, which returns a option's value with the appropriate type. @@ -127,7 +130,7 @@ * `BadOptionError` * `NoSectionError` * `NoOptionError` - """ + """ sect_opt = section_option.lower().split('.') if len(sect_opt) != 2:# do we need a regexp to check the format? raise BadOptionError( @@ -158,13 +161,13 @@ def dget(self, option): """Returns the value of the `option`. - + If the option could not be found in the configuration file, the configured default value, from ``LazyConfig._cfg`` will be returned. - + Arguments: - + `option` : string the configuration option in the form "``section``\ **.**\ ``option``" @@ -188,7 +191,7 @@ def set(self, option, value): """Set the value of an option. - + Throws a ``ValueError`` if `value` couldn't be converted to ``LazyConfigOption.cls``""" section, option = self.__get_section_option(option) @@ -202,7 +205,7 @@ def has_section(self, section): """Checks if ``section`` is a known configuration section.""" - return section.lower() in self._cfg + return section.lower() in self._cfg def has_option(self, option): """Checks if the option (section\ **.**\ option) is a known @@ -214,7 +217,6 @@ return False - class LazyConfigOption(object): """A simple container class for configuration settings. @@ -266,7 +268,7 @@ """Creates a new Config instance Arguments: - + ``filename`` path to the configuration file """ @@ -290,11 +292,9 @@ 'smtp' : LCO(bool_t, True, self.get_boolean), }, 'bin': { - 'dovecotpw': LCO(str, '/usr/sbin/dovecotpw', self.get, - self.exec_ok), - 'du': LCO(str, '/usr/bin/du', self.get, self.exec_ok), - 'postconf': LCO(str, '/usr/sbin/postconf', self.get, - self.exec_ok), + 'dovecotpw': LCO(str, '/usr/sbin/dovecotpw', self.get, exec_ok), + 'du': LCO(str, '/usr/bin/du', self.get, exec_ok), + 'postconf': LCO(str, '/usr/sbin/postconf', self.get, exec_ok), }, 'database': { 'host': LCO(str, 'localhost', self.get), @@ -313,7 +313,7 @@ 'name': LCO(str, 'Maildir', self.get), }, 'misc': { - 'base_directory': LCO(str, '/srv/mail', self.get, self.is_dir), + 'base_directory': LCO(str, '/srv/mail', self.get, is_dir), 'dovecot_version': LCO(int, 12, self.getint), 'gid_mail': LCO(int, 8, self.getint), 'password_scheme': LCO(str, 'CRAM-MD5', self.get, @@ -341,6 +341,8 @@ Raises a VMMConfigException if the check fails. """ + # TODO: There are only two settings w/o defaults. + # So there is no need for cStringIO if not self.__chkCfg(): errmsg = StringIO() errmsg.write(_(u'Missing options, which have no default value.\n')) @@ -356,36 +358,10 @@ """Returns an iterator object for all configuration sections.""" return self._cfg.iterkeys() - def is_dir(self, path): - """Checks if ``path`` is a directory. - - Throws a `ConfigValueError` if ``path`` is not a directory. - """ - path = self.__expand_path(path) - if not os.path.isdir(path): - raise ConfigValueError(_(u'“%s” is not a directory') % \ - get_unicode(path)) - return path - - def exec_ok(self, binary): - """Checks if the ``binary`` exists and if it is executable. - - Throws a `ConfigValueError` if the ``binary`` isn't a file or is - not executable. - """ - binary = self.__expand_path(binary) - if not os.path.isfile(binary): - raise ConfigValueError(_(u'“%s” is not a file') % \ - get_unicode(binary)) - if not os.access(binary, os.X_OK): - raise ConfigValueError(_(u'File is not executable: “%s”') % \ - get_unicode(binary)) - return binary - def known_scheme(self, scheme): """Converts ``scheme`` to upper case and checks if is known by Dovecot (listed in VirtualMailManager.SCHEMES). - + Throws a `ConfigValueError` if the scheme is not listed in VirtualMailManager.SCHEMES. """ @@ -404,6 +380,8 @@ Arguments: sections -- list of strings with section names """ + # TODO: Derivate CliConfig from Config an move the interactive + # stuff to CliConfig input_fmt = _(u'Enter new value for option %(option)s \ [%(current_value)s]: ') failures = 0 @@ -435,6 +413,7 @@ def __saveChanges(self): """Writes changes to the configuration file.""" + # TODO: Move interactive stuff to CliConfig copy2(self.__cfgFileName, self.__cfgFileName+'.bak') self.__cfgFile = open(self.__cfgFileName, 'w') self.write(self.__cfgFile) @@ -442,7 +421,7 @@ def __chkCfg(self): """Checks all section's options for settings w/o default values. - + Returns ``True`` if everything is fine, else ``False``.""" errors = False for section in self._cfg.iterkeys(): @@ -456,10 +435,3 @@ self.__missing[section] = missing return not errors - def __expand_path(self, path): - """Expands paths, starting with ``.`` or ``~``, to an absolute path.""" - if path.startswith('.'): - return os.path.abspath(path) - if path.startswith('~'): - return os.path.expanduser(path) - return path diff -r d0425225ce52 -r 6e1ef32fbd82 VirtualMailManager/Domain.py --- a/VirtualMailManager/Domain.py Thu Feb 04 19:08:01 2010 +0000 +++ b/VirtualMailManager/Domain.py Fri Feb 05 20:13:32 2010 +0000 @@ -6,13 +6,17 @@ from random import choice -from __main__ import ERR -from Exceptions import VMMDomainException as VMMDE -import VirtualMailManager as VMM -from Transport import Transport +from VirtualMailManager import chk_domainname +from VirtualMailManager.constants.ERROR import \ + ACCOUNT_AND_ALIAS_PRESENT, ACCOUNT_PRESENT, ALIAS_PRESENT, \ + DOMAIN_ALIAS_EXISTS, DOMAIN_EXISTS, NO_SUCH_DOMAIN +from VirtualMailManager.Exceptions import VMMDomainException as VMMDE +from VirtualMailManager.Transport import Transport + MAILDIR_CHARS = '0123456789abcdefghijklmnopqrstuvwxyz' + class Domain(object): """Class to manage e-mail domains.""" __slots__ = ('_basedir','_domaindir','_id','_name','_transport','_dbh') @@ -25,7 +29,7 @@ transport -- default vmm.cfg/misc/transport (str) """ self._dbh = dbh - self._name = VMM.VirtualMailManager.chkDomainname(domainname) + self._name = chk_domainname(domainname) self._basedir = basedir if transport is not None: self._transport = Transport(self._dbh, transport=transport) @@ -34,8 +38,8 @@ |
|
From: <nev...@us...> - 2010-02-04 19:14:12
|
details: http://hg.localdomain.org/vmm/rev/d0425225ce52 changeset: 184:d0425225ce52 user: Pascal Volk date: Thu Feb 04 19:08:01 2010 +0000 description: moved VMM/VMM to VMM/cli/handler diffstat: VirtualMailManager/VirtualMailManager.py | 699 ------------------------------- VirtualMailManager/cli/handler.py | 699 +++++++++++++++++++++++++++++++ 2 files changed, 699 insertions(+), 699 deletions(-) diffs (truncated from 1406 to 300 lines): diff -r eb4c73d9d0a4 -r d0425225ce52 VirtualMailManager/VirtualMailManager.py --- a/VirtualMailManager/VirtualMailManager.py Tue Feb 02 02:28:28 2010 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,699 +0,0 @@ -# -*- coding: UTF-8 -*- -# Copyright (c) 2007 - 2010, Pascal Volk -# See COPYING for distribution information. - -"""The main class for vmm.""" - - -from encodings.idna import ToASCII, ToUnicode -from getpass import getpass -from shutil import rmtree -from subprocess import Popen, PIPE - -from pyPgSQL import PgSQL # python-pgsql - http://pypgsql.sourceforge.net - -from __main__ import os, re, ENCODING, ERR, w_std -from ext.Postconf import Postconf -from Account import Account -from Alias import Alias -from AliasDomain import AliasDomain -from Config import Config as Cfg -from Domain import Domain -from EmailAddress import EmailAddress -from Exceptions import * -from Relocated import Relocated - -SALTCHARS = './0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' -RE_ASCII_CHARS = """^[\x20-\x7E]*$""" -RE_DOMAIN = """^(?:[a-z0-9-]{1,63}\.){1,}[a-z]{2,6}$""" -RE_DOMAIN_SRCH = """^[a-z0-9-\.]+$""" -RE_LOCALPART = """[^\w!#$%&'\*\+-\.\/=?^_`{\|}~]""" -RE_MBOX_NAMES = """^[\x20-\x25\x27-\x7E]*$""" - -class VirtualMailManager(object): - """The main class for vmm""" - __slots__ = ('__Cfg', '__cfgFileName', '__dbh', '__scheme', '__warnings', - '_postconf') - def __init__(self): - """Creates a new VirtualMailManager instance. - Throws a VMMNotRootException if your uid is greater 0. - """ - self.__cfgFileName = '' - self.__warnings = [] - self.__Cfg = None - self.__dbh = None - - if os.geteuid(): - raise VMMNotRootException(_(u"You are not root.\n\tGood bye!\n"), - ERR.CONF_NOPERM) - if self.__chkCfgFile(): - self.__Cfg = Cfg(self.__cfgFileName) - self.__Cfg.load() - if not os.sys.argv[1] in ('cf','configure','h','help','v','version'): - self.__Cfg.check() - self.__chkenv() - self.__scheme = self.__Cfg.dget('misc.password_scheme') - self._postconf = Postconf(self.__Cfg.dget('bin.postconf')) - - def __findCfgFile(self): - for path in ['/root', '/usr/local/etc', '/etc']: - tmp = os.path.join(path, 'vmm.cfg') - if os.path.isfile(tmp): - self.__cfgFileName = tmp - break - if not len(self.__cfgFileName): - raise VMMException( - _(u"No “vmm.cfg” found in: /root:/usr/local/etc:/etc"), - ERR.CONF_NOFILE) - - def __chkCfgFile(self): - """Checks the configuration file, returns bool""" - self.__findCfgFile() - fstat = os.stat(self.__cfgFileName) - 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 VMMPermException(_( - u'fix permissions (%(perms)s) for “%(file)s”\n\ -`chmod 0600 %(file)s` would be great.') % {'file': - self.__cfgFileName, 'perms': fmode}, ERR.CONF_WRONGPERM) - else: - return True - - def __chkenv(self): - """""" - 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, self.__Cfg.dget('misc.gid_mail')) - os.umask(old_umask) - elif not os.path.isdir(basedir): - raise VMMException(_(u'“%s” is not a directory.\n\ -(vmm.cfg: section "misc", option "base_directory")') % - basedir, ERR.NO_SUCH_DIRECTORY) - for opt, val in self.__Cfg.items('bin'): - if not os.path.exists(val): - raise VMMException(_(u'“%(binary)s” doesn\'t exist.\n\ -(vmm.cfg: section "bin", option "%(option)s")') %{'binary': val,'option': opt}, - ERR.NO_SUCH_BINARY) - elif not os.access(val, os.X_OK): - raise VMMException(_(u'“%(binary)s” is not executable.\n\ -(vmm.cfg: section "bin", option "%(option)s")') %{'binary': val,'option': opt}, - ERR.NOT_EXECUTABLE) - - def __dbConnect(self): - """Creates a pyPgSQL.PgSQL.connection instance.""" - if self.__dbh is None or 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'), - client_encoding='utf8', unicode_results=True) - dbc = self.__dbh.cursor() - dbc.execute("SET NAMES 'UTF8'") - dbc.close() - except PgSQL.libpq.DatabaseError, e: - raise VMMException(str(e), ERR.DATABASE_ERROR) - - def idn2ascii(domainname): - """Converts an idn domainname in punycode. - - Arguments: - domainname -- the domainname to convert (unicode) - """ - return '.'.join([ToASCII(lbl) for lbl in domainname.split('.') if lbl]) - idn2ascii = staticmethod(idn2ascii) - - def ace2idna(domainname): - """Convertis a domainname from ACE according to IDNA - - Arguments: - domainname -- the domainname to convert (str) - """ - return u'.'.join([ToUnicode(lbl) for lbl in domainname.split('.')\ - if lbl]) - ace2idna = staticmethod(ace2idna) - - def chkDomainname(domainname): - """Validates the domain name of an e-mail address. - - Keyword arguments: - domainname -- the domain name that should be validated - """ - if not re.match(RE_ASCII_CHARS, domainname): - domainname = VirtualMailManager.idn2ascii(domainname) - if len(domainname) > 255: - raise VMMException(_(u'The domain name is too long.'), - ERR.DOMAIN_TOO_LONG) - if not re.match(RE_DOMAIN, domainname): - raise VMMException(_(u'The domain name “%s” is invalid.') %\ - domainname, ERR.DOMAIN_INVALID) - return domainname - chkDomainname = staticmethod(chkDomainname) - - def _exists(dbh, query): - dbc = dbh.cursor() - dbc.execute(query) - gid = dbc.fetchone() - dbc.close() - if gid is None: - return False - else: - return True - _exists = staticmethod(_exists) - - def accountExists(dbh, address): - sql = "SELECT gid FROM users WHERE gid = (SELECT gid FROM domain_name\ - WHERE domainname = '%s') AND local_part = '%s'" % (address._domainname, - address._localpart) - return VirtualMailManager._exists(dbh, sql) - accountExists = staticmethod(accountExists) - - def aliasExists(dbh, address): - sql = "SELECT DISTINCT gid FROM alias WHERE gid = (SELECT gid FROM\ - domain_name WHERE domainname = '%s') AND address = '%s'" %\ - (address._domainname, address._localpart) - return VirtualMailManager._exists(dbh, sql) - aliasExists = staticmethod(aliasExists) - - def relocatedExists(dbh, address): - sql = "SELECT gid FROM relocated WHERE gid = (SELECT gid FROM\ - domain_name WHERE domainname = '%s') AND address = '%s'" %\ - (address._domainname, address._localpart) - return VirtualMailManager._exists(dbh, sql) - relocatedExists = staticmethod(relocatedExists) - - def _readpass(self): - # TP: Please preserve the trailing space. - readp_msg0 = _(u'Enter new password: ').encode(ENCODING, 'replace') - # TP: Please preserve the trailing space. - readp_msg1 = _(u'Retype new password: ').encode(ENCODING, 'replace') - mismatched = True - flrs = 0 - while mismatched: - if flrs > 2: - raise VMMException(_(u'Too many failures - try again later.'), - ERR.VMM_TOO_MANY_FAILURES) - clear0 = getpass(prompt=readp_msg0) - clear1 = getpass(prompt=readp_msg1) - if clear0 != clear1: - flrs += 1 - w_std(_(u'Sorry, passwords do not match')) - continue - if len(clear0) < 1: - flrs += 1 - w_std(_(u'Sorry, empty passwords are not permitted')) - continue - mismatched = False - return clear0 - - def __getAccount(self, address, password=None): - self.__dbConnect() - address = EmailAddress(address) - if not password is None: - password = self.__pwhash(password) - return Account(self.__dbh, address, password) - - def __getAlias(self, address, destination=None): - self.__dbConnect() - address = EmailAddress(address) - if destination is not None: - destination = EmailAddress(destination) - return Alias(self.__dbh, address, destination) - - def __getRelocated(self,address, destination=None): - self.__dbConnect() - address = EmailAddress(address) - if destination is not None: - destination = EmailAddress(destination) - return Relocated(self.__dbh, address, destination) - - def __getDomain(self, domainname, transport=None): - if transport is None: - transport = self.__Cfg.dget('misc.transport') - self.__dbConnect() - return Domain(self.__dbh, domainname, - self.__Cfg.dget('misc.base_directory'), transport) - - def __getDiskUsage(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): - return Popen([self.__Cfg.dget('bin.du'), "-hs", directory], - stdout=PIPE).communicate()[0].split('\t')[0] - else: - return 0 - - def __isdir(self, directory): - isdir = os.path.isdir(directory) - if not isdir: - 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): - 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, - self.__Cfg.dget('misc.gid_mail')) - os.chdir(domdirdirs[0]) - os.umask(0007) - self.__makedir(domdirdirs[1], self.__Cfg.dget('domain.directory_mode'), - 0, gid) - os.chdir(oldpwd) - - def __subscribeFL(self, folderlist, uid, gid): - fname = os.path.join(self.__Cfg.dget('maildir.name'), 'subscriptions') - sf = file(fname, 'w') - for f in folderlist: - sf.write(f+'\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. |
|
From: <nev...@us...> - 2010-02-02 02:29:04
|
details: http://hg.localdomain.org/vmm/rev/eb4c73d9d0a4 changeset: 183:eb4c73d9d0a4 user: Pascal Volk date: Tue Feb 02 02:28:28 2010 +0000 description: vmm: reworked subcommand/arguments mapping. diffstat: vmm | 121 +++++++++++++++++++++++++++++-------------------------------------- 1 files changed, 53 insertions(+), 68 deletions(-) diffs (135 lines): diff -r 84811fcc3c69 -r eb4c73d9d0a4 vmm --- a/vmm Mon Feb 01 20:53:39 2010 +0000 +++ b/vmm Tue Feb 02 02:28:28 2010 +0000 @@ -463,7 +463,27 @@ os.sys.version.split()[0], _(u'on'), os.uname()[0], __prog__, _(u'is free software and comes with ABSOLUTELY NO WARRANTY.'))) -#def main(): +def main(): + subcommand = os.sys.argv[1] + known_subcommand = False + try: + for s, l, f in subcmd_func.__iter__(): + if subcommand in (s, l): + known_subcommand = True + f() + if not known_subcommand: + usage(EXIT.UNKNOWN_COMMAND, _(u'Unknown subcommand: “%s”')% argv[1]) + show_warnings() + except (EOFError, KeyboardInterrupt): + # TP: We have to cry, because root has killed/interrupted vmm + # with Ctrl+C or Ctrl+D. + w_err(EXIT.USER_INTERRUPT, _(u'\nOuch!\n')) + except (VMME.VMMConfigException, VMME.VMMException), e: + if e.code() != ERR.DATABASE_ERROR: + w_err(e.code(), _(u'Error: %s') % e.msg()) + else: + w_err(e.code(), unicode(e.msg(), ENCODING, 'replace')) + if __name__ == '__main__': __prog__ = os.path.basename(os.sys.argv[0]) gettext.install(__prog__, '/usr/local/share/locale', unicode=1) @@ -475,70 +495,35 @@ usage(EXIT.MISSING_ARGS) vmm = get_vmm() - try: - if argv[1] in (u'cf', u'configure'): - configure() - elif argv[1] in (u'da', u'domainadd'): - domain_add() - elif argv[1] in (u'di', u'domaininfo'): - domain_info() - elif argv[1] in (u'dt', u'domaintransport'): - domain_transport() - elif argv[1] in (u'dd', u'domaindelete'): - domain_delete() - elif argv[1] in (u'ada', u'aliasdomainadd'): - alias_domain_add() - elif argv[1] in (u'adi', u'aliasdomaininfo'): - alias_domain_info() - elif argv[1] in (u'ads', u'aliasdomainswitch'): - alias_domain_switch() - elif argv[1] in (u'add', u'aliasdomaindelete'): - alias_domain_delete() - elif argv[1] in (u'ua', u'useradd'): - user_add() - elif argv[1] in (u'ui', u'userinfo'): - user_info() - elif argv[1] in (u'un', u'username'): - user_name() - elif argv[1] in (u'up', u'userpassword'): - user_password() - elif argv[1] in (u'ut', u'usertransport'): - user_transport() - elif argv[1] in (u'u0', u'userdisable'): - user_disable() - elif argv[1] in (u'u1', u'userenable'): - user_enable() - elif argv[1] in (u'ud', u'userdelete'): - user_delete() - elif argv[1] in (u'aa', u'aliasadd'): - alias_add() - elif argv[1] in (u'ai', u'aliasinfo'): - alias_info() - elif argv[1] in (u'ad', u'aliasdelete'): - alias_delete() - elif argv[1] in (u'ra', u'relocatedadd'): - relocated_add() - elif argv[1] in (u'ri', u'relocatedinfo'): - relocated_info() - elif argv[1] in (u'rd', u'relocateddelete'): - relocated_delete() - elif argv[1] in (u'gu', u'getuser'): - user_byID() - elif argv[1] in (u'ld', u'listdomains'): - domain_list() - elif argv[1] in (u'h', u'help'): - usage() - elif argv[1] in (u'v', u'version'): - show_version() - else: - usage(EXIT.UNKNOWN_COMMAND, _(u'Unknown subcommand: “%s”')% argv[1]) - show_warnings() - except (EOFError, KeyboardInterrupt): - # TP: We have to cry, because root has killed/interrupted vmm - # with Ctrl+C or Ctrl+D. - w_err(EXIT.USER_INTERRUPT, _(u'\nOuch!\n')) - except (VMME.VMMConfigException, VMME.VMMException), e: - if e.code() != ERR.DATABASE_ERROR: - w_err(e.code(), _(u'Error: %s') % e.msg()) - else: - w_err(e.code(), unicode(e.msg(), ENCODING, 'replace')) + + subcmd_func = ( + #short long function + ('da', 'domainadd', domain_add), + ('di', 'domaininfo', domain_info), + ('dt', 'domaintransport', domain_transport), + ('dd', 'domaindelete', domain_delete), + ('ada', 'aliasdomainadd', alias_domain_add), + ('adi', 'aliasdomaininfo', alias_domain_info), + ('ads', 'aliasdomainswitch', alias_domain_switch), + ('add', 'aliasdomaindelete', alias_domain_delete), + ('ua', 'useradd', user_add), + ('ui', 'userinfo', user_info), + ('un', 'username', user_name), + ('up', 'userpassword', user_password), + ('ut', 'usertransport', user_transport), + ('u0', 'userdisable', user_disable), + ('u1', 'userenable', user_enable), + ('ud', 'userdelete', user_delete), + ('aa', 'aliasadd', alias_add), + ('ai', 'aliasinfo', alias_info), + ('ad', 'aliasdelete', alias_delete), + ('ra', 'relocatedadd', relocated_add), + ('ri', 'relocatedinfo', relocated_info), + ('rd', 'relocateddelete', relocated_delete), + ('cf', 'configure', configure), + ('gu', 'getuser', user_byID), + ('ld', 'listdomains', domain_list), + ('h', 'help', usage), + ('v', 'version', show_version),) + + main() |
|
From: <nev...@us...> - 2010-02-01 20:54:06
|
details: http://hg.localdomain.org/vmm/rev/84811fcc3c69 changeset: 182:84811fcc3c69 user: Pascal Volk date: Mon Feb 01 20:53:39 2010 +0000 description: VMM/VMM: Allow version/help subcommands even with missing configuration options. diffstat: VirtualMailManager/VirtualMailManager.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff -r 866a6d679fce -r 84811fcc3c69 VirtualMailManager/VirtualMailManager.py --- a/VirtualMailManager/VirtualMailManager.py Mon Feb 01 19:57:42 2010 +0000 +++ b/VirtualMailManager/VirtualMailManager.py Mon Feb 01 20:53:39 2010 +0000 @@ -49,7 +49,7 @@ if self.__chkCfgFile(): self.__Cfg = Cfg(self.__cfgFileName) self.__Cfg.load() - if not os.sys.argv[1] in ['cf', 'configure']: + if not os.sys.argv[1] in ('cf','configure','h','help','v','version'): self.__Cfg.check() self.__chkenv() self.__scheme = self.__Cfg.dget('misc.password_scheme') |
|
From: <nev...@us...> - 2010-02-01 19:58:49
|
details: http://hg.localdomain.org/vmm/rev/866a6d679fce changeset: 181:866a6d679fce user: Pascal Volk date: Mon Feb 01 19:57:42 2010 +0000 description: update_config: do not add options w/ default values. remove config.done diffstat: update_config.py | 17 ++++++++++------- 1 files changed, 10 insertions(+), 7 deletions(-) diffs (60 lines): diff -r f8279c90e99c -r 866a6d679fce update_config.py --- a/update_config.py Mon Feb 01 18:46:17 2010 +0000 +++ b/update_config.py Mon Feb 01 19:57:42 2010 +0000 @@ -36,7 +36,7 @@ raise SystemExit(3) def get_cfg_parser(cf): - fh = file(cf, 'r') + fh = open(cf, 'r') cp = ConfigParser() cp.readfp(fh) fh.close() @@ -44,7 +44,7 @@ def update_cfg_file(cp, cf): copy2(cf, cf+'.bak.'+str(time())) - fh = file(cf, 'w') + fh = open(cf, 'w') cp.write(fh) fh.close() @@ -72,6 +72,9 @@ return cp.get(ss, so) def upd_052(cp): + global had_config + + had_config = cp.remove_section('config') add_sections(cp, ('domain', 'account')) if cp.has_section('domdir'): for src, dst in (('domdir.mode', 'domain.directory_mode'), @@ -90,23 +93,23 @@ ('misc.passwdscheme', 'misc.password_scheme'), ('misc.dovecotvers', 'misc.dovecot_version')): move_option(cp, src, dst) - for dst, val in (('account.random_password', 'false'), - ('account.password_length', '8'), - ('domain.auto_postmaster', 'true')): - add_option(cp, dst, val) # def main(): if __name__ == '__main__': sect_opt = [] + had_config = False cf = get_config_file() cp = get_cfg_parser(cf) update(cp) if len(sect_opt): + had_config = False update_cfg_file(cp, cf) sect_opt.sort() print 'Please have a look at your configuration: %s' %cf print 'This are your Renamed/New settings:' for s_o, st in sect_opt: print '%s %s = %s' % (st, s_o, get_option(cp, s_o)) + if had_config: + update_cfg_file(cp, cf) + print 'Removed section "config" with option "done" (obsolte)' print - |
|
From: <nev...@us...> - 2010-02-01 18:46:44
|
details: http://hg.localdomain.org/vmm/rev/f8279c90e99c changeset: 180:f8279c90e99c user: Pascal Volk date: Mon Feb 01 18:46:17 2010 +0000 description: VMM/Config: dropped option config.done diffstat: VirtualMailManager/Config.py | 10 ++-------- VirtualMailManager/VirtualMailManager.py | 3 +-- man/de/man5/vmm.cfg.5.rst | 27 +-------------------------- man/man5/vmm.cfg.5.rst | 25 +------------------------ vmm | 5 ++--- 5 files changed, 7 insertions(+), 63 deletions(-) diffs (181 lines): diff -r 3d09c657e9e5 -r f8279c90e99c VirtualMailManager/Config.py --- a/VirtualMailManager/Config.py Sat Jan 30 05:15:21 2010 +0000 +++ b/VirtualMailManager/Config.py Mon Feb 01 18:46:17 2010 +0000 @@ -320,7 +320,6 @@ self.known_scheme), 'transport': LCO(str, 'dovecot:', self.get), }, - 'config': {'done': LCO(bool_t, False, self.get_boolean)} } def load(self): @@ -354,8 +353,8 @@ raise VMMConfigException(errmsg.getvalue(), ERR.CONF_ERROR) def getsections(self): - """Returns a generator object for all configurable sections.""" - return (s for s in self._cfg.iterkeys() if s != 'config') + """Returns an iterator object for all configuration sections.""" + return self._cfg.iterkeys() def is_dir(self, path): """Checks if ``path`` is a directory. @@ -409,10 +408,6 @@ [%(current_value)s]: ') failures = 0 - # if config.done == false (default at 1st run), - # then set changes true - if not self.dget('config.done'): - self._modified = True w_std(_(u'Using configuration file: %s\n') % self.__cfgFileName) for s in sections: w_std(_(u'* Configuration section: “%s”') % s ) @@ -440,7 +435,6 @@ def __saveChanges(self): """Writes changes to the configuration file.""" - self.set('config.done', True) copy2(self.__cfgFileName, self.__cfgFileName+'.bak') self.__cfgFile = open(self.__cfgFileName, 'w') self.write(self.__cfgFile) diff -r 3d09c657e9e5 -r f8279c90e99c VirtualMailManager/VirtualMailManager.py --- a/VirtualMailManager/VirtualMailManager.py Sat Jan 30 05:15:21 2010 +0000 +++ b/VirtualMailManager/VirtualMailManager.py Mon Feb 01 18:46:17 2010 +0000 @@ -445,11 +445,10 @@ Keyword arguments: section -- the section to configure (default None): - 'database', 'maildir', 'bin' or 'misc' """ if section is None: self.__Cfg.configure(self.__Cfg.getsections()) - elif section in self.__Cfg.getsections(): + elif self.__Cfg.has_section(section): self.__Cfg.configure([section]) else: raise VMMException(_(u"Invalid section: “%s”") % section, diff -r 3d09c657e9e5 -r f8279c90e99c man/de/man5/vmm.cfg.5.rst --- a/man/de/man5/vmm.cfg.5.rst Sat Jan 30 05:15:21 2010 +0000 +++ b/man/de/man5/vmm.cfg.5.rst Mon Feb 01 18:46:17 2010 +0000 @@ -7,7 +7,7 @@ --------------------------- :Author: Pascal Volk <nev...@us...> -:Date: 2010-01-30 +:Date: 2010-02-01 :Version: vmm-0.6.0 :Manual group: vmm Manual :Manual section: 5 @@ -63,9 +63,6 @@ user = ich pass = xxxxxxxx - [config] - done = true - SUCHREIHENFOLGE --------------- @@ -205,29 +202,6 @@ postconf = /usr/sbin/postconf -CONFIG ------- -Bei der **config**-Sektion handelt es sich um eine interne -Steuerungs-Sektion. - -.. _config.done: - -``done (Vorgabe: false)`` : *Boolean* - Diese Option hat den Wert *false*, wenn |vmm(1)|_ zum ersten Mal - installiert wurde. Wenn Sie die Datei *vmm.cfg* von Hand editieren, weisen - Sie dieser Option abschließend den Wert *true* zu. Wird die Konfiguration - über das Kommando |vmm configure|_ angepasst, wird der Wert dieser Option - automatisch auf *true* gesetzt. - - Ist der Wert dieser Option *false*, so startet |vmm(1)|_ beim nächsten - Aufruf im interaktiven Konfigurations-Modus. - -Beispiel:: - - [config] - done = true - - DATABASE -------- Die **database**-Sektion wird verwendet, um die für den Datenbankzugriff diff -r 3d09c657e9e5 -r f8279c90e99c man/man5/vmm.cfg.5.rst --- a/man/man5/vmm.cfg.5.rst Sat Jan 30 05:15:21 2010 +0000 +++ b/man/man5/vmm.cfg.5.rst Mon Feb 01 18:46:17 2010 +0000 @@ -7,7 +7,7 @@ -------------------------- :Author: Pascal Volk <nev...@us...> -:Date: 2010-01-30 +:Date: 2010-02-01 :Version: vmm-0.6.0 :Manual group: vmm Manual :Manual section: 5 @@ -59,9 +59,6 @@ user = me pass = xxxxxxxx - [config] - done = true - SEARCH ORDER ------------- @@ -195,27 +192,6 @@ postconf = /usr/sbin/postconf -CONFIG ------- -The **config** section is an internal used control section. - -.. _config.done: - -``done (default: false)`` : *Boolean* - This option is set to *false* when |vmm(1)|_ is installed for the first - time. When you edit *vmm.cfg*, set this option to *true*. This option is - also set to *true* when you configure |vmm(1)|_ with the command |vmm - configure|_. - - If this option is set to *false*, |vmm(1)|_ will start in the interactive - configurations mode. - -Example:: - - [config] - done = true - - DATABASE -------- The **database** section is used to specify some options required to diff -r 3d09c657e9e5 -r f8279c90e99c vmm --- a/vmm Sat Jan 30 05:15:21 2010 +0000 +++ b/vmm Mon Feb 01 18:46:17 2010 +0000 @@ -181,7 +181,7 @@ print def configure(): - if need_setup or len(argv) < 3: + if argc < 3: vmm.configure() else: vmm.configure(argv[2]) @@ -476,8 +476,7 @@ vmm = get_vmm() try: - need_setup = not vmm.cfgDget('config.done') - if argv[1] in (u'cf', u'configure') or need_setup: + if argv[1] in (u'cf', u'configure'): configure() elif argv[1] in (u'da', u'domainadd'): domain_add() |