diff --git a/INSTALL b/INSTALL
index f61245c1d..71fc3d0ef 100644
--- a/INSTALL
+++ b/INSTALL
@@ -544,6 +544,12 @@ they already exist) the following parameters::
virtual_transport = dovecot
dovecot_destination_recipient_limit = 1
+Then, edit the */etc/postfix/master.cf* file and add the following
+definition at the end::
+
+ dovecot unix - n n - - pipe
+ flags=DRhu user=vmail:vmail argv=/usr/lib/dovecot/deliver -f ${sender} -d ${recipient}
+
If you have followed the :ref:`postfix-label` section to install your
environnement, you need to modify the SQL query corresponding to the
``virtual_mailbox_maps`` parameter. Edit the
diff --git a/admin/__init__.py b/admin/__init__.py
index 1003d4e9d..c886038f4 100644
--- a/admin/__init__.py
+++ b/admin/__init__.py
@@ -24,22 +24,27 @@ parameters.register_admin("PASSWORD_SCHEME", type="list", deflt="crypt",
parameters.register_admin("ITEMS_PER_PAGE", type="int", deflt=30,
help=_("Number of displayed items per page"))
-#
-# Quick fix for #184
-#
-# Just catch the DatabaseError exception raised when runnning the
-# first ``syncdb`` command.
-#
-try:
- enabled_extensions = list(Extension.objects.filter(enabled=True))
-except DatabaseError:
- enabled_extensions = []
+def enabled_applications():
+ """Return the list of currently enabled extensions
+
+ Quick fix for #184:
+
+ Just catch the DatabaseError exception raised when runnning the
+ first ``syncdb`` command.
+
+ :return: a list
+ """
+ result = [("admin", "admin"), ("userprefs", "userprefs")]
+ try:
+ exts = list(Extension.objects.filter(enabled=True))
+ except DatabaseError:
+ exts = []
+ result += map(lambda ext: (ext.name, ext.name), exts)
+ return sorted(result)
parameters.register_admin("DEFAULT_TOP_REDIRECTION", type="list", deflt="admin",
app="general",
- values=sorted([("admin", "admin"), ("userprefs", "userprefs")] \
- + map(lambda ext: (ext.name, ext.name),
- enabled_extensions)),
+ values=enabled_applications(),
help=_("The default redirection used when no application is specified"))
def unset_default_topredirection(**kwargs):
@@ -51,4 +56,14 @@ def unset_default_topredirection(**kwargs):
if topredirection == kwargs["ext"].name:
parameters.save_admin("DEFAULT_TOP_REDIRECTION", "userprefs", app="general")
+def update_available_applications(**kwargs):
+ """Simple callback to update the list of available applications
+
+ Must be called each time an extension is disabled/enabled.
+ """
+ parameters.update_admin("DEFAULT_TOP_REDIRECTION", app="general",
+ values=enabled_applications())
+
events.register("ExtDisabled", unset_default_topredirection)
+events.register("ExtDisabled", update_available_applications)
+events.register("ExtEnabled", update_available_applications)
diff --git a/admin/views.py b/admin/views.py
index a6f39b6d5..7c7b56472 100644
--- a/admin/views.py
+++ b/admin/views.py
@@ -596,16 +596,16 @@ def saveextensions(request):
parts = k.split("_", 1)
dbext = Extension.objects.get(name=parts[1])
if not dbext in actived_exts:
- dbext.on()
dbext.enabled = True
dbext.save()
+ dbext.on()
else:
found += [dbext]
for ext in actived_exts:
if not ext in found:
- ext.off()
ext.enabled = False
ext.save()
+ ext.off()
messages.info(request, _("Modifications applied."), fail_silently=True)
return HttpResponseRedirect(reverse(admin.views.viewextensions))
diff --git a/extensions/webmail/static/js/webmail.js b/extensions/webmail/static/js/webmail.js
index 09fd0c762..16e520fc9 100644
--- a/extensions/webmail/static/js/webmail.js
+++ b/extensions/webmail/static/js/webmail.js
@@ -782,11 +782,10 @@ function sendmail_callback(evt) {
function compose_callback(resp) {
wm_updatelisting(resp);
- window.addEvent("resize", resize_window_callback);
-
var editormode = resp.editor;
if (editormode == "html") {
+ window.addEvent("resize", resize_window_callback);
var instance = CKEDITOR.instances[editorid];
if (instance) {
CKEDITOR.remove(instance);
diff --git a/lib/events.py b/lib/events.py
index 434dd358a..732ea08bc 100644
--- a/lib/events.py
+++ b/lib/events.py
@@ -1,6 +1,9 @@
# -*- coding: utf-8 -*-
"""
+:mod:`events` --- simple events handling
+----------------------------------------
+
This module provides a simple way of managing events between Modoboa
core application and additional components.
diff --git a/lib/parameters.py b/lib/parameters.py
index 2e01e6d23..59ddc6e25 100644
--- a/lib/parameters.py
+++ b/lib/parameters.py
@@ -36,7 +36,12 @@ def __is_defined(app, level, name):
def __register(app, level, name, **kwargs):
"""Register a new parameter.
- app corresponds to a core component (admin, main) or an extension.
+ ``app`` corresponds to a core component (admin, main) or to an
+ extension.
+
+ :param name: the application's name
+ :param level: the level this parameter is available from
+ :param name: the parameter's name
"""
if not app in _params.keys():
_params[app] = {}
@@ -53,7 +58,24 @@ def __register(app, level, name, **kwargs):
for k, v in kwargs.iteritems():
_params[app][level][name][k] = v
+def __update(app, level, name, **kwargs):
+ """Update a parameter's definition
+
+ :param app: the application's name
+ :param level: the level this parameter is available from
+ :param name: the parameter's name
+ """
+ if not app in _params.keys() or not level in _levels.keys() \
+ or not _params[app][level].has_key(name):
+ return
+ for k, v in kwargs.iteritems():
+ _params[app][level][name][k] = v
+
def __guess_extension():
+ """Tries to guess the application's name by inspecting the stack
+
+ :return: a string or None
+ """
modname = inspect.getmodule(inspect.stack()[2][0]).__name__
m = re.match("(?:modoboa\.)?(?:extensions\.)?([^\.$]+)", modname)
if m:
@@ -61,6 +83,13 @@ def __guess_extension():
return None
def register_admin(name, **kwargs):
+ """Register a new parameter (admin level)
+
+ Each parameter is associated to one application. If no application
+ is provided, the function tries to guess the appropriate one.
+
+ :param name: the parameter's name
+ """
if kwargs.has_key("app"):
app = kwargs["app"]
del kwargs["app"]
@@ -68,6 +97,21 @@ def register_admin(name, **kwargs):
app = __guess_extension()
return __register(app, 'A', name, **kwargs)
+def update_admin(name, **kwargs):
+ """Update a parameter's definition (admin level)
+
+ Each parameter is associated to one application. If no application
+ is provided, the function tries to guess the appropriate one.
+
+ :param name: the parameter's name
+ """
+ if kwargs.has_key("app"):
+ app = kwargs["app"]
+ del kwargs["app"]
+ else:
+ app = __guess_extension()
+ return __update(app, 'A', name, **kwargs)
+
def register_user(name, **kwargs):
if kwargs.has_key("app"):
app = kwargs["app"]
diff --git a/static/js/dynamic_textinput.js b/static/js/dynamic_textinput.js
index 0afd61b72..6e902388b 100644
--- a/static/js/dynamic_textinput.js
+++ b/static/js/dynamic_textinput.js
@@ -3,7 +3,8 @@ var DynamicTextInput = new Class({
Implements: [Options],
options: {
- parentContainer: null
+ parentContainer: null,
+ containerLevel: 1
},
initialize: function(targets, options) {
@@ -68,7 +69,11 @@ var DynamicTextInput = new Class({
"margin-top": "2px"
});
if (!this.options.parentContainer) {
- field[0].inject(this.target.getParent(), "after");
+ var container = this.target;
+ for (var i = 0; i < this.options.containerLevel; i++) {
+ container = container.getParent()
+ }
+ field[0].inject(container, "after");
} else {
field[0].inject(this.options.parentContainer);
}
diff --git a/templates/admin/mbaliasform.html b/templates/admin/mbaliasform.html
index f31802848..3f7e5e8ec 100644
--- a/templates/admin/mbaliasform.html
+++ b/templates/admin/mbaliasform.html
@@ -9,7 +9,9 @@