* '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'
--- 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 <neverseen@users.sourceforge.net>
+
+ * 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 <neverseen@users.sourceforge.net>
* create_tables: Renamed table maildir to maillocation
--- 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
--- 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):
--- 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)
--- 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):
--- 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()
--- 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()
--- 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):
--- 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;
--- 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