mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-17 05:41:25 +02:00
+2
-2
@@ -11,8 +11,8 @@ as an administration panel or a webmail.
|
||||
Modoboa integrates with well known software such as `Postfix
|
||||
<http://postfix.org/>`_ or `Dovecot <http://dovecot.org/>`_. A SQL
|
||||
database (`MySQL <http://www.mysql.com>`_, `PostgreSQL
|
||||
<http://www.postgresql.org/>`_) is used as a central point of
|
||||
communication between all components.
|
||||
<http://www.postgresql.org/>`_ or `SQLite <http://www.sqlite.org>`_)
|
||||
is used as a central point of communication between all components.
|
||||
|
||||
Modoboa is developed with modularity in mind, expanding it is really
|
||||
easy. Actually, all current features are extensions.
|
||||
|
||||
@@ -161,6 +161,23 @@ PostgreSQL users
|
||||
|
||||
iterate_query = SELECT email AS username FROM admin_user
|
||||
|
||||
SQLite users
|
||||
------------
|
||||
|
||||
::
|
||||
|
||||
driver = sqlite
|
||||
|
||||
connect = <path to the sqlite db file>
|
||||
|
||||
default_pass_scheme = CRYPT
|
||||
|
||||
password_query = SELECT email AS user, password FROM admin_user WHERE email='%u' and is_active=1
|
||||
|
||||
user_query = SELECT '<mailboxes storage directory>/%d/%n' AS home, <uid> as uid, <gid> as gid, ('*:bytes=' || mb.quota || 'M') AS quota_rule FROM admin_mailbox mb INNER JOIN admin_domain dom ON mb.domain_id=dom.id WHERE mb.address='%n' AND dom.name='%d'
|
||||
|
||||
iterate_query = SELECT email AS username FROM admin_user
|
||||
|
||||
.. note::
|
||||
|
||||
Replace values between ``<>`` with yours.
|
||||
@@ -228,6 +245,8 @@ Finally, edit the :file:`dovecot-dict-sql.conf.ext` file and put the
|
||||
following content inside::
|
||||
|
||||
connect = host=<db host> dbname=<db name> user=<db user> password=<password>
|
||||
# SQLite users
|
||||
# connect = /path/to/the/database.db
|
||||
|
||||
map {
|
||||
pattern = priv/quota/storage
|
||||
@@ -404,7 +423,7 @@ be used by Postfix to lookup into Modoboa tables.
|
||||
To automaticaly generate the requested map files and store them in a
|
||||
directory, run the following command::
|
||||
|
||||
$ modoboa-admin.py postfix_maps --dbtype <mysql|postgres> mapfiles
|
||||
$ modoboa-admin.py postfix_maps --dbtype <mysql|postgres|sqlite> mapfiles
|
||||
|
||||
:file:`mapfiles` is the directory where the files will be
|
||||
stored. Answer the few questions and you're done.
|
||||
@@ -427,22 +446,24 @@ Use the following configuration in the :file:`/etc/postfix/main.cf` file
|
||||
virtual_mailbox_base = /var/vmail
|
||||
|
||||
relay_domains =
|
||||
virtual_mailbox_domains = mysql:/etc/postfix/sql-domains.cf
|
||||
virtual_alias_domains = mysql:/etc/postfix/sql-domain-aliases.cf
|
||||
virtual_mailbox_maps = mysql:/etc/postfix/sql-mailboxes.cf
|
||||
virtual_alias_maps = mysql:/etc/postfix/sql-aliases.cf,
|
||||
mysql:/etc/postfix/sql-domain-aliases-mailboxes.cf,
|
||||
mysql:/etc/postfix/sql-email2email.cf,
|
||||
mysql:/etc/postfix/sql-catchall-aliases.cf
|
||||
virtual_mailbox_domains = <driver>:/etc/postfix/sql-domains.cf
|
||||
virtual_alias_domains = <driver>:/etc/postfix/sql-domain-aliases.cf
|
||||
virtual_mailbox_maps = <driver>:/etc/postfix/sql-mailboxes.cf
|
||||
virtual_alias_maps = <driver>:/etc/postfix/sql-aliases.cf,
|
||||
<driver>:/etc/postfix/sql-domain-aliases-mailboxes.cf,
|
||||
<driver>:/etc/postfix/sql-email2email.cf,
|
||||
<driver>:/etc/postfix/sql-catchall-aliases.cf
|
||||
|
||||
smtpd_recipient_restrictions =
|
||||
...
|
||||
check_recipient_access mysql:/etc/postfix/maps/sql-maintain.cf
|
||||
check_recipient_access <driver>:/etc/postfix/maps/sql-maintain.cf
|
||||
permit_mynetworks
|
||||
...
|
||||
|
||||
# Stuff after
|
||||
|
||||
Replace ``<driver>`` by the name of the database you use.
|
||||
|
||||
Then, edit the :file:`/etc/postfix/master.cf` file and add the following
|
||||
definition at the end::
|
||||
|
||||
|
||||
@@ -6,69 +6,111 @@ from django.template import Context, Template
|
||||
from modoboa.core.management import Command
|
||||
|
||||
|
||||
class MapFile(object):
|
||||
category = 'std'
|
||||
class MapFilesGenerator(object):
|
||||
|
||||
def __init__(self):
|
||||
self.base_tpl = Template("""user = {{ dbuser }}
|
||||
password = {{ dbpassword }}
|
||||
self.template = Template("""user = {{ dbuser }}
|
||||
password = {{ dbpass }}
|
||||
dbname = {{ dbname }}
|
||||
hosts = {{ dbhost }}
|
||||
query = {{ query|safe }}
|
||||
""")
|
||||
self.tpl_context = {
|
||||
'dbhost': raw_input('Database host: '),
|
||||
'dbname': raw_input('Database name: '),
|
||||
'dbuser': raw_input('Username: '),
|
||||
'dbpass': getpass.getpass('Password: ')
|
||||
}
|
||||
if not self.tpl_context['dbhost']:
|
||||
self.tpl_context['dbhost'] = '127.0.0.1'
|
||||
|
||||
def render(self, destdir, dbtype, **options):
|
||||
def render(self, args):
|
||||
"""Render all map files.
|
||||
|
||||
:param args: arguments received from the command line
|
||||
"""
|
||||
try:
|
||||
options['query'] = getattr(self, dbtype)
|
||||
except AttributeError:
|
||||
return
|
||||
os.mkdir(args.destdir)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
content = self.base_tpl.render(Context(options))
|
||||
fp = open("%s/%s" % (destdir, self.filename), "w")
|
||||
fp.write(content)
|
||||
fp.close()
|
||||
for v in globals().values():
|
||||
if not inspect.isclass(v) or not issubclass(v, MapFile):
|
||||
continue
|
||||
if v is MapFile:
|
||||
continue
|
||||
if not v.category in args.categories:
|
||||
continue
|
||||
content = self.template.render(
|
||||
Context(dict(self.tpl_context.items(),
|
||||
query=getattr(v, args.dbtype)))
|
||||
)
|
||||
with open("%s/%s" % (args.destdir, v.filename), "w") as fp:
|
||||
print >> fp, content
|
||||
|
||||
|
||||
class SQLiteMapFilesGenerator(MapFilesGenerator):
|
||||
|
||||
def __init__(self):
|
||||
self.template = Template("""dbpath = {{ dbpath }}
|
||||
query = {{ query|safe }}
|
||||
""")
|
||||
self.tpl_context = {
|
||||
'dbpath': raw_input('Database path: ')
|
||||
}
|
||||
|
||||
|
||||
class MapFile(object):
|
||||
category = 'std'
|
||||
|
||||
|
||||
class DomainsMap(MapFile):
|
||||
filename = 'sql-domains.cf'
|
||||
mysql = "SELECT name FROM admin_domain WHERE name='%s' AND enabled=1"
|
||||
postgres = "SELECT name FROM admin_domain WHERE name='%s' AND enabled"
|
||||
sqlite = "SELECT name FROM admin_domain WHERE name='%s' AND enabled=1"
|
||||
|
||||
|
||||
class DomainsAliasesMap(MapFile):
|
||||
filename = 'sql-domain-aliases.cf'
|
||||
mysql = "SELECT dom.name FROM admin_domain dom INNER JOIN admin_domainalias domal ON dom.id=domal.target_id WHERE domal.name='%s' AND domal.enabled=1 AND dom.enabled=1"
|
||||
postgres = "SELECT dom.name FROM admin_domain dom INNER JOIN admin_domainalias domal ON dom.id=domal.target_id WHERE domal.name='%s' AND domal.enabled AND dom.enabled"
|
||||
sqlite = "SELECT dom.name FROM admin_domain dom INNER JOIN admin_domainalias domal ON dom.id=domal.target_id WHERE domal.name='%s' AND domal.enabled=1 AND dom.enabled=1"
|
||||
|
||||
|
||||
class MailboxesMap(MapFile):
|
||||
filename = 'sql-mailboxes.cf'
|
||||
mysql = "SELECT 1 FROM admin_mailbox mb INNER JOIN admin_domain dom ON mb.domain_id=dom.id INNER JOIN admin_user user ON mb.user_id=user.id WHERE dom.enabled=1 AND dom.name='%d' AND user.is_active=1 AND mb.address='%u'"
|
||||
postgres = "SELECT 1 FROM admin_mailbox mb INNER JOIN admin_domain dom ON mb.domain_id=dom.id INNER JOIN admin_user u ON mb.user_id=u.id WHERE dom.enabled AND dom.name='%d' AND u.is_active AND mb.address='%u'"
|
||||
sqlite = "SELECT 1 FROM admin_mailbox mb INNER JOIN admin_domain dom ON mb.domain_id=dom.id INNER JOIN admin_user user ON mb.user_id=user.id WHERE dom.enabled=1 AND dom.name='%d' AND user.is_active=1 AND mb.address='%u'"
|
||||
|
||||
|
||||
class AliasesMap(MapFile):
|
||||
filename = 'sql-aliases.cf'
|
||||
mysql = "(SELECT concat(mb.address, '@', dom.name) FROM admin_mailbox mb INNER JOIN admin_domain dom ON mb.domain_id=dom.id WHERE mb.id IN (SELECT al_mb.mailbox_id FROM admin_alias_mboxes al_mb INNER JOIN admin_alias al ON al_mb.alias_id=al.id INNER JOIN admin_domain dom ON al.domain_id=dom.id WHERE dom.name='%d' AND dom.enabled=1 AND al.address='%u' AND al.enabled=1)) UNION (SELECT concat(al.address, '@', dom.name) FROM admin_alias al INNER JOIN admin_domain dom ON al.domain_id=dom.id WHERE al.id IN (SELECT al_al.to_alias_id FROM admin_alias_aliases al_al INNER JOIN admin_alias al ON al_al.from_alias_id=al.id INNER JOIN admin_domain dom ON al.domain_id=dom.id WHERE dom.name='%d' AND dom.enabled=1 AND al.address='%u' AND al.enabled=1)) UNION (SELECT al.extmboxes FROM admin_alias al INNER JOIN admin_domain dom ON al.domain_id=dom.id WHERE dom.name='%d' AND dom.enabled=1 AND al.address='%u' AND al.enabled=1 AND al.extmboxes<>'')"
|
||||
postgres = "(SELECT mb.address || '@' || dom.name FROM admin_mailbox mb INNER JOIN admin_domain dom ON mb.domain_id=dom.id WHERE mb.id IN (SELECT al_mb.mailbox_id FROM admin_alias_mboxes al_mb INNER JOIN admin_alias al ON al_mb.alias_id=al.id INNER JOIN admin_domain dom ON al.domain_id=dom.id WHERE dom.name='%d' AND dom.enabled AND al.address='%u' AND al.enabled)) UNION (SELECT al.address || '@' || dom.name FROM admin_alias al INNER JOIN admin_domain dom ON al.domain_id=dom.id WHERE al.id IN (SELECT al_al.to_alias_id FROM admin_alias_aliases al_al INNER JOIN admin_alias al ON al_al.from_alias_id=al.id INNER JOIN admin_domain dom ON al.domain_id=dom.id WHERE dom.name='%d' AND dom.enabled AND al.address='%u' AND al.enabled)) UNION (SELECT al.extmboxes FROM admin_alias al INNER JOIN admin_domain dom ON al.domain_id=dom.id WHERE dom.name='%d' AND dom.enabled AND al.address='%u' AND al.enabled AND al.extmboxes<>'')"
|
||||
sqlite = "(SELECT (mb.address || '@' || dom.name) FROM admin_mailbox mb INNER JOIN admin_domain dom ON mb.domain_id=dom.id WHERE mb.id IN (SELECT al_mb.mailbox_id FROM admin_alias_mboxes al_mb INNER JOIN admin_alias al ON al_mb.alias_id=al.id INNER JOIN admin_domain dom ON al.domain_id=dom.id WHERE dom.name='%d' AND dom.enabled=1 AND al.address='%u' AND al.enabled=1)) UNION (SELECT (al.address || '@' || dom.name) FROM admin_alias al INNER JOIN admin_domain dom ON al.domain_id=dom.id WHERE al.id IN (SELECT al_al.to_alias_id FROM admin_alias_aliases al_al INNER JOIN admin_alias al ON al_al.from_alias_id=al.id INNER JOIN admin_domain dom ON al.domain_id=dom.id WHERE dom.name='%d' AND dom.enabled=1 AND al.address='%u' AND al.enabled=1)) UNION (SELECT al.extmboxes FROM admin_alias al INNER JOIN admin_domain dom ON al.domain_id=dom.id WHERE dom.name='%d' AND dom.enabled=1 AND al.address='%u' AND al.enabled=1 AND al.extmboxes<>'')"
|
||||
|
||||
|
||||
class DomainAliasesMailboxesMap(MapFile):
|
||||
filename = 'sql-domain-aliases-mailboxes.cf'
|
||||
mysql = "(SELECT concat(mb.address, '@', dom.name) FROM admin_domainalias domal INNER JOIN admin_domain dom ON domal.target_id=dom.id INNER JOIN admin_mailbox mb ON mb.domain_id=dom.id WHERE domal.name='%d' AND dom.enabled=1 AND mb.address='%u') UNION (SELECT concat(al.address, '@', dom.name) FROM admin_domainalias domal INNER JOIN admin_domain dom ON domal.target_id=dom.id INNER JOIN admin_alias al ON al.domain_id=dom.id WHERE domal.name='%d' AND dom.enabled=1 AND al.address='%u')"
|
||||
postgres = "(SELECT mb.address || '@' || dom.name FROM admin_domainalias domal INNER JOIN admin_domain dom ON domal.target_id=dom.id INNER JOIN admin_mailbox mb ON mb.domain_id=dom.id WHERE domal.name='%d' AND dom.enabled AND mb.address='%u') UNION (SELECT al.address || '@' || dom.name FROM admin_domainalias domal INNER JOIN admin_domain dom ON domal.target_id=dom.id INNER JOIN admin_alias al ON al.domain_id=dom.id WHERE domal.name='%d' AND dom.enabled AND al.address='%u')"
|
||||
sqlite = "(SELECT mb.address || '@' || dom.name FROM admin_domainalias domal INNER JOIN admin_domain dom ON domal.target_id=dom.id INNER JOIN admin_mailbox mb ON mb.domain_id=dom.id WHERE domal.name='%d' AND dom.enabled=1 AND mb.address='%u') UNION (SELECT al.address || '@' || dom.name FROM admin_domainalias domal INNER JOIN admin_domain dom ON domal.target_id=dom.id INNER JOIN admin_alias al ON al.domain_id=dom.id WHERE domal.name='%d' AND dom.enabled=1 AND al.address='%u')"
|
||||
|
||||
|
||||
class CatchallAliasesMap(MapFile):
|
||||
filename = 'sql-catchall-aliases.cf'
|
||||
mysql = "(SELECT concat(mb.address, '@', dom.name) FROM admin_mailbox mb INNER JOIN admin_domain dom ON mb.domain_id=dom.id WHERE mb.id IN (SELECT al_mb.mailbox_id FROM admin_alias al INNER JOIN admin_domain dom ON al.domain_id=dom.id INNER JOIN admin_alias_mboxes al_mb ON al.id=al_mb.alias_id WHERE al.enabled=1 AND al.address='*' AND dom.name='%d' AND dom.enabled=1)) UNION (SELECT al.extmboxes FROM admin_alias al INNER JOIN admin_domain dom ON al.domain_id=dom.id WHERE al.enabled='1' AND al.extmboxes<>'' AND al.address='*' AND dom.name='%d' AND dom.enabled=1)"
|
||||
postgres = "(SELECT mb.address || '@' || dom.name FROM admin_mailbox mb INNER JOIN admin_domain dom ON mb.domain_id=dom.id WHERE mb.id IN (SELECT al_mb.mailbox_id FROM admin_alias al INNER JOIN admin_domain dom ON al.domain_id=dom.id INNER JOIN admin_alias_mboxes al_mb ON al.id=al_mb.alias_id WHERE al.enabled AND al.address='*' AND dom.name='%d' AND dom.enabled)) UNION (SELECT al.extmboxes FROM admin_alias al INNER JOIN admin_domain dom ON al.domain_id=dom.id WHERE al.enabled AND al.extmboxes<>'' AND al.address='*' AND dom.name='%d' AND dom.enabled)"
|
||||
sqlite = "(SELECT (mb.address || '@' || dom.name) FROM admin_mailbox mb INNER JOIN admin_domain dom ON mb.domain_id=dom.id WHERE mb.id IN (SELECT al_mb.mailbox_id FROM admin_alias al INNER JOIN admin_domain dom ON al.domain_id=dom.id INNER JOIN admin_alias_mboxes al_mb ON al.id=al_mb.alias_id WHERE al.enabled=1 AND al.address='*' AND dom.name='%d' AND dom.enabled=1)) UNION (SELECT al.extmboxes FROM admin_alias al INNER JOIN admin_domain dom ON al.domain_id=dom.id WHERE al.enabled='1' AND al.extmboxes<>'' AND al.address='*' AND dom.name='%d' AND dom.enabled=1)"
|
||||
|
||||
|
||||
class MaintainMap(MapFile):
|
||||
filename = 'sql-maintain.cf'
|
||||
mysql = "SELECT '450 Requested mail action not taken: mailbox unavailable' FROM admin_mailbox mb INNER JOIN admin_domain dom ON mb.domain_id=dom.id INNER JOIN admin_mailboxoperation mbop ON mbop.mailbox_id=mb.id WHERE dom.name='%d' AND mb.address='%u' LIMIT 1"
|
||||
postgres = "SELECT '450 Requested mail action not taken: mailbox unavailable' FROM admin_mailbox mb INNER JOIN admin_domain dom ON mb.domain_id=dom.id INNER JOIN admin_mailboxoperation mbop ON mbop.mailbox_id=mb.id WHERE dom.name='%d' AND mb.address='%u' LIMIT 1"
|
||||
sqlite = "SELECT '450 Requested mail action not taken: mailbox unavailable' FROM admin_mailbox mb INNER JOIN admin_domain dom ON mb.domain_id=dom.id INNER JOIN admin_mailboxoperation mbop ON mbop.mailbox_id=mb.id WHERE dom.name='%d' AND mb.address='%u' LIMIT 1"
|
||||
|
||||
|
||||
class TransportMap(MapFile):
|
||||
@@ -76,6 +118,7 @@ class TransportMap(MapFile):
|
||||
filename = 'sql-transport.cf'
|
||||
mysql = "SELECT method FROM postfix_autoreply_transport WHERE domain='%s'"
|
||||
postgres = "SELECT method FROM postfix_autoreply_transport WHERE domain='%s'"
|
||||
sqlite = "SELECT method FROM postfix_autoreply_transport WHERE domain='%s'"
|
||||
|
||||
|
||||
class AutoRepliesMap(MapFile):
|
||||
@@ -83,6 +126,7 @@ class AutoRepliesMap(MapFile):
|
||||
filename = 'sql-autoreplies.cf'
|
||||
mysql = "SELECT full_address, autoreply_address FROM postfix_autoreply_alias WHERE full_address='%s'"
|
||||
postgres = "SELECT full_address, autoreply_address FROM postfix_autoreply_alias WHERE full_address='%s'"
|
||||
sqlite = "SELECT full_address, autoreply_address FROM postfix_autoreply_alias WHERE full_address='%s'"
|
||||
|
||||
|
||||
class PostfixMapsCommand(Command):
|
||||
@@ -90,30 +134,23 @@ class PostfixMapsCommand(Command):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(PostfixMapsCommand, self).__init__(*args, **kwargs)
|
||||
self._parser.add_argument('destdir', type=str,
|
||||
help='Directory that will contain generated map files')
|
||||
self._parser.add_argument('--dbtype', type=str, choices=['mysql', 'postgres'], default='mysql',
|
||||
help='Used database type')
|
||||
self._parser.add_argument('--dbhost', type=str, default='127.0.0.1',
|
||||
help='Database host address')
|
||||
self._parser.add_argument('--categories', type=str, nargs='*', default=['std'],
|
||||
help='Map file categories to generate (choices: std, autoreply)')
|
||||
self._parser.add_argument(
|
||||
'destdir', type=str,
|
||||
help='Directory that will contain generated map files'
|
||||
)
|
||||
self._parser.add_argument(
|
||||
'--dbtype', type=str, choices=['mysql', 'postgres', 'sqlite'],
|
||||
default='mysql',
|
||||
help='Used database type'
|
||||
)
|
||||
self._parser.add_argument(
|
||||
'--categories', type=str, nargs='*', default=['std'],
|
||||
help='Map file categories to generate (choices: std, autoreply)'
|
||||
)
|
||||
|
||||
def handle(self, parsed_args):
|
||||
dbname = raw_input('Database name: ')
|
||||
dbuser = raw_input('Username: ')
|
||||
dbpass = getpass.getpass('Password: ')
|
||||
|
||||
try:
|
||||
os.mkdir(parsed_args.destdir)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
for k, v in globals().iteritems():
|
||||
if not inspect.isclass(v) or not issubclass(v, MapFile):
|
||||
continue
|
||||
if not v.category in parsed_args.categories:
|
||||
continue
|
||||
v().render(parsed_args.destdir, parsed_args.dbtype,
|
||||
dbname=dbname, dbuser=dbuser, dbpassword=dbpass,
|
||||
dbhost=parsed_args.dbhost)
|
||||
if parsed_args.dbtype == 'sqlite':
|
||||
g = SQLiteMapFilesGenerator()
|
||||
else:
|
||||
g = MapFilesGenerator()
|
||||
g.render(parsed_args)
|
||||
|
||||
Reference in New Issue
Block a user