Version 0.6 !!

This commit is contained in:
tonio
2009-06-19 13:54:05 +02:00
parent 968122d50b
commit 55f6c56c9f
19 changed files with 280 additions and 47 deletions
+75 -7
View File
@@ -1,3 +1,4 @@
:q
Installation
============
@@ -31,6 +32,17 @@ Run the initialisation script. It will insert needed data into the database :
export PYTHONPATH=$PWD/..
DJANGO_SETTINGS_MODULE=mailng.settings ./scripts/populate.py
How to upgrade
--------------
0.5 -> 0.6 : No modifications have been made to the core SQL schema so you
just have to decompress the new tarball at the same location than your
current installation. Once done, go to MailNG repository and run::
python manage.py syncdb
You must also modify 'settings.py' in order to activate new components.
Host configuration
------------------
@@ -109,20 +121,71 @@ Then, use the following configuration in your /etc/postfix/main.cf file
virtual_alias_maps = mysql:/etc/postfix/sql-aliases.cf
# Stuff after
NB: Mailng only supports maildir format for now. Others will surely be
added soon.
NB: Mailng supports both maildir and mbox formats. You can specify
which format to use by modifying the MAILBOX_TYPE variable located
inside 'settings.py'.
Tips to activate auto-reply messages in Postifx
-----------------------------------------------
Since version 0.6, mail users can define an auto-reply message with MailNG.
To make Postfix understand this feature, you need to update your configuration
files as follow::
# /etc/postfix/main.cf
transport_maps = mysql:/etc/postfix/maps/sql-transport.cf
virtual_alias_maps = mysql:/etc/postfix/maps/sql-aliases.cf
mysql:/etc/postfix/maps/sql-autoreplies.cf
# /etc/postfix/master.cf
autoreply unix - n n - - pipe
flags= user=nobody argv=<path_to_mailng>/scripts/autoreply $sender $mailbox
Then, create new map files with the following content::
# /etc/postfix/maps/sql-transport.cf
user = <user>
password = <password>
dbname = <database>
hosts = 127.0.0.1
query = SELECT method FROM postfix_autoreply_transport WHERE domain='%s'
# /etc/postfix/maps/sql-autoreplies.cf
user = <user>
password = <password>
dbname = <database>
hosts = 127.0.0.1
query = SELECT full_address, autoreply_address FROM postfix_autoreply_alias WHERE full_address='%s'
NB: auto-reply messages are just sent one time per sender for a
pre-defined time period. By default, this period is equal to 1 day
(86400s), you can adjust this value by modifying the AUTOREPLY_TIMEOUT
variable located inside 'settings.py'.
NB: Be sure that both 'autoreply' and 'autoreply.py' scripts (located
inside the 'scripts' directory) have good permissions (ie. 0755).
Tips to link Mailng with dovecot
--------------------------------
Edit your main Dovecot config file (/etc/dovecot/dovecot.conf) and put the
If you are using 'maildir' format to store mailboxes, add the
following line inside your main Dovecot config file
(/etc/dovecot/dovecot.conf)::
mail_location = maildir:<path_to_mailboxes>/%d/%n/.maildir
If you are using 'mbox' format, put the following::
mail_location = mbox:<path_to_mailboxes>/%d/%n/:INBOX=<path_to_mailboxes>/%d/%n/Inbox
To make the authentication work, edit 'dovecot.conf' and add the
following inside::
auth default {
# ... stuff before
passdb sql {
# Path for SQL configuration file, see /etc/dovecot/dovecot-sql.conf for
# Path for SQL configuration file, see /etc/dovecot/dovecot-sql.conf for
# example
args = /etc/dovecot/dovecot-sql.conf
}
@@ -155,23 +218,28 @@ Put the following lines inside your dovecot.conf file::
mail_plugins = quota quota_imap
}
Before continuing, you need to know which quota backend must be user
(function of mailboxes format)::
* 'mbox' : backend=dirsize,
* 'maildir' : backend=maildir.
If you use version prior to 1.1, add also the following configuration::
plugin {
# 10 MB default quota limit
quota = maildir:storage=10240
quota = <backend>:storage=10240
}
Then modify the above user_query inside dovecot-sql.conf file like
that to activate per user quotas::
user_query = SELECT path AS home, uid, gid, concat('maildir:storage=', quota / 1024) AS quota FROM admin_mailbox WHERE full_address = '%u'
user_query = SELECT path AS home, uid, gid, concat('<backend>:storage=', quota / 1024) AS quota FROM admin_mailbox WHERE full_address = '%u'
For version >= 1.1, put the following configuration inside dovecot.conf file::
plugin {
# Default 10M storage limit with an extra 5M limit when saving to Trash.
quota = maildir:User quota
quota = <backend>:User quota
quota_rule = *:storage=10M
quota_rule2 = Trash:storage=5M
}
+8 -8
View File
@@ -18,9 +18,7 @@ class Domain(models.Model):
def create_dir(self):
path = "%s/%s" % (settings.STORAGE_PATH, self.name)
if exec_as_vuser("mkdir %s" % path):
return False
return True
return exec_as_vuser("mkdir %s" % path)
def rename_dir(self, newname):
code, output = exec_pipe("sudo -u %s mv %s/%s %s/%s" \
@@ -74,14 +72,16 @@ class Mailbox(models.Model):
except AttributeError:
mbtype = "maildir"
if mbtype == "mbox":
template = ["Inbox", "Drafts", "Sent", "Trash", "Junk"]
for dir in template:
exec_as_vuser("touch %s/%s" % (path, dir))
self.path = "%s/%s/Inbox" % (domain.name, self.address)
else:
template = [".Drafts/", ".Sent/", ".Trash/", ".Junk/"]
for dir in template:
for sdir in ["cur", "new", "tmp"]:
exec_as_vuser("mkdir -p %s/%s/%s" % (path, dir, sdir))
self.path = "%s/%s/" % (domain.name, self.address)
else:
exec_as_vuser("mkdir %s/.maildir/" % path)
exec_as_vuser("mkdir -p %s/.maildir/%s/%s" % (path, dir, sdir))
self.path = "%s/%s/.maildir/" % (domain.name, self.address)
return True
+7
View File
@@ -14,6 +14,7 @@ from mailng.admin.models import Domain, Mailbox, Alias
from forms import MailboxForm, DomainForm, AliasForm, PermissionForm
from mailng.lib.authbackends import crypt_password
from mailng.lib import _render, _ctx_ok, _ctx_ko
from mailng.lib import events
def is_superuser(user):
if not user.is_superuser:
@@ -50,6 +51,7 @@ def newdomain(request):
domain = form.save(commit=False)
if domain.create_dir():
form.save()
events.raiseEvent("CreateDomain", dom=domain)
ctx = _ctx_ok(reverse(admin.views.domains))
return HttpResponse(simplejson.dumps(ctx),
mimetype="application/json")
@@ -98,6 +100,7 @@ def editdomain(request, dom_id):
@permission_required("admin.delete_domain")
def deldomain(request, dom_id):
domain = Domain.objects.get(pk=dom_id)
events.raiseEvent("DeleteDomain", dom=domain)
domain.delete_dir()
domain.delete()
return HttpResponseRedirect('/mailng/admin/')
@@ -157,6 +160,9 @@ def newmailbox(request, dom_id=None):
mb.quota = domain.quota
mb.full_address = "%s@%s" % (mb.address, domain.name)
mb.save()
events.raiseEvent("CreateMailbox", mbox=mb)
ctx = _ctx_ok(reverse(admin.views.mailboxes, args=[domain.id]))
return HttpResponse(simplejson.dumps(ctx),
mimetype="application/json")
@@ -221,6 +227,7 @@ def editmailbox(request, dom_id, mbox_id=None):
@permission_required("admin.delete_mailbox")
def delmailbox(request, dom_id, mbox_id=None):
mb = Mailbox.objects.get(pk=mbox_id)
events.raiseEvent("DeleteMailbox", mbox=mb)
mb.delete_dir()
mb.user.delete()
mb.delete()
+14
View File
@@ -0,0 +1,14 @@
# -*- coding: utf-8 -*-
import os
import re
def loadextensions():
from django.conf import settings
expr = re.compile("mailng\.extensions\.(.+)")
for app in settings.INSTALLED_APPS:
m = expr.match(app)
if not m:
continue
module = __import__(m.group(1), globals(), locals(), ['main'])
module.main.init()
+42
View File
@@ -0,0 +1,42 @@
# -*- coding: utf-8 -*-
"""
Postfix auto-replies plugin.
This module provides a way to integrate MailNG auto-reply
functionality into Postfix.
"""
from mailng.lib import events
from models import Transport, Alias
def init():
events.register("CreateDomain", onCreateDomain)
events.register("DeleteDomain", onDeleteDomain)
events.register("CreateMailbox", onCreateMailbox)
events.register("DeleteMailbox", onDeleteMailbox)
def onCreateDomain(**kwargs):
dom = kwargs["dom"]
transport = Transport()
transport.domain = "autoreply.%s" % dom.name
transport.method = "autoreply:"
transport.save()
def onDeleteDomain(**kwargs):
dom = kwargs["dom"]
trans = Transport.objects.get(domain="autoreply.%s" % dom.name)
trabs.delete()
def onCreateMailbox(**kwargs):
mbox = kwargs["mbox"]
alias = Alias()
alias.full_address = mbox.full_address
alias.autoreply_address = \
"%s@autoreply.%s" % (mbox.full_address, mbox.domain.name)
alias.save()
def onDeleteMailbox(**kwargs):
mbox = kwargs["mbox"]
alias = Alias.objects.get(full_address=mbox.full_address)
alias.delete()
+10
View File
@@ -0,0 +1,10 @@
from django.db import models
from mailng.admin.models import Domain, Mailbox
class Transport(models.Model):
domain = models.CharField(max_length=300)
method = models.CharField(max_length=255)
class Alias(models.Model):
full_address = models.CharField(max_length=255)
autoreply_address = models.CharField(max_length=255)
+29
View File
@@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
"""
This module provides a simple way of managing events between MailNG
core application and additional components.
"""
events = ["CreateDomain",
"DeleteDomain",
"CreateMailbox",
"DeleteMailbox"]
callbacks = {}
def register(event, callback):
if not event in events:
return 0
if not event in callbacks.keys():
callbacks[event] = []
callbacks[event].append(callback)
return 1
def raiseEvent(event, **kwargs):
if not event in events or not event in callbacks.keys():
return 0
for callback in callbacks[event]:
callback(**kwargs)
return 1
+43 -22
View File
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2009-06-17 10:13+0200\n"
"POT-Creation-Date: 2009-06-19 10:29+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Antoine Nguyen <tonio@ngyn.org>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -25,11 +25,11 @@ msgstr ""
msgid "Password"
msgstr "Mot de passe"
#: admin/forms.py:18
#: admin/forms.py:18 main/forms.py:21
msgid "Confirmation"
msgstr ""
#: admin/forms.py:32
#: admin/forms.py:32 main/forms.py:36
msgid "Passwords mismatch"
msgstr "Les mots de passe diffèrent"
@@ -54,43 +54,43 @@ msgstr "Super administrateur"
msgid "Domain administrator"
msgstr "Admin. de domaine"
#: admin/models.py:9 admin/models.py:48
#: admin/models.py:9 admin/models.py:46
msgid "name"
msgstr "Nom"
#: admin/models.py:11 admin/models.py:112 main/models.py:9
#: admin/models.py:11 admin/models.py:110 main/models.py:9
msgid "enabled"
msgstr "Activé"
#: admin/models.py:49 admin/models.py:109
#: admin/models.py:47 admin/models.py:107
msgid "address"
msgstr "Adresse"
#: admin/models.py:51
#: admin/models.py:49
msgid "password"
msgstr "Mot de passe"
#: admin/models.py:111
#: admin/models.py:109
msgid "mailbox"
msgstr "Boite aux lettres"
#: admin/views.py:26
#: admin/views.py:21
msgid "Permission denied."
msgstr "Permission refusée."
#: admin/views.py:54 admin/views.py:85
#: admin/views.py:49 admin/views.py:81
msgid "Domain with this name already defined"
msgstr "Un domaine avec ce nom existe déjà"
#: admin/views.py:62
#: admin/views.py:58
msgid "Failed to initialise domain, check permissions"
msgstr "Impossible d'initialiser le domaine, vérifier les permissions"
#: admin/views.py:88
#: admin/views.py:84
msgid "Failed to rename domain, check permissions"
msgstr "Impossible de renommer le domaine, vérifier les permissions"
#: admin/views.py:138 admin/views.py:191
#: admin/views.py:135 admin/views.py:191
msgid "Mailbox with this address already exists"
msgstr "Une boite aux lettres pour cette adresse existe déjà"
@@ -103,7 +103,7 @@ msgstr ""
msgid "Failed to rename mailbox, check permissions"
msgstr "Impossible de renommer la boite aux lettres, vérifier les permissions."
#: admin/views.py:261 admin/views.py:290
#: admin/views.py:262 admin/views.py:291
msgid "Alias with this address already exists"
msgstr "Un alias avec cette adresse existe déjà"
@@ -115,6 +115,18 @@ msgstr "Activé"
msgid "enabled_f"
msgstr "Activée"
#: main/forms.py:17
msgid "Old password"
msgstr "Ancien mot de passe"
#: main/forms.py:19
msgid "New password"
msgstr "Nouveau mot de passe"
#: main/forms.py:31
msgid "Old password mismatchs"
msgstr "L'ancien mot de passe est incorrect"
#: main/models.py:7
msgid "subject"
msgstr "sujet"
@@ -123,7 +135,7 @@ msgstr "sujet"
msgid "content"
msgstr "contenu"
#: main/views.py:34
#: main/views.py:45
msgid "Auto reply message updated successfully."
msgstr "Message de réponse auto. mis à jour."
@@ -237,7 +249,8 @@ msgid "yes,no"
msgstr "oui,non"
#: templates/admin/editalias.html:14 templates/admin/editdomain.html:15
#: templates/admin/editmailbox.html:16 templates/main/autoreply.html:16
#: templates/admin/editmailbox.html:16 templates/main/autoreply.html:17
#: templates/main/chpassword.html:15
msgid "Update"
msgstr "Mettre à jour"
@@ -297,15 +310,23 @@ msgstr "Aucun admin de domaine défini."
msgid "Permissions"
msgstr ""
#: templates/main/header.html:5
msgid "General"
msgstr "Général"
#: templates/main/menu.html:5
#: templates/main/chpassword.html:7 templates/main/menu.html:13
msgid "Change password"
msgstr "Changer de mot de passe"
#: templates/main/menu.html:10
#: templates/main/header.html:8
msgid "General"
msgstr "Général"
#: templates/main/index.html:11
msgid "Your auto-reply message is activated."
msgstr "Votre réponse automatique est active."
#: templates/main/index.html:13
msgid "Your auto-reply message is not activated."
msgstr "Votre réponse automatique n'est pas active."
#: templates/main/menu.html:6
msgid "Auto-reply message"
msgstr "Message de réponse automatique"
+7 -2
View File
@@ -13,11 +13,16 @@ from mailng.lib import _render, _ctx_ok, _ctx_ko
from mailng.lib.authbackends import crypt_password
from forms import ARmessageForm, ChangePasswordForm
from models import ARmessage
from admin.models import Mailbox
from mailng.admin.models import Mailbox
@login_required
def index(request):
return _render(request, "main/index.html", {})
mb = Mailbox.objects.get(user=request.user.id)
try:
arm = ARmessage.objects.filter(mbox=mb.id, enabled=True)
except ARmessage.DoesNotExist:
arm = None
return _render(request, "main/index.html", {"arm" : arm})
@login_required
def autoreply(request):
+7
View File
@@ -0,0 +1,7 @@
#!/bin/sh
BASEDIR=/home/tonio
export PYTHONPATH=$BASEDIR
export DJANGO_SETTINGS_MODULE=mailng.settings
$BASEDIR/mailng/scripts/autoreply.py $1 $2
+7 -1
View File
@@ -2,6 +2,7 @@
# -*- coding: utf-8 -*-
import sys
import smtplib
from email.mime.text import MIMEText
import datetime
from django.conf import settings
@@ -38,7 +39,12 @@ if __name__ == "__main__":
msg['Subject'] = armessage.subject
msg['From'] = mailbox
msg['To'] = sender
print msg
s = smtplib.SMTP()
s.connect()
s.sendmail(mailbox, sender, msg.as_string())
s.quit()
lastar.last_sent = datetime.datetime.now()
lastar.save()
sys.exit(0)
+3
View File
@@ -80,6 +80,9 @@ INSTALLED_APPS = (
'django.contrib.sites',
'mailng.admin',
'mailng.main'
# MailNG extensions here.
# 'mailng.extensions.postfix_autoreply'
)
AUTHENTICATION_BACKENDS = (
+5
View File
@@ -0,0 +1,5 @@
window.addEvent('domready', function() {
SqueezeBox.assign($$('a.boxed'), {
parse: 'rel'
});
});
Binary file not shown.

After

Width:  |  Height:  |  Size: 863 B

+5
View File
@@ -297,4 +297,9 @@ body {
color: green;
font-weight: bold;
margin-right: 10px;
}
.info {
float: left;
font-style: italic;
}
+9 -1
View File
@@ -5,5 +5,13 @@
{% menu "" perms %}
{% endblock %}
{% block subcontent %}
<div class="info">
<img src="/static/pics/info.png" border="0" />
{% if arm %}
{% trans "Your auto-reply message is activated." %}
{% else %}
{% trans "Your auto-reply message is not activated." %}
{% endif %}
</div>
{% endblock %}
+6 -6
View File
@@ -1,15 +1,15 @@
{% load i18n %}
<ul>
{% url main.views.changepassword as chpwd_url %}
<li><a href="{{ chpwd_url }}"
class="boxed" rel="{handler:'iframe',size:{x:350,y:220}}">
<img src="/static/pics/edit.png" border="0"/>
{% trans "Change password" %}</a>
</li>
<li {% ifequal selection "autoreply" %}class="selected"{% endifequal %}>
{% url main.views.autoreply as ar_url %}
<a href="{{ ar_url }}"><img src="/static/pics/auto-reply.png" border="0"/>
{% trans "Auto-reply message" %}
</a>
</li>
{% url main.views.changepassword as chpwd_url %}
<li><a href="{{ chpwd_url }}"
class="boxed" rel="{handler:'iframe',size:{x:350,y:220}}">
<img src="/static/pics/edit.png" border="0"/>
{% trans "Change password" %}</a>
</li>
</ul>
+3
View File
@@ -5,6 +5,9 @@ from django.conf import settings
# from django.contrib import admin
# admin.autodiscover()
from mailng.extensions import loadextensions
loadextensions()
urlpatterns = patterns('',
# Example:
# (r'^mailng/', include('mailng.foo.urls')),