* 'VirtualMailManager/EmailAddress.py'
- Added to repository - to simplify/reduce address validation.
* 'VirtualMailManager/Relocated.py'
- Added to repository
* 'VirtualMailManager/Exceptions.py'
- Added exception classes for class EmailAddress and class Relocated
* 'VirtualMailManager/constants/ERROR.py'
- Updated
- Removed shebang
* 'VirtualMailManager/VirtualMailManager.py'
- Moved static methods chkLocalpart() and chkEmailAddress to new class
EmailAddress
- Added static methods accountExists(), aliasExists(), relocatedExists() and
_exists()
- Fixed a bug in VirtualMailManager._readpass()
- Integrated class EmailAddress
* 'VirtualMailManager/Alias.py'
- Integrated class EmailAddress
- Removed Alias._isAccount()
* 'VirtualMailManager/Account.py'
- Integrated class EmailAddress
- Removed Account._isAlias()
* 'VirtualMailManager/AliasDomain.py'
* 'VirtualMailManager/Config.py'
* 'VirtualMailManager/Domain.py'
* 'VirtualMailManager/MailLocation.py'
* 'VirtualMailManager/Transport.py'
* 'VirtualMailManager/constants/EXIT.py'
- Removed shebang
* 'vmm'
- more detailed error messages from alias_add()
--- a/TODO Sat Sep 06 03:07:28 2008 +0000
+++ b/TODO Mon Sep 08 05:30:17 2008 +0000
@@ -5,4 +5,5 @@
- VirtualMailManager/Alias.py
- check if account exists, when destination is in the same domain
+ - avoid looping aliases
--- a/VirtualMailManager/Account.py Sat Sep 06 03:07:28 2008 +0000
+++ b/VirtualMailManager/Account.py Mon Sep 08 05:30:17 2008 +0000
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# Copyright 2007-2008 VEB IT
# See COPYING for distribution information.
@@ -17,6 +16,7 @@
from Domain import Domain
from Transport import Transport
from MailLocation import MailLocation
+from EmailAddress import EmailAddress
import VirtualMailManager as VMM
import constants.ERROR as ERR
@@ -25,9 +25,10 @@
def __init__(self, dbh, address, password=None):
self._dbh = dbh
self._base = None
- self._addr = VMM.VirtualMailManager.chkEmailAddress(address)
- self._localpart = None
- self._name = None
+ if isinstance(address, EmailAddress):
+ self._addr = address
+ else:
+ raise TypeError("Argument 'address' is not an EmailAddress")
self._uid = 0
self._gid = 0
self._mid = 0
@@ -35,15 +36,19 @@
self._passwd = password
self._setAddr()
self._exists()
- if self._isAlias():
+ if VMM.VirtualMailManager.aliasExists(self._dbh, self._addr):
raise AccE(_(u"There is already an alias with the address »%s«.") %\
- address, ERR.ALIAS_EXISTS)
+ self._addr, ERR.ALIAS_EXISTS)
+ if VMM.VirtualMailManager.relocatedExists(self._dbh, self._addr):
+ raise AccE(
+ _(u"There is already an relocated user with the address »%s«.") %\
+ self._addr, ERR.RELOCATED_EXISTS)
def _exists(self):
dbc = self._dbh.cursor()
dbc.execute("SELECT uid, mid, tid FROM users \
WHERE gid=%s AND local_part=%s",
- self._gid, self._localpart)
+ self._gid, self._addr._localpart)
result = dbc.fetchone()
dbc.close()
if result is not None:
@@ -52,24 +57,12 @@
else:
return False
- def _isAlias(self):
- dbc = self._dbh.cursor()
- dbc.execute("SELECT gid FROM alias WHERE gid=%s AND address=%s",
- self._gid, self._localpart)
- gid = dbc.fetchone()
- dbc.close()
- if gid is not None:
- return True
- else:
- return False
-
def _setAddr(self):
- self._localpart, d = self._addr.split('@')
- dom = Domain(self._dbh, d)
+ dom = Domain(self._dbh, self._addr._domainname)
self._gid = dom.getID()
if self._gid == 0:
- raise AccE(_(u"The domain »%s« doesn't exist yet.") % d,
- ERR.NO_SUCH_DOMAIN)
+ raise AccE(_(u"The domain »%s« doesn't exist yet.") %\
+ self._addr._domainname, ERR.NO_SUCH_DOMAIN)
self._base = dom.getDir()
self._tid = dom.getTransportID()
@@ -96,15 +89,15 @@
if service in ['smtp', 'pop3', 'imap', 'managesieve']:
dbc.execute(
"UPDATE users SET %s=%s WHERE local_part='%s' AND gid=%s"
- % (service, state, self._localpart, self._gid))
+ % (service, state, self._addr._localpart, self._gid))
elif state:
dbc.execute("UPDATE users SET smtp = TRUE, pop3 = TRUE,\
imap = TRUE, managesieve = TRUE WHERE local_part = %s AND gid = %s",
- self._localpart, self._gid)
+ self._addr._localpart, self._gid)
else:
dbc.execute("UPDATE users SET smtp = FALSE, pop3 = FALSE,\
imap = FALSE, managesieve = FALSE WHERE local_part = %s AND gid = %s",
- self._localpart, self._gid)
+ self._addr._localpart, self._gid)
if dbc.rowcount > 0:
self._dbh.commit()
dbc.close()
@@ -146,8 +139,8 @@
dbc.execute("""INSERT INTO users (local_part, passwd, uid, gid,\
mid, tid, smtp, pop3, imap, managesieve)\
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)""",
- self._localpart, self._passwd, self._uid, self._gid, self._mid,
- self._tid, smtp, pop3, imap, managesieve)
+ self._addr._localpart, self._passwd, self._uid, self._gid,
+ self._mid, self._tid, smtp, pop3, imap, managesieve)
self._dbh.commit()
dbc.close()
else:
@@ -163,14 +156,14 @@
dbc = self._dbh.cursor()
if what == 'password':
dbc.execute("UPDATE users SET passwd=%s WHERE local_part=%s AND\
- gid=%s", value, self._localpart, self._gid)
+ gid=%s", value, self._addr._localpart, self._gid)
elif what == 'transport':
self._tid = Transport(self._dbh, transport=value).getID()
dbc.execute("UPDATE users SET tid=%s WHERE local_part=%s AND\
- gid=%s", self._tid, self._localpart, self._gid)
+ gid=%s", self._tid, self._addr._localpart, self._gid)
else:
dbc.execute("UPDATE users SET name=%s WHERE local_part=%s AND\
- gid=%s", value, self._localpart, self._gid)
+ gid=%s", value, self._addr._localpart, self._gid)
if dbc.rowcount > 0:
self._dbh.commit()
dbc.close()
@@ -179,7 +172,7 @@
dbc = self._dbh.cursor()
dbc.execute("SELECT name, uid, gid, mid, tid, smtp, pop3, imap, \
managesieve FROM users WHERE local_part=%s AND gid=%s",
- self._localpart, self._gid)
+ self._addr._localpart, self._gid)
info = dbc.fetchone()
dbc.close()
if info is None:
@@ -209,7 +202,7 @@
dbc = self._dbh.cursor()
if delalias == 'delalias':
dbc.execute("DELETE FROM users WHERE gid=%s AND local_part=%s",
- self._gid, self._localpart)
+ self._gid, self._addr._localpart)
u_rc = dbc.rowcount
# delete also all aliases where the destination address is the same
# as for this account.
@@ -220,7 +213,7 @@
a_count = self.__aliaseCount()
if a_count == 0:
dbc.execute("DELETE FROM users WHERE gid=%s AND local_part=%s",
- self._gid, self._localpart)
+ self._gid, self._addr._localpart)
if dbc.rowcount > 0:
self._dbh.commit()
else:
--- a/VirtualMailManager/Alias.py Sat Sep 06 03:07:28 2008 +0000
+++ b/VirtualMailManager/Alias.py Mon Sep 08 05:30:17 2008 +0000
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# Copyright 2007-2008 VEB IT
# See COPYING for distribution information.
@@ -15,62 +14,55 @@
from Exceptions import VMMAliasException as VMMAE
from Domain import Domain
+from EmailAddress import EmailAddress
import constants.ERROR as ERR
import VirtualMailManager as VMM
class Alias:
- """Class to manage e-mail accounts."""
+ """Class to manage e-mail aliases."""
def __init__(self, dbh, address, destination=None):
+ 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._addr = VMM.VirtualMailManager.chkEmailAddress(address)
- if destination is None:
- self._dest = None
- elif destination.count('@'):
- self._dest = VMM.VirtualMailManager.chkEmailAddress(destination)
- else:
- self._dest = VMM.VirtualMailManager.chkLocalpart(destination)
- self._localpart = None
self._gid = 0
self._isNew = False
self._setAddr()
if not self._dest is None:
self._exists()
- if self._isAccount():
- raise VMMAE(_(u"There is already an account with address »%s«.") %
+ 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 an relocated user with the address »%s«.") %\
+ self._addr, ERR.RELOCATED_EXISTS)
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._localpart, self._dest)
+ AND destination=%s", self._gid, self._addr._localpart, str(self._dest))
gid = dbc.fetchone()
dbc.close()
if gid is None:
self._isNew = True
- else:
- self._isNew = False
- def _isAccount(self):
- dbc = self._dbh.cursor()
- dbc.execute("SELECT uid FROM users WHERE gid=%s AND local_part=%s",
- self._gid, self._localpart)
- uid = dbc.fetchone()
- dbc.close()
- if uid is not None:
- return True
- else:
- return False
-
def _setAddr(self):
- self._localpart, d = self._addr.split('@')
- dom = Domain(self._dbh, d)
+ dom = Domain(self._dbh, self._addr._domainname)
self._gid = dom.getID()
if self._gid == 0:
- raise VMMAE(_(u"The domain »%s« doesn't exist yet.") % d,
- ERR.NO_SUCH_DOMAIN)
+ raise VMMAE(_(u"The domain »%s« doesn't exist yet.") %\
+ self._addr._domainname, ERR.NO_SUCH_DOMAIN)
def save(self):
if self._dest is None:
@@ -79,17 +71,18 @@
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)
+ (%s, %s, %s)", self._gid, self._addr._localpart, str(self._dest))
self._dbh.commit()
dbc.close()
else:
- raise VMMAE(_(u"The alias »%s« already exists.") % self._addr,
- ERR.ALIAS_EXISTS)
+ raise VMMAE(
+ _(u"The alias »%(a)s« with destination »%(d)s« already exists.")\
+ % {'a': self._addr, 'd': self._dest}, ERR.ALIAS_EXISTS)
def getInfo(self):
dbc = self._dbh.cursor()
dbc.execute('SELECT destination FROM alias WHERE gid=%s AND address=%s',
- self._gid, self._localpart)
+ self._gid, self._addr._localpart)
destinations = dbc.fetchall()
dbc.close()
if len(destinations) > 0:
@@ -105,15 +98,19 @@
dbc = self._dbh.cursor()
if self._dest is None:
dbc.execute("DELETE FROM alias WHERE gid=%s AND address=%s",
- self._gid, self._localpart)
+ self._gid, self._addr._localpart)
else:
dbc.execute("DELETE FROM alias WHERE gid=%s AND address=%s AND \
- destination=%s", self._gid, self._localpart, self._dest)
+ destination=%s", self._gid, self._addr._localpart, str(self._dest))
rowcount = dbc.rowcount
dbc.close()
if rowcount > 0:
self._dbh.commit()
else:
- raise VMMAE(_(u"The alias »%s« doesn't exists.") % self._addr,
- ERR.NO_SUCH_ALIAS)
+ if self._dest is None:
+ msg = u"The alias »%s« doesn't exists." % self._addr
+ else:
+ msg = u"The alias »%(a)s« with destination »%(d)s« doesn't\
+ exists." % {'a': self._addr, 'd': self._dest}
+ raise VMMAE(_(msg), ERR.NO_SUCH_ALIAS)
--- a/VirtualMailManager/AliasDomain.py Sat Sep 06 03:07:28 2008 +0000
+++ b/VirtualMailManager/AliasDomain.py Mon Sep 08 05:30:17 2008 +0000
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# Copyright 2008 VEB IT
# See COPYING for distribution information.
--- a/VirtualMailManager/Config.py Sat Sep 06 03:07:28 2008 +0000
+++ b/VirtualMailManager/Config.py Mon Sep 08 05:30:17 2008 +0000
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# Copyright 2007-2008 VEB IT
# See COPYING for distribution information.
--- a/VirtualMailManager/Domain.py Sat Sep 06 03:07:28 2008 +0000
+++ b/VirtualMailManager/Domain.py Mon Sep 08 05:30:17 2008 +0000
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# Copyright 2007-2008 VEB IT
# See COPYING for distribution information.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/VirtualMailManager/EmailAddress.py Mon Sep 08 05:30:17 2008 +0000
@@ -0,0 +1,87 @@
+# -*- coding: UTF-8 -*-
+# Copyright 2008 VEB IT
+# See COPYING for distribution information.
+# $Id$
+
+"""Virtual Mail Manager's EmailAddress class to handle e-mail addresses."""
+
+from constants.VERSION import VERSION
+
+__author__ = 'Pascal Volk <p.volk@veb-it.de>'
+__version__ = VERSION
+__revision__ = 'rev '+'$Rev$'.split()[1]
+__date__ = '$Date$'.split()[1]
+
+import re
+
+from Exceptions import VMMEmailAddressException as VMMEAE
+import VirtualMailManager as VMM
+import constants.ERROR as ERR
+
+RE_LOCALPART = """[^\w!#$%&'\*\+-\.\/=?^_`{\|}~]"""
+
+class EmailAddress(object):
+ def __init__(self, address):
+ self._localpart = None
+ self._domainname = None
+ self.__chkAddress(address)
+
+ def __eq__(self, other):
+ if hasattr(other, '_localpart') and hasattr(other, '_domainname'):
+ return self._localpart == other._localpart\
+ and self._domainname == other._domainname
+ else:
+ return NotImplemented
+
+ def __ne__(self, other):
+ if hasattr(other, '_localpart') and hasattr(other, '_domainname'):
+ return not self._localpart == other._localpart\
+ and self._domainname == other._domainname
+ else:
+ return NotImplemented
+
+ def __repr__(self):
+ return "EmailAddress('%s@%s')" % (self._localpart, self._domainname)
+
+ def __str__(self):
+ return "%s@%s" % (self._localpart, self._domainname)
+
+ def __chkAddress(self, address):
+ try:
+ localpart, domain = address.split('@')
+ except ValueError:
+ raise VMMEAE(_(u"Missing '@' sign in e-mail address »%s«.") %
+ address, ERR.INVALID_ADDRESS)
+ except AttributeError:
+ raise VMMEAE(_(u"»%s« looks not like an e-mail address.") %
+ address, ERR.INVALID_ADDRESS)
+ if len(domain) > 0:
+ domain = VMM.VirtualMailManager.chkDomainname(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
+
+ def __chkLocalpart(self, localpart):
+ """Validates the local part of an e-mail address.
+
+ Keyword arguments:
+ localpart -- of the e-mail address that should be validated (str)
+ """
+ if len(localpart) < 1:
+ raise VMMEAE(_(u'No localpart specified.'),
+ ERR.LOCALPART_INVALID)
+ if len(localpart) > 64:
+ raise VMMEAE(_(u'The local part »%s« is too long') %
+ localpart, ERR.LOCALPART_TOO_LONG)
+ ic = re.compile(RE_LOCALPART).findall(localpart)
+ if len(ic):
+ ichrs = ''
+ for c in set(ic):
+ ichrs += u"»%s« " % c
+ raise VMMEAE(_(u"The local part »%(lpart)s« contains invalid\
+ characters: %(ichrs)s") % {'lpart': localpart, 'ichrs': ichrs},
+ ERR.LOCALPART_INVALID)
+ return localpart
+
--- a/VirtualMailManager/Exceptions.py Sat Sep 06 03:07:28 2008 +0000
+++ b/VirtualMailManager/Exceptions.py Mon Sep 08 05:30:17 2008 +0000
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# Copyright 2007-2008 VEB IT
# See COPYING for distribution information.
@@ -65,13 +64,22 @@
def __init__(self, msg, code):
VMMException.__init__(self, msg, code)
+class VMMEmailAddressException(VMMException):
+ """Exception class for EmailAddress exceptions"""
+ def __init__(self, msg, code):
+ VMMException.__init__(self, msg, code)
+
class VMMMailLocationException(VMMException):
"""Exception class for MailLocation exceptions"""
def __init__(self, msg, code):
VMMException.__init__(self, msg, code)
+class VMMRelocatedException(VMMException):
+ """Exception class for Relocated exceptions"""
+ def __init__(self, msg, code):
+ VMMException.__init__(self, msg, code)
+
class VMMTransportException(VMMException):
"""Exception class for Transport exceptions"""
def __init__(self, msg, code):
VMMException.__init__(self, msg, code)
-
--- a/VirtualMailManager/MailLocation.py Sat Sep 06 03:07:28 2008 +0000
+++ b/VirtualMailManager/MailLocation.py Mon Sep 08 05:30:17 2008 +0000
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# Copyright 2008 VEB IT
# See COPYING for distribution information.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/VirtualMailManager/Relocated.py Mon Sep 08 05:30:17 2008 +0000
@@ -0,0 +1,107 @@
+# -*- coding: UTF-8 -*-
+# Copyright 2008 VEB IT
+# See COPYING for distribution information.
+# $Id$
+
+"""Virtual Mail Manager's Relocated class to manage relocated users."""
+
+from constants.VERSION import VERSION
+
+__author__ = 'Pascal Volk <p.volk@veb-it.de>'
+__version__ = VERSION
+__revision__ = 'rev '+'$Rev$'.split()[1]
+__date__ = '$Date$'.split()[1]
+
+from Exceptions import VMMRelocatedException as VMMRE
+from Domain import Domain
+from EmailAddress import EmailAddress
+import constants.ERROR as ERR
+import VirtualMailManager as VMM
+
+class Relocated:
+ """Class to manage e-mail addresses of relocated users."""
+ def __init__(self, dbh, address, destination=None):
+ 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 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 VMM.VirtualMailManager.accountExists(self._dbh, self._addr):
+ raise VMMRE(_(u"There is already an account with address »%s«.") %\
+ self._addr, ERR.ACCOUNT_EXISTS)
+ if 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()
+ 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 yet.") %\
+ self._addr._domainname, ERR.NO_SUCH_DOMAIN)
+
+ def save(self):
+ if self._dest is None:
+ raise VMMRE(_(u"No destination address for relocated user denoted."),
+ 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]
+ else:
+ raise VMMRE(
+ _(u"The relocated user »%s« doesn't exists.") % self._addr,
+ ERR.NO_SUCH_RELOCATED)
+
+ def delete(self):
+ dbc = self._dbh.cursor()
+ dbc.execute("DELETE FROM relocated WHERE gid = %s AND address = %s",
+ self._gid, self._addr._localpart)
+ rowcount = dbc.rowcount
+ dbc.close()
+ if rowcount > 0:
+ self._dbh.commit()
+ else:
+ raise VMMRE(
+ _(u"The relocated user »%s« doesn't exists.") % self._addr,
+ ERR.NO_SUCH_RELOCATED)
+
--- a/VirtualMailManager/Transport.py Sat Sep 06 03:07:28 2008 +0000
+++ b/VirtualMailManager/Transport.py Mon Sep 08 05:30:17 2008 +0000
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# Copyright 2008 VEB IT
# See COPYING for distribution information.
--- a/VirtualMailManager/VirtualMailManager.py Sat Sep 06 03:07:28 2008 +0000
+++ b/VirtualMailManager/VirtualMailManager.py Mon Sep 08 05:30:17 2008 +0000
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# Copyright 2007-2008 VEB IT
# See COPYING for distribution information.
@@ -23,13 +22,15 @@
from pyPgSQL import PgSQL # python-pgsql - http://pypgsql.sourceforge.net
-from Exceptions import *
import constants.ERROR as ERR
-from Config import Config as Cfg
from Account import Account
from Alias import Alias
+from AliasDomain import AliasDomain
+from Config import Config as Cfg
from Domain import Domain
-from AliasDomain import AliasDomain
+from EmailAddress import EmailAddress
+from Exceptions import *
+from Relocated import Relocated
SALTCHARS = './0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
RE_ASCII_CHARS = """^[\x20-\x7E]*$"""
@@ -114,29 +115,6 @@
except PgSQL.libpq.DatabaseError, e:
raise VMMException(str(e), ERR.DATABASE_ERROR)
- def chkLocalpart(localpart):
- """Validates the local part of an e-mail address.
-
- Keyword arguments:
- localpart -- the e-mail address that should be validated (str)
- """
- if len(localpart) < 1:
- raise VMMException(_(u'No localpart specified.'),
- ERR.LOCALPART_INVALID)
- if len(localpart) > 64:
- raise VMMException(_(u'The local part »%s« is too long') %
- localpart, ERR.LOCALPART_TOO_LONG)
- ic = re.compile(RE_LOCALPART).findall(localpart)
- if len(ic):
- ichrs = ''
- for c in set(ic):
- ichrs += u"»%s« " % c
- raise VMMException(_(u"The local part »%(lpart)s« contains invalid\
- characters: %(ichrs)s") % {'lpart': localpart, 'ichrs': ichrs},
- ERR.LOCALPART_INVALID)
- return localpart
- chkLocalpart = staticmethod(chkLocalpart)
-
def idn2ascii(domainname):
"""Converts an idn domainname in punycode.
@@ -179,52 +157,70 @@
ERR.DOMAIN_TOO_LONG)
re.compile(RE_DOMAIN)
if not re.match(RE_DOMAIN, domainname):
- raise VMMException(_(u'The domain name is invalid.'),
- ERR.DOMAIN_INVALID)
+ raise VMMException(_(u'The domain name »%s« is invalid.') %\
+ domainname, ERR.DOMAIN_INVALID)
return domainname
chkDomainname = staticmethod(chkDomainname)
- def chkEmailAddress(address):
- try:
- localpart, domain = address.split('@')
- except ValueError:
- raise VMMException(_(u"Missing '@' sign in e-mail address »%s«.") %
- address, ERR.INVALID_ADDRESS)
- except AttributeError:
- raise VMMException(_(u"»%s« looks not like an e-mail address.") %
- address, ERR.INVALID_ADDRESS)
- if len(domain) > 0:
- domain = VirtualMailManager.chkDomainname(domain)
+ def _exists(dbh, query):
+ dbc = dbh.cursor()
+ dbc.execute(query)
+ gid = dbc.fetchone()
+ dbc.close()
+ if gid is None:
+ return False
else:
- raise VMMException(_(u"Missing domain name after »%s@«.") %
- localpart, ERR.DOMAIN_NO_NAME)
- localpart = VirtualMailManager.chkLocalpart(localpart)
- return '%s@%s' % (localpart, domain)
- chkEmailAddress = staticmethod(chkEmailAddress)
+ return True
+ _exists = staticmethod(_exists)
+
+ def accountExists(dbh, address):
+ sql = "SELECT gid FROM users WHERE gid = (SELECT gid FROM domain_name\
+ WHERE domainname = '%(_domainname)s') AND local_part = '%(_localpart)s'" %\
+ address.__dict__
+ 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 = '%(_domainname)s') AND address =\
+ '%(_localpart)s'" % address.__dict__
+ 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 = '%(_domainname)s') AND address =\
+ '%(_localpart)s'" % address.__dict__
+ return VirtualMailManager._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 _readpass(self):
- clear0 = ''
- clear1 = '1'
- while clear0 != clear1:
- while len(clear0) < 1:
- clear0 = getpass(prompt=_('Enter new password: '))
- if len(clear0) < 1:
- sys.stderr.write('%s\n'
- % _('Sorry, empty passwords are not permitted'))
+ mismatched = True
+ while mismatched:
+ clear0 = getpass(prompt=_('Enter new password: '))
clear1 = getpass(prompt=_('Retype new password: '))
if clear0 != clear1:
- clear0 = ''
sys.stderr.write('%s\n' % _('Sorry, passwords do not match'))
+ continue
+ if len(clear0) < 1 or len(clear1) < 1:
+ sys.stderr.write('%s\n'
+ % _('Sorry, empty passwords are not permitted'))
+ continue
+ mismatched = False
return clear0
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 __getDomain(self, domainname, transport=None):
--- a/VirtualMailManager/constants/ERROR.py Sat Sep 06 03:07:28 2008 +0000
+++ b/VirtualMailManager/constants/ERROR.py Mon Sep 08 05:30:17 2008 +0000
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# Copyright 2007-2008 VEB IT
# See COPYING for distribution information.
@@ -41,7 +40,11 @@
NO_SUCH_BINARY = 54
NO_SUCH_DIRECTORY = 55
NO_SUCH_DOMAIN = 56
-TRANSPORT_INIT = 57
-UNKNOWN_MAILLOCATION_ID = 58
-UNKNOWN_SERVICE = 59
-UNKNOWN_TRANSPORT_ID = 60
+NO_SUCH_RELOCATED = 57
+RELOCATED_ADDR_DEST_IDENTICAL = 58
+RELOCATED_EXISTS = 59
+RELOCATED_MISSING_DEST = 60
+TRANSPORT_INIT = 61
+UNKNOWN_MAILLOCATION_ID = 62
+UNKNOWN_SERVICE = 63
+UNKNOWN_TRANSPORT_ID = 64
--- a/VirtualMailManager/constants/EXIT.py Sat Sep 06 03:07:28 2008 +0000
+++ b/VirtualMailManager/constants/EXIT.py Mon Sep 08 05:30:17 2008 +0000
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# Copyright 2007-2008 VEB IT
# See COPYING for distribution information.
--- a/pgsql-virtual_mailbox_domains.cf Sat Sep 06 03:07:28 2008 +0000
+++ b/pgsql-virtual_mailbox_domains.cf Mon Sep 08 05:30:17 2008 +0000
@@ -9,4 +9,4 @@
dbname = mailsys
# Postfix 2.2 and later The SQL query template. See pgsql_table(5).
-query = SELECT gid FROM postfix_gid WHERE domainname = '%d'
+query = SELECT gid FROM postfix_gid WHERE domainname = '%s'
--- a/vmm Sat Sep 06 03:07:28 2008 +0000
+++ b/vmm Mon Sep 08 05:30:17 2008 +0000
@@ -317,8 +317,10 @@
vmm.userPassword(argv[2].lower(), password)
def alias_add():
- if argc < 4:
+ if argc < 3:
usage(EXIT.MISSING_ARGS, _(u'Missing alias address and destination.'))
+ elif argc < 4:
+ usage(EXIT.MISSING_ARGS, _(u'Missing destination address.'))
else:
vmm.aliasAdd(argv[2].lower(), argv[3])