# HG changeset patch # User Pascal Volk # Date 1204489320 0 # Node ID e3d3dbeb5b845c560a8341cec71a594ca43a506d # Parent 7e3ce56f49e6ae0908a33e0a3eb8922599290a01 * 'create_tables.pgsql' - Added view vmm_domain_info * 'VirtualMailManager/Alias.py' - Removed attribute Alias._aid - Removed parameter basedir from Alias.__init__() and Alias._setAddr() * 'VirtualMailManager/MailLocation.py' - Fixed typo in MailLocation.__init__() * 'VirtualMailManager/Account.py' - Integrated Transport- and MailLocation-stuff - Removed attributes: Account._base and Account._home * 'VirtualMailManager/VirtualMailManager.py' - some small fixes * 'VirtualMailManager/Domain.py' - Added Transport-stuff * 'vmm.cfg' - 'Added option transport in section misc' diff -r 7e3ce56f49e6 -r e3d3dbeb5b84 ChangeLog --- a/ChangeLog Sat Feb 02 19:48:17 2008 +0000 +++ b/ChangeLog Sun Mar 02 20:22:00 2008 +0000 @@ -1,4 +1,17 @@ === 0.0.0 === +2008-03-02 Pascal Volk + + * create_tables.pgsql: Added view vmm_domain_info + * VirtualMailManager/Alias.py: Removed attribute Alias._aid + Removed parameter basedir from Alias.__init__() and Alias._setAddr() + * VirtualMailManager/MailLocation.py: Fixed typo in MailLocation.__init__() + * VirtualMailManager/Account.py: Integrated Transport- and + MailLocation-stuff + Removed attributes: Account._base and Account._home + * VirtualMailManager/VirtualMailManager.py: some small fixes + * VirtualMailManager/Domain.py: Added Transport-stuff + * vmm.cfg: Added option transport in section misc + 2008-02-02 Pascal Volk * create_tables: Renamed table maildir to maillocation diff -r 7e3ce56f49e6 -r e3d3dbeb5b84 TODO --- a/TODO Sat Feb 02 19:48:17 2008 +0000 +++ b/TODO Sun Mar 02 20:22:00 2008 +0000 @@ -1,9 +1,6 @@ # $Id$ - general - - add transport to user tbl (per account) / fall back transport via dom tbl - - make default transport configurable via vmm.cfg (for domains and - accounts - write manpages - vmm diff -r 7e3ce56f49e6 -r e3d3dbeb5b84 VirtualMailManager/Account.py --- a/VirtualMailManager/Account.py Sat Feb 02 19:48:17 2008 +0000 +++ b/VirtualMailManager/Account.py Sun Mar 02 20:22:00 2008 +0000 @@ -15,21 +15,23 @@ from Exceptions import VMMAccountException from Domain import Domain +from Transport import Transport +from MailLocation import MailLocation import constants.ERROR as ERR class Account: """Class to manage e-mail accounts.""" - def __init__(self, dbh, basedir, address, password=None): + def __init__(self, dbh, address, password=None): self._dbh = dbh - self._base = basedir self._base = None self._addr = address self._localpart = None self._name = None self._uid = 0 self._gid = 0 + self._mid = 0 + self._tid = 0 self._passwd = password - self._home = None self._setAddr(address) self._exists() if self._isAlias(): @@ -39,35 +41,37 @@ def _exists(self): dbc = self._dbh.cursor() - dbc.execute("SELECT uid FROM users WHERE gid=%s AND local_part=%s", + dbc.execute("SELECT uid, mid, tid FROM users \ +WHERE gid=%s AND local_part=%s", self._gid, self._localpart) - uid = dbc.fetchone() + result = dbc.fetchone() dbc.close() - if uid is not None: - self._uid = uid[0] + if result is not None: + self._uid, self._mid, self._tid = result return True else: return False def _isAlias(self): dbc = self._dbh.cursor() - dbc.execute("SELECT id FROM alias WHERE gid=%s AND address=%s", + dbc.execute("SELECT gid FROM alias WHERE gid=%s AND address=%s", self._gid, self._localpart) - aid = dbc.fetchone() + gid = dbc.fetchone() dbc.close() - if aid is not None: + if gid is not None: return True else: return False def _setAddr(self, address): self._localpart, d = address.split('@') - dom = Domain(self._dbh, d, self._base) + dom = Domain(self._dbh, d) self._gid = dom.getID() - self._base = dom.getDir() if self._gid == 0: raise VMMAccountException(("Domain »%s« doesn't exist." % d, ERR.NO_SUCH_DOMAIN)) + self._base = dom.getDir() + self._tid = dom.getTransportID() def _setID(self): dbc = self._dbh.cursor() @@ -75,9 +79,9 @@ self._uid = dbc.fetchone()[0] dbc.close() - def _prepare(self): + def _prepare(self, maillocation): self._setID() - self._home = "%i" % self._uid + self._mid = MailLocation(self._dbh, maillocation=maillocation).getID() def _switchState(self, state): if not isinstance(state, bool): @@ -110,13 +114,13 @@ def disable(self): self._switchState(True) - def save(self, mail): + def save(self, maillocation): if self._uid < 1: - self._prepare() + self._prepare(maillocation) dbc = self._dbh.cursor() dbc.execute("""INSERT INTO users (local_part, passwd, uid, gid,\ - home, mail) VALUES (%s, %s, %s, %s, %s, %s)""", self._localpart, - self._passwd, self._uid, self._gid, self._home, mail) + mid, tid) VALUES (%s, %s, %s, %s, %s, %s)""", self._localpart, self._passwd, + self._uid, self._gid, self._mid, self._tid ) self._dbh.commit() dbc.close() else: @@ -142,7 +146,7 @@ def getInfo(self): dbc = self._dbh.cursor() - dbc.execute("SELECT name, uid, gid, home, mail, disabled FROM users\ + dbc.execute("SELECT name, uid, gid, mid, tid, disabled FROM users\ WHERE local_part=%s AND gid=%s", self._localpart, self._gid) info = dbc.fetchone() dbc.close() @@ -150,14 +154,18 @@ raise VMMAccountException(("Account doesn't exists", ERR.NO_SUCH_ACCOUNT)) else: - keys = ['name', 'uid', 'gid', 'home', 'mail', 'disabled'] + keys = ['name', 'uid', 'gid', 'maildir', 'transport', 'disabled'] info = dict(zip(keys, info)) if bool(info['disabled']): info['disabled'] = 'Yes' else: info['disabled'] = 'No' info['address'] = self._addr - info['home'] = '%s/%s' % (self._base, info['home']) + info['maildir'] = '%s/%s/%s' % (self._base, info['uid'], + MailLocation(self._dbh, + mid=info['maildir']).getMailLocation()) + info['transport'] = Transport(self._dbh, + tid=info['transport']).getTransport() return info def delete(self): diff -r 7e3ce56f49e6 -r e3d3dbeb5b84 VirtualMailManager/Alias.py --- a/VirtualMailManager/Alias.py Sat Feb 02 19:48:17 2008 +0000 +++ b/VirtualMailManager/Alias.py Sun Mar 02 20:22:00 2008 +0000 @@ -19,7 +19,7 @@ class Alias: """Class to manage e-mail accounts.""" - def __init__(self, dbh, address, basedir, destination=None): + def __init__(self, dbh, address, destination=None): if address == destination: raise VMMAliasException(('Address and destination are identical.', ERR.ALIAS_ADDR_DEST_IDENTICAL)) @@ -28,8 +28,8 @@ self._dest = destination self._localpart = None self._gid = 0 - self._aid = 0 - self._setAddr(basedir) + self._isNew = False + self._setAddr() if not self._dest is None: self._exists() if self._isAccount(): @@ -39,15 +39,14 @@ def _exists(self): dbc = self._dbh.cursor() - dbc.execute("SELECT id FROM alias WHERE gid=%s AND address=%s\ + dbc.execute("SELECT gid FROM alias WHERE gid=%s AND address=%s\ AND destination=%s", self._gid, self._localpart, self._dest) - aid = dbc.fetchone() + gid = dbc.fetchone() dbc.close() - if aid is not None: - self._aid = aid[0] - return True + if gid is None: + self._isNew = True else: - return False + self._isNew = False def _isAccount(self): dbc = self._dbh.cursor() @@ -60,9 +59,9 @@ else: return False - def _setAddr(self, basedir): + def _setAddr(self): self._localpart, d = self._addr.split('@') - dom = Domain(self._dbh, d, basedir) + dom = Domain(self._dbh, d) self._gid = dom.getID() if self._gid == 0: raise VMMAliasException(("Domain »%s« doesn't exist." % d, @@ -72,7 +71,7 @@ if self._dest is None: raise VMMAliasException(('No destination address for alias denoted.', ERR.ALIAS_MISSING_DEST)) - if self._aid < 1: + if self._isNew: dbc = self._dbh.cursor() dbc.execute("INSERT INTO alias (gid, address, destination) VALUES\ (%s, %s, %s)", self._gid, self._localpart, self._dest) diff -r 7e3ce56f49e6 -r e3d3dbeb5b84 VirtualMailManager/Config.py --- a/VirtualMailManager/Config.py Sat Feb 02 19:48:17 2008 +0000 +++ b/VirtualMailManager/Config.py Sun Mar 02 20:22:00 2008 +0000 @@ -69,7 +69,8 @@ self.__miscopts = [ ['passwdscheme', 'CRAM-MD5'], ['gid_mail', 8], - ['forcedel', 'false'] + ['forcedel', 'false'], + ['transport', 'dovecot:'] ] def load(self): diff -r 7e3ce56f49e6 -r e3d3dbeb5b84 VirtualMailManager/Domain.py --- a/VirtualMailManager/Domain.py Sat Feb 02 19:48:17 2008 +0000 +++ b/VirtualMailManager/Domain.py Sun Mar 02 20:22:00 2008 +0000 @@ -17,24 +17,25 @@ from Exceptions import VMMDomainException import constants.ERROR as ERR +from Transport import Transport MAILDIR_CHARS = '0123456789abcdefghijklmnopqrstuvwxyz' class Domain: """Class to manage e-mail domains.""" - def __init__(self, dbh, domainname, basedir, transport=None): + def __init__(self, dbh, domainname, basedir=None, transport=None): """Creates a new Domain instance. Keyword arguments: dbh -- a pyPgSQL.PgSQL.connection domainname -- name of the domain (str) - transport -- see transport(5), default 'dovecot:' (str) + transport -- default vmm.cfg/misc/transport (str) """ self._dbh = dbh self._name = domainname self._basedir = basedir - if transport is None: - self._transport = 'dovecot:' + if transport is not None: + self._transport = Transport(self._dbh, transport=transport) else: self._transport = transport self._id = 0 @@ -48,12 +49,13 @@ will be returned. """ dbc = self._dbh.cursor() - dbc.execute("SELECT gid, domaindir FROM domains WHERE domainname=%s", + dbc.execute("SELECT gid,tid,domaindir FROM domains WHERE domainname=%s", self._name) result = dbc.fetchone() dbc.close() if result is not None: - self._id, self._domaindir = result[0], result[1] + self._id, self._domaindir = result[0], result[2] + self._transport = Transport(self._dbh, tid=result[1]) return True else: return False @@ -122,8 +124,8 @@ if self._id < 1: self._prepare() dbc = self._dbh.cursor() - dbc.execute("INSERT INTO domains (gid, domainname, transport,\ - domaindir) VALUES (%s, %s, %s, %s)", self._id, self._name, self._transport, + dbc.execute("INSERT INTO domains (gid, domainname, tid, domaindir)\ + VALUES (%s, %s, %s, %s)", self._id, self._name, self._transport.getID(), self._domaindir) self._dbh.commit() dbc.close() @@ -158,9 +160,10 @@ transport -- the new transport (str) """ if self._id > 0: + trsp = Transport(self._dbh, transport=transport) dbc = self._dbh.cursor() - dbc.execute("UPDATE domains SET transport=%s WHERE gid=%s", - transport, self._id) + dbc.execute("UPDATE domains SET tid=%s WHERE gid=%s", trsp.getID(), + self._id) if dbc.rowcount > 0: self._dbh.commit() dbc.close() @@ -176,15 +179,20 @@ """Returns the directory of the domain.""" return self._domaindir + def getTransport(self): + """Returns domain's transport.""" + return self._transport.getTransport() + + def getTransportID(self): + """Returns the ID from the domain's transport.""" + return self._transport.getID() + def getInfo(self): """Returns a dictionary with information about the domain.""" sql = """\ -SELECT gid, domainname, transport, domaindir, count(uid) AS accounts, aliases - FROM domains - LEFT JOIN users USING (gid) - LEFT JOIN vmm_alias_count USING (gid) - WHERE gid = %i -GROUP BY gid, domainname, transport, domaindir, aliases""" % self._id +SELECT gid, domainname, transport, domaindir, accounts, aliases + FROM vmm_domain_info + WHERE gid = %i""" % self._id dbc = self._dbh.cursor() dbc.execute(sql) info = dbc.fetchone() diff -r 7e3ce56f49e6 -r e3d3dbeb5b84 VirtualMailManager/MailLocation.py --- a/VirtualMailManager/MailLocation.py Sat Feb 02 19:48:17 2008 +0000 +++ b/VirtualMailManager/MailLocation.py Sun Mar 02 20:22:00 2008 +0000 @@ -36,7 +36,7 @@ ERR.MAILLOCATION_INIT)) elif mid is not None: try: - self.__id = long(tid) + self.__id = long(mid) except ValueError: raise MLE(('mid must be an int/long.', ERR.MAILLOCATION_INIT)) self._loadByID() diff -r 7e3ce56f49e6 -r e3d3dbeb5b84 VirtualMailManager/VirtualMailManager.py --- a/VirtualMailManager/VirtualMailManager.py Sat Feb 02 19:48:17 2008 +0000 +++ b/VirtualMailManager/VirtualMailManager.py Sun Mar 02 20:22:00 2008 +0000 @@ -192,8 +192,7 @@ self.__dbConnect() if not password is None: password = self.__pwhash(password) - return Account(self.__dbh, self.__Cfg.get('maildir', 'base'), address, - password) + return Account(self.__dbh, address, password) def __getAlias(self, address, destination=None): address = self.__chkEmailAddress(address) @@ -203,11 +202,12 @@ else: destination = self.__chkLocalpart(destination) self.__dbConnect() - return Alias(self.__dbh, address, self.__Cfg.get('maildir', 'base'), - destination) + return Alias(self.__dbh, address, destination) def __getDomain(self, domainname, transport=None): domainname = self.__chkDomainname(domainname) + if transport is None: + transport = self.__Cfg.get('misc', 'transport') self.__dbConnect() return Domain(self.__dbh, domainname, self.__Cfg.get('maildir', 'base'), transport) @@ -422,7 +422,7 @@ acc = self.__getAccount(emailaddress) info = acc.getInfo() if self.__Cfg.getboolean('maildir', 'diskusage') or diskusage: - info['disk usage'] = self.__getDiskUsage('%(home)s/%(mail)s' % info) + info['disk usage'] = self.__getDiskUsage('%(maildir)s' % info) return info def user_password(self, emailaddress, password): diff -r 7e3ce56f49e6 -r e3d3dbeb5b84 create_tables.pgsql --- a/create_tables.pgsql Sat Feb 02 19:48:17 2008 +0000 +++ b/create_tables.pgsql Sun Mar 02 20:22:00 2008 +0000 @@ -134,3 +134,12 @@ SELECT count(DISTINCT address) AS aliases, gid FROM alias GROUP BY gid; + +CREATE OR REPLACE VIEW vmm_domain_info AS + SELECT gid, domainname, transport, domaindir, count(uid) AS accounts, + aliases + FROM domains + LEFT JOIN transport USING (tid) + LEFT JOIN users USING (gid) + LEFT JOIN vmm_alias_count USING (gid) + GROUP BY gid, domainname, transport, domaindir, aliases; diff -r 7e3ce56f49e6 -r e3d3dbeb5b84 vmm.cfg --- a/vmm.cfg Sat Feb 02 19:48:17 2008 +0000 +++ b/vmm.cfg Sun Mar 02 20:22:00 2008 +0000 @@ -22,7 +22,7 @@ [maildir] ; The base directory for all domains/accounts (String) base = /home/mail -; name of the Maildir folder +; default name of the Maildir folder folder = Maildir ; Permissions for maildirs (Int) ; octal 0700 -> decimal 448 @@ -61,6 +61,8 @@ gid_mail = 8 ; force deletion of accounts and aliases (Boolean) forcedel = false +; default transport for domains and accounts +transport = dovecot: # # Configuration state