diff --git a/modoboa/extensions/sievefilters/__init__.py b/modoboa/extensions/sievefilters/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/modoboa/extensions/sievefilters/app_settings.py b/modoboa/extensions/sievefilters/app_settings.py deleted file mode 100644 index c3d1cbb4d..000000000 --- a/modoboa/extensions/sievefilters/app_settings.py +++ /dev/null @@ -1,65 +0,0 @@ -# coding: utf-8 -from django.utils.translation import ugettext_lazy as _ -from django import forms -from sievelib.managesieve import SUPPORTED_AUTH_MECHS -from modoboa.lib.parameters import AdminParametersForm, UserParametersForm -from modoboa.lib.form_utils import SeparatorField, YesNoField, InlineRadioSelect - - -def supported_auth_mechs(): - values = [('AUTO', 'auto')] - for m in SUPPORTED_AUTH_MECHS: - values += [(m, m.lower())] - return values - - -class ParametersForm(AdminParametersForm): - app = "sievefilters" - - sep1 = SeparatorField(label=_("ManageSieve settings")) - - server = forms.CharField( - label=_("Server address"), - initial="127.0.0.1", - help_text=_("Address of your MANAGESIEVE server"), - widget=forms.TextInput(attrs={"class": "form-control"}) - ) - - port = forms.IntegerField( - label=_("Server port"), - initial=4190, - help_text=_("Listening port of your MANAGESIEVE server"), - widget=forms.TextInput(attrs={"class": "form-control"}) - ) - - starttls = YesNoField( - label=_("Connect using STARTTLS"), - initial="no", - help_text=_("Use the STARTTLS extension") - ) - - authentication_mech = forms.ChoiceField( - label=_("Authentication mechanism"), - choices=supported_auth_mechs(), - initial="auto", - help_text=_("Prefered authentication mechanism"), - widget=forms.Select(attrs={"class": "form-control"}) - ) - - -class UserSettings(UserParametersForm): - app = "sievefilters" - - sep1 = SeparatorField(label=_("General")) - - editor_mode = forms.ChoiceField( - initial="gui", - label=_("Editor mode"), - choices=[("raw", "raw"), ("gui", "simplified")], - help_text=_("Select the mode you want the editor to work in"), - widget=InlineRadioSelect(attrs={"type": "checkbox"}) - ) - - @staticmethod - def has_access(user): - return user.mailbox_set.count() != 0 diff --git a/modoboa/extensions/sievefilters/forms.py b/modoboa/extensions/sievefilters/forms.py deleted file mode 100644 index 01e91e98c..000000000 --- a/modoboa/extensions/sievefilters/forms.py +++ /dev/null @@ -1,322 +0,0 @@ -"""Custom forms.""" - -from django import forms -from django.forms.widgets import RadioFieldRenderer, RadioSelect, RadioInput -from django.http import QueryDict -from django.utils.encoding import force_unicode -from django.utils.html import conditional_escape -from django.utils.safestring import mark_safe -from django.utils.translation import ugettext as _, ugettext_lazy - -from modoboa.extensions.admin.templatetags.admin_tags import gender - - -class FiltersSetForm(forms.Form): - name = forms.CharField( - widget=forms.TextInput(attrs={"class": "form-control"}) - ) - active = forms.BooleanField( - label=gender("Active", "m"), required=False, - initial=False, - help_text=ugettext_lazy("Check to activate this filters set") - ) - - -class CustomRadioInput(RadioInput): - - def __unicode__(self): - return self.render() - - def render(self, name=None, value=None, attrs=None, choices=()): - name = name or self.name - value = value or self.value - attrs = attrs or self.attrs - if 'id' in self.attrs: - label_for = ' for="%s_%s"' % (self.attrs['id'], self.index) - else: - label_for = '' - choice_label = conditional_escape(force_unicode(self.choice_label)) - return mark_safe( - u'%s %s' - % (label_for, self.tag(), choice_label) - ) - - -class CustomRadioFieldRenderer(RadioFieldRenderer): - - def __iter__(self): - for i, choice in enumerate(self.choices): - yield CustomRadioInput( - self.name, self.value, self.attrs.copy(), choice, i) - - def __getitem__(self, idx): - choice = self.choices[idx] - return CustomRadioInput( - self.name, self.value, self.attrs.copy(), choice, idx) - - def render(self): - return mark_safe(u'\n'.join([force_unicode(w) for w in self])) - - -class CustomRadioSelect(RadioSelect): - renderer = CustomRadioFieldRenderer - - -class FilterForm(forms.Form): - - def __init__(self, conditions, actions, request, *args, **kwargs): - super(FilterForm, self).__init__(*args, **kwargs) - - self.field_widths = { - "match_type": 8 - } - - self.fields["name"] = forms.CharField(label=_("Name")) - self.fields["match_type"] = forms.ChoiceField( - choices=[("allof", _("All of the following")), - ("anyof", _("Any of the following")), - ("all", _("All messages"))], - initial="anyof", - widget=CustomRadioSelect() - ) - - self.header_operators = [ - ("contains", _("contains"), "string"), - ("notcontains", _("does not contain"), "string"), - ("is", _("is"), "string"), - ("isnot", _("is not"), "string") - ] - - self.cond_templates = [ - {"name": "Subject", - "label": _("Subject"), - "operators": self.header_operators}, - {"name": "From", - "label": _("Sender"), - "operators": self.header_operators}, - {"name": "To", - "label": _("Recipient"), - "operators": self.header_operators}, - {"name": "Cc", - "label": _("Cc"), - "operators": self.header_operators}, - {"name": "size", "label": _("Size"), - "operators": [("over", _("is greater than"), "number"), - ("under", _("is less than"), "number")]}, - ] - - self.action_templates = [ - {"name": "fileinto", "label": _("Move message to"), - "args": [{"type": "list", "vloader": "userfolders"}]}, - {"name": "redirect", "label": _("Redirect message to"), - "args": [{"type": "string"}]}, - ] - - self.conds_cnt = 0 - for c in conditions: - getattr(self, "_build_%s_field" % c[0])(c[1], c[2]) - self.actions_cnt = 0 - for a in actions: - getattr(self, "_build_%s_field" % a[0])(request, a[1]) - - def clean_name(self): - """Check that name does not contain strange chars. - """ - if '#' in self.cleaned_data["name"]: - raise forms.ValidationError(_("Wrong filter name")) - return self.cleaned_data["name"] - - def _build_header_field(self, name, op, value): - targets = [] - ops = [] - vfield = None - for tpl in self.cond_templates: - targets += [(tpl["name"], tpl["label"]), ] - if tpl["name"] != name: - continue - for opdef in tpl["operators"]: - ops += [opdef[:2]] - if op != opdef[0]: - continue - if opdef[2] in ["string", "number"]: - vfield = forms.CharField(max_length=255, initial=value) - - self.fields["cond_target_%d" % self.conds_cnt] = \ - forms.ChoiceField(initial=name, choices=targets) - self.fields["cond_operator_%d" % self.conds_cnt] = \ - forms.ChoiceField(initial=op, choices=ops) - self.fields["cond_value_%d" % self.conds_cnt] = vfield - self.conds_cnt += 1 - - def _build_Subject_field(self, op, value): - self._build_header_field("Subject", op, value) - - def _build_To_field(self, op, value): - self._build_header_field("To", op, value) - - def _build_From_field(self, op, value): - self._build_header_field("From", op, value) - - def _build_Cc_field(self, op, value): - self._build_header_field("Cc", op, value) - - def _build_size_field(self, op, value): - self._build_header_field("size", op, value) - - def _build_action_field(self, request, name, value): - actions = [] - args = None - for tpl in self.action_templates: - actions += [(tpl["name"], tpl["label"]), ] - if name == tpl["name"]: - args = tpl["args"] - self.fields["action_name_%d" % self.actions_cnt] = \ - forms.ChoiceField(initial=name, choices=actions) - for cnt in xrange(0, len(args)): - arg = args[cnt] - aname = "action_arg_%d_%d" % (self.actions_cnt, cnt) - if arg["type"] == "string": - self.fields[aname] = forms.CharField( - max_length=255, - initial=value) - elif arg["type"] == "list": - choices = getattr(self, arg["vloader"])(request) - self.fields[aname] = forms.ChoiceField( - initial=value, - choices=choices) - self.actions_cnt += 1 - - def _build_redirect_field(self, request, value): - self._build_action_field(request, "redirect", value) - - def _build_fileinto_field(self, request, value): - self._build_action_field(request, "fileinto", value) - - def __build_folders_list(self, folders, user, imapc, parentmb=None): - ret = [] - for fd in folders: - value = fd["path"] if "path" in fd else fd["name"] - if parentmb: - ret += [ - (value, fd["name"].replace( - "%s%s" % (parentmb, imapc.hdelimiter), "")) - ] - else: - ret += [(value, fd["name"])] - if "sub" in fd: - submboxes = imapc.getmboxes(user, value, unseen_messages=False) - ret += self.__build_folders_list(submboxes, user, imapc, value) - return ret - - def userfolders(self, request): - from modoboa.extensions.webmail.lib import get_imapconnector - - mbc = get_imapconnector(request) - ret = mbc.getmboxes(request.user, unseen_messages=False) - - folders = self.__build_folders_list(ret, request.user, mbc) - return folders - - def tofilter(self): - conditions = [] - actions = [] - for cpt in xrange(0, self.conds_cnt): - conditions += [(self.cleaned_data["cond_target_%d" % cpt], - ":" + self.cleaned_data["cond_operator_%d" % cpt], - self.cleaned_data["cond_value_%d" % cpt])] - for cpt in xrange(0, self.actions_cnt): - naction = (self.cleaned_data["action_name_%d" % cpt],) - argcpt = 0 - while True: - try: - naction += ( - self.cleaned_data[ - "action_arg_%d_%d" % - (cpt, argcpt)],) - except KeyError: - break - argcpt += 1 - actions += [naction] - - return (conditions, actions) - - -def build_filter_form_from_qdict(request): - conditions = [] - actions = [] - qdict = QueryDict("", mutable=True) - qdict["name"] = request.POST["name"] - qdict["match_type"] = request.POST["match_type"] - cpt = 0 - i = 0 - if qdict["match_type"] != "all": - while True: - if cpt == int(request.POST["conds"]): - break - if "cond_target_%d" % i in request.POST: - qdict["cond_target_%d" % cpt] = ( - request.POST["cond_target_%d" % i] - ) - qdict["cond_operator_%d" % cpt] = ( - request.POST["cond_operator_%d" % i] - ) - qdict["cond_value_%d" % cpt] = request.POST["cond_value_%d" % i] - condtarget = request.POST["cond_target_%d" % i] - condop = request.POST["cond_operator_%d" % i] - condvalue = request.POST["cond_value_%d" % i] - conditions += [(condtarget, condop, condvalue)] - cpt += 1 - i += 1 - cpt = 0 - i = 0 - while True: - if cpt == int(request.POST["actions"]): - break - if "action_name_%d" % i in request.POST: - qdict["action_name_%d" % cpt] = request.POST["action_name_%d" % i] - action = request.POST["action_name_%d" % i] - argcpt = 0 - args = [] - while True: - try: - qdict["action_arg_%d_%d" % (cpt, argcpt)] = \ - request.POST["action_arg_%d_%d" % (i, argcpt)] - args += [request.POST["action_arg_%d_%d" % (i, argcpt)]] - except KeyError: - break - argcpt += 1 - args = [action] + args - actions += [args] - cpt += 1 - i += 1 - - return FilterForm(conditions, actions, request, qdict) - - -def build_filter_form_from_filter(request, name, fobj): - from sievelib.commands import SizeCommand, TrueCommand - - match_type = fobj["test"].name - conditions = [] - for t in fobj["test"]["tests"]: - if isinstance(t, TrueCommand): - match_type = "all" - conditions += [("Subject", "contains", "")] - break - elif isinstance(t, SizeCommand): - conditions += [("size", t["comparator"][1:], t["limit"])] - else: - conditions += [(t["header-names"].strip('"'), - t["match-type"][1:], - t["key-list"].strip('"'))] - actions = [] - for c in fobj.children: - action = (c.name,) - for arg in c.args_definition: - action += (c[arg["name"]].strip('"'),) - actions += [action] - - form = FilterForm(conditions, actions, request) - form.fields["name"].initial = name - form.fields["match_type"].initial = match_type - return form diff --git a/modoboa/extensions/sievefilters/general_callbacks.py b/modoboa/extensions/sievefilters/general_callbacks.py deleted file mode 100644 index c09b73fc4..000000000 --- a/modoboa/extensions/sievefilters/general_callbacks.py +++ /dev/null @@ -1,32 +0,0 @@ -from django.utils.translation import ugettext as _ -from django.core.urlresolvers import reverse -from modoboa.lib import events - - -@events.observe("UserMenuDisplay") -def menu(target, user): - if target != "options_menu": - return [] - if not user.mailbox_set.count(): - return [] - return [ - {"name": "sievefilters", - "label": _("Message filters"), - "url": reverse("sievefilters:index"), - "img": "fa fa-filter"} - ] - - -@events.observe("UserLogout") -def userlogout(request): - from .lib import SieveClient - - if not request.user.mailbox_set.count(): - return - try: - sc = SieveClient(user=request.user.username, - password=request.session["password"]) - except Exception: - pass - else: - sc.logout() diff --git a/modoboa/extensions/sievefilters/lib.py b/modoboa/extensions/sievefilters/lib.py deleted file mode 100644 index 26cf8a2d1..000000000 --- a/modoboa/extensions/sievefilters/lib.py +++ /dev/null @@ -1,107 +0,0 @@ -# coding: utf-8 - -"""Internal tools.""" - -from sievelib.factory import FiltersSet -from sievelib.managesieve import Client, Error -from sievelib.parser import Parser - -from django.utils.translation import ugettext as _ - -from modoboa.lib import parameters -from modoboa.lib.connections import ConnectionsManager, ConnectionError -from modoboa.lib.exceptions import ModoboaException - - -class SieveClientError(ModoboaException): - http_code = 424 - - -class SieveClient(object): - __metaclass__ = ConnectionsManager - - def __init__(self, user=None, password=None): - try: - ret, msg = self.login(user, password) - except Error as e: - raise ConnectionError(str(e)) - if not ret: - raise ConnectionError(msg) - - def login(self, user, password): - self.msc = Client(parameters.get_admin("SERVER"), - int(parameters.get_admin("PORT")), - debug=False) - use_starttls = True if parameters.get_admin("STARTTLS") == "yes" \ - else False - authmech = parameters.get_admin("AUTHENTICATION_MECH") - if authmech == "AUTO": - authmech = None - try: - ret = self.msc.connect(user, password, use_starttls, authmech) - except Error: - ret = False - if not ret: - return False, _( - "Connection to MANAGESIEVE server failed, check your " - "configuration" - ) - return True, None - - def logout(self): - self.msc.logout() - self.msc = None - - def refresh(self, user, password): - import ssl - - if self.msc is not None: - try: - self.msc.capability() - except Error as e: - pass - else: - return - try: - ret, msg = self.login(user, password) - except (Error, ssl.SSLError) as e: - raise ConnectionError(e) - if not ret: - raise ConnectionError(msg) - - def listscripts(self): - return self.msc.listscripts() - - def getscript(self, name, format="raw"): - content = self.msc.getscript(name) - if content is None: - raise SieveClientError(self.msc.errmsg) - if format == "raw": - return content - p = Parser() - if not p.parse(content): - print "Parse error????" - return None - fs = FiltersSet(name) - fs.from_parser_result(p) - return fs - - def pushscript(self, name, content, active=False): - if isinstance(content, unicode): - content = content.encode("utf-8") - if not self.msc.havespace(name, len(content)): - error = "%s (%s)" % ( - _("Not enough space on server"), self.msc.errmsg) - raise SieveClientError(error) - if not self.msc.putscript(name, content): - raise SieveClientError(self.msc.errmsg) - if active and not self.msc.setactive(name): - raise SieveClientError(self.msc.errmsg) - - def deletescript(self, name): - if not self.msc.deletescript(name): - raise SieveClientError(self.msc.errmsg) - - def activatescript(self, name): - if not self.msc.setactive(name): - raise SieveClientError(self.msc.errmsg) diff --git a/modoboa/extensions/sievefilters/modo_extension.py b/modoboa/extensions/sievefilters/modo_extension.py deleted file mode 100644 index 0b4fe46ba..000000000 --- a/modoboa/extensions/sievefilters/modo_extension.py +++ /dev/null @@ -1,24 +0,0 @@ -# coding: utf-8 -"""Declare and register the sievefilters extension.""" - -from django.utils.translation import ugettext_lazy - -from modoboa.core.extensions import ModoExtension, exts_pool -from modoboa.lib import parameters - - -class SieveFilters(ModoExtension): - name = "sievefilters" - label = "Sieve filters" - version = "1.0" - description = ugettext_lazy("Plugin to easily create server-side filters") - url = "sfilters" - available_for_topredirection = True - - def load(self): - from .app_settings import ParametersForm, UserSettings - parameters.register(ParametersForm, ugettext_lazy("Sieve filters")) - parameters.register(UserSettings, ugettext_lazy("Message filters")) - from modoboa.extensions.sievefilters import general_callbacks - -exts_pool.register_extension(SieveFilters) diff --git a/modoboa/extensions/sievefilters/static/sievefilters/css/style.css b/modoboa/extensions/sievefilters/static/sievefilters/css/style.css deleted file mode 100644 index 6ff656c85..000000000 --- a/modoboa/extensions/sievefilters/static/sievefilters/css/style.css +++ /dev/null @@ -1,134 +0,0 @@ -.fset_container { - padding: 0 15px; -} - -#set_content textarea { - width: 100%; - height: 500px; -} - -#set_content label { - margin: 5px; -} - -#filters_list { - border-left: 1px solid #CCC; - position: absolute; - padding-left: 5px; - left: 190px; - right: 10px; - top: 0px; - bottom: 0px; -} - -#id_content { - width: 95% !important; - height: 270px; -} - -/* Filter form */ -#filterform { - margin: 7px; -} - -#filterform h2 { - margin: 0; - padding: 0; - font-size: 1em; - margin-top: 20px; -} - -#submit_container { - width: 100%; - position: absolute; - bottom: 5px; - text-align: center; -} - -#error { - white-space: pre-line; -} - -#addfilterlist { - background-color: #FAFAFA; - border: 1px solid #CCCCCC; - border-radius: 26px 26px 26px 26px; - padding: 14px 5px 5px; -} - -#matchtype { - font-size: 0.9em; -} - - -div.item { - margin-bottom: 10px; - margin-left: 5px; - overflow: auto; -} - -ul.errors { - list-style: none; - display: inline; - margin: 0; - padding: 0; -} - -.errors li { - color: red; - font-weight: bold; - font-size: 0.9em; - display: inline; -} - -.leftbox { - width: 155px; -} - -.leftbox h1 { - float: none !important; - padding: 0; - margin: 0; - font-size: 1.1em; -} - -.leftbox ul { - list-style: none; - padding: 5px 0 0 0; - margin: 0; -} - -.leftbox li { - margin: 5px 0; -} - -.leftbox a, .leftbox a:visited { - color: black; - text-decoration: none; -} - -.leftbox a:hover { - color: #6AB0C5; - text-decoration: none; -} - -.leftbox li.selected { - background-color: #FFFF77; -} - -.leftbox img { - float: left; - margin-right: 5px; -} - -a.green { - text-decoration: none; - font-weight: bold; - color: green; -} - -a.red { - text-decoration: none; - font-weight: bold; - color: red; -} \ No newline at end of file diff --git a/modoboa/extensions/sievefilters/static/sievefilters/js/jquery.dynfields.js b/modoboa/extensions/sievefilters/static/sievefilters/js/jquery.dynfields.js deleted file mode 100644 index 1b6c8a253..000000000 --- a/modoboa/extensions/sievefilters/static/sievefilters/js/jquery.dynfields.js +++ /dev/null @@ -1,339 +0,0 @@ -(function($) { - var DynamicCondition = function(element, options) { - this.$element = $(element); - this.options = $.extend({}, $.fn.dyncondition.defaults, options); - this.fields_cnt = 1; - this.nextid = 1; - - var $addlink = $('', { - href: '#', - id: this.$element.attr("id") + '_rmbtn', - html: '' - }); - $("select[name*=cond_target_]").change($.proxy(this.target_change, this)); - $addlink.click($.proxy(this.addfields, this)); - this.$element.append($addlink); - - for (var cpt = 1; true; cpt++) { - var $div = $("#condition_" + cpt); - - if (!$div.length) { - break; - } - $div.append(this.newrmlink()); - this.nextid++; - this.fields_cnt++; - } - }; - - DynamicCondition.prototype = { - constructor: DynamicCondition, - - loadoperators: function($container, tpl) { - $container.empty(); - for (var ocpt = 0; ocpt < tpl.operators.length; ocpt++) { - var $opt = $("', { - href: '#', - id: 'condition_' + this.nextid + '_rmbtn', - html: '' - }).click($.proxy(this.removefields, this)); - }, - - addfields: function(e) { - e.preventDefault(); - var $div = $("
", { - id: "condition_" + this.nextid, 'class': "item" - }); - var $condtarget = $("", { - id: "id_cond_operator_" + this.nextid, - name: "cond_operator_" + this.nextid, - class: "form-control element-inline-block" - }); - var $condvalue = $("", { - id: "id_cond_value_" + this.nextid, - name: "cond_value_" + this.nextid, - type: "text", - class: "form-control element-inline-block" - }); - var $rmlink = this.newrmlink(); - - for (var cpt = 0; cpt < this.options.templates.length; cpt++) { - var tpl = this.options.templates[cpt]; - var $opt = $("
'); - $condoperator.wrap('
'); - $condvalue.wrap('
'); - this.$element.after($div); - this.nextid++; - this.fields_cnt++; - }, - - target_change: function(e) { - var $target = $(e.target); - var parts = $target.attr("name").split("_"); - var $container = $("#id_cond_operator_" + parts[2]); - - for (var cpt = 0; cpt < this.options.templates.length; cpt++) { - var tpl = this.options.templates[cpt]; - - if (tpl.name != $target.val()) { - continue; - } - this.loadoperators($container, tpl); - break; - } - }, - - counter: function() { - return this.fields_cnt; - } - }; - - $.fn.dyncondition = function(method) { - return this.each(function() { - var $this = $(this), - data = $this.data('dyncondition'), - options = typeof method === "object" && method; - - if (!data) { - $this.data('dyncondition', new DynamicCondition(this, options)); - } - if (typeof method === "string") { - data[method](); - } - }); - }; - - $.fn.dyncondition.defaults = { - defaultcond: "Subject", - templates: [] - }; - -})(jQuery); - -/* - * Dynamic actions class - */ -(function($) { - var DynamicAction = function(element, options) { - this.$element = $(element); - this.options = $.extend({}, $.fn.dynaction.defaults, options); - this.nextid = 1; - this.fields_cnt = 1; - - var $addlink = $('', { - href: '#', - id: this.$element.attr("id") + '_rmbtn', - html: '' - }); - $("select[name*=action_name_]").change($.proxy(this.name_change, this)); - $addlink.click($.proxy(this.addfields, this)); - this.$element.append($addlink); - - for (var cpt = 1; true; cpt++) { - var $div = $("#action_" + cpt); - - if (!$div.length) { - break; - } - $div.append(this.newrmlink()); - this.nextid++; - this.fields_cnt++; - } - - $("#id_action_arg_0_0").find("option").each(function() { - var $this = $(this), - cpt = 1, - start = 0, - value = $this.val(); - - while (true) { - var id = value.indexOf(options.hdelimiter, start); - if (id == -1) { - break; - } - $this.css("margin-left", (cpt * 20) + "px"); - cpt++; - start = id + 1; - } - }); - - this.$fdoptions = $("#id_action_arg_0_0").find("option"); - }; - - DynamicAction.prototype = { - constructor: DynamicAction, - - loadargs: function(id, tpl) { - var res = []; - - for (var acpt = 0; acpt < tpl.args.length; acpt++) { - var argname = "action_arg_" + id + "_" + acpt; - var $child = null; - - if (tpl.args[acpt].type == "list") { - $child = $("", { - type: "text", - id: "id_" + argname, - name: argname, - class: "form-control" - }); - } - res.push($child); - } - return res; - }, - - deletePrevArgs: function(id) { - for (var cpt = 0; true; cpt++) { - var $arg = $("#id_action_arg_" + id + "_" + cpt); - if (!$arg.length) { - break; - } - $arg.remove(); - } - }, - - name_change: function(e) { - var $target = $(e.target); - var parts = $target.attr("name").split("_"); - var $pos = $("#action_" + parts[2] + "_rmbtn"); - - e.preventDefault(); - this.deletePrevArgs(parts[2]); - for (var cpt = 0; cpt < this.options.templates.length; cpt++) { - var tpl = this.options.templates[cpt]; - if (tpl.name != $target.val()) { - continue; - } - $.each(this.loadargs(parts[2], tpl), function(idx, arg) { - $pos.before(arg); - }); - } - }, - - newrmlink: function() { - return $('', { - href: '#', - id: 'action_' + this.nextid + '_rmbtn', - html: '' - }).click($.proxy(this.removefields, this)); - }, - - addfields: function(e) { - e.preventDefault(); - var $div = $("
", {id: "action_" + this.nextid, "class": "item"}); - var $actioname = $("{% endif %} - {% render_field form.name %} -
{% trans "Conditions" %}
-
-
- {% render_field form.match_type %} -
-
- {% for ec in conds_nb %} - {% display_condition form ec %} - {% endfor %} -
-
-
{% trans "Actions" %}
-
- {% for ea in actions_nb %} - {% display_action form ea %} - {% endfor %} -
-{% endblock %} diff --git a/modoboa/extensions/sievefilters/templates/sievefilters/guieditor.html b/modoboa/extensions/sievefilters/templates/sievefilters/guieditor.html deleted file mode 100644 index d73924118..000000000 --- a/modoboa/extensions/sievefilters/templates/sievefilters/guieditor.html +++ /dev/null @@ -1,25 +0,0 @@ -{% load i18n sfilters_tags %}{% load url from future %} -{% if fs.filters %} - - - - - - - {% for filter in fs.filters %} - - - - - - {% endfor %} -
{% trans "Actions" %}{% trans "Name" %}{% trans "Active" %}
{% filter_actions fs.name filter forloop.counter forloop.last %}{{ filter.name }} - - {{ filter.enabled|yesno }} - -
-{% else %} -
{% trans "No filter defined yet" %}
-{% endif %} diff --git a/modoboa/extensions/sievefilters/templates/sievefilters/index.html b/modoboa/extensions/sievefilters/templates/sievefilters/index.html deleted file mode 100644 index 40d3482ba..000000000 --- a/modoboa/extensions/sievefilters/templates/sievefilters/index.html +++ /dev/null @@ -1,104 +0,0 @@ -{% extends "twocols.html" %}{% load i18n sfilters_tags %}{% load url from future %} -{% load static %} - -{% block pagetitle %}{% trans "Message filters" %}{% endblock %} - -{% block extra_css %} - -{% endblock %} - -{% block extra_js %} - - - - - -{% endblock %} - -{% block leftcol %} - -{% endblock %} - -{% block apparea %} -
- {% if not active_script and not scripts %} -
{% trans "No filters set defined yet. You must create one in order to define filters." %}
- {% endif %} -
-{% endblock %} diff --git a/modoboa/extensions/sievefilters/templates/sievefilters/rawfilter.html b/modoboa/extensions/sievefilters/templates/sievefilters/rawfilter.html deleted file mode 100644 index 301f70161..000000000 --- a/modoboa/extensions/sievefilters/templates/sievefilters/rawfilter.html +++ /dev/null @@ -1,6 +0,0 @@ -{% load url from future %} -
{% csrf_token %} - -
- diff --git a/modoboa/extensions/sievefilters/templatetags/__init__.py b/modoboa/extensions/sievefilters/templatetags/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/modoboa/extensions/sievefilters/templatetags/sfilters_tags.py b/modoboa/extensions/sievefilters/templatetags/sfilters_tags.py deleted file mode 100644 index 3bc0f937f..000000000 --- a/modoboa/extensions/sievefilters/templatetags/sfilters_tags.py +++ /dev/null @@ -1,179 +0,0 @@ -from django import template -from django.core.urlresolvers import reverse -from django.template.loader import render_to_string -from django.utils.translation import ugettext as _ - -from modoboa.lib.web_utils import render_actions -from modoboa.lib.templatetags.form_tags import configure_field_classes - -register = template.Library() - - -@register.simple_tag -def sfilters_menu(user): - entries = [ - {"name": "newfilterset", - "img": "fa fa-plus", - "label": _("New filters set"), - "url": reverse("sievefilters:fs_add"), - "modal": True, - "modalcb": "filtersetform_cb" - } - ] - - return render_to_string('common/menulist.html', - {"entries": entries, "user": user}) - - -@register.simple_tag -def fset_menu(mode, setname): - entries = [] - if mode == "gui": - entries += [ - {"name": "newfilter", - "img": "fa fa-plus", - "label": _("New filter"), - "url": reverse("sievefilters:filter_add", - args=[setname]), - "modal": True, - "autowidth": True, - "modalcb": "filterform_cb"} - ] - if mode == "raw": - entries += [ - {"name": "savefs", - "img": "fa fa-download-alt", - "label": _("Save filters set"), - "url": reverse("sievefilters:fs_save", - args=[setname])}, - ] - - entries += [ - {"name": "activatefs", - "img": "fa fa-check", - "label": _("Activate filters set"), - "url": reverse("sievefilters:fs_activate", - args=[setname])}, - {"name": "removefs", - "img": "fa fa-trash", - "label": _("Remove filters set"), - "url": reverse("sievefilters:fs_delete", args=[setname])}, - {"name": "downloadfs", - "img": "fa fa-download", - "label": _("Download"), - "url": reverse("sievefilters:fs_download", args=[setname])} - ] - - return render_to_string('common/menulist.html', - {"entries": entries}) - - -@register.simple_tag -def filter_actions(setname, f, position, islast): - actions = [ - {"name": "editfilter", - "url": reverse( - "sievefilters:filter_change", args=[setname, f["name"]]), - "img": "fa fa-edit", - "title": _("Edit filter"), - "modal": True, - "autowidth": True, - "modalcb": "filterform_cb"}, - {"name": "removefilter", - "url": reverse( - "sievefilters:filter_delete", args=[setname, f["name"]]), - "img": "fa fa-trash", - "title": _("Remove this filter")} - ] - if position != 1: - actions += [ - {"name": "movefilter_up", - "url": reverse( - "sievefilters:filter_move_up", args=[setname, f["name"]]), - "img": "fa fa-chevron-up", - "title": _("Move this filter up")} - ] - if not islast: - actions += [ - {"name": "movefilter_down", - "url": reverse( - "sievefilters:filter_move_down", args=[setname, f["name"]]), - "img": "fa fa-chevron-down", - "title": _("Move this filter down")}, - ] - return render_actions(actions) - - -@register.simple_tag -def display_errors(errors): - if not len(errors): - return "" - t = template.Template(""" -
    - {% for error in errors %} -
  • {{ error|safe }}
  • - {% endfor %} -
-""") - return t.render(template.Context({ - "errors": errors - })) - - -@register.simple_tag -def display_condition(form, cnt): - target = form["cond_target_%d" % cnt] - configure_field_classes(target) - operator = form["cond_operator_%d" % cnt] - configure_field_classes(operator) - value = form["cond_value_%d" % cnt] - configure_field_classes(value) - t = template.Template(""" -
-
{{ tfield }}
-
{{ofield}}
-
{{ vfield }}
- {{ verrors }} -
-""") - return t.render(template.Context({ - "idx": cnt, - "tfield": target, - "ofield": operator, - "vfield": value, - "verrors": display_errors(value.errors) - })) - - -@register.simple_tag -def display_action(form, cnt): - action = form["action_name_%d" % cnt] - configure_field_classes(action) - values = [] - acnt = 0 - verrors = [] - while True: - try: - field = form["action_arg_%d_%d" % (cnt, acnt)] - configure_field_classes(field) - values += [field] - if field.errors: - verrors += field.errors - acnt += 1 - except KeyError: - break - t = template.Template(""" -
-
- {{ afield }} -
- {% for v in values %} -
{{ v }}
- {% endfor %}{{ verrors }} -
-""") - return t.render(template.Context({ - "idx": cnt, - "afield": action, "values": values, - "verrors": display_errors(verrors) - })) diff --git a/modoboa/extensions/sievefilters/test.py b/modoboa/extensions/sievefilters/test.py deleted file mode 100644 index 9d35832dc..000000000 --- a/modoboa/extensions/sievefilters/test.py +++ /dev/null @@ -1,42 +0,0 @@ -if __name__ == "__main__": - clt = ManageSieveClient("mail.koalabs.org", 2000) - if clt.connect("tonio@ngyn.org", "aka/12;c", starttls=True): - print clt.get_sasl_mechanisms() - print clt.get_sieve_capabilities() - print clt.havespace("test", 45) - - if not clt.putscript("myscript", """require ["fileinto", "envelope"]; - -if envelope :contains "to" "tmartin+sent" { - fileinto "INBOX.sent"; -} -"""): - print clt.errmsg - - if not clt.putscript("test", """#comment -InvalidSieveCommand -"""): - print clt.errmsg - - clt.deletescript("thescript") - - if not clt.setactive("myscript"): - print clt.errmsg - print clt.listscripts() - - sc = clt.getscript("myscript") - if sc is None: - print clt.errmsg - else: - print sc - - if not clt.renamescript("myscript", "thescript"): - print clt.errmsg - - clt.setactive("") - - if not clt.deletescript("thescript"): - print clt.errmsg - else: - print clt.errmsg - clt.logout() diff --git a/modoboa/extensions/sievefilters/urls.py b/modoboa/extensions/sievefilters/urls.py deleted file mode 100644 index 70f3f4262..000000000 --- a/modoboa/extensions/sievefilters/urls.py +++ /dev/null @@ -1,29 +0,0 @@ -from django.conf.urls import patterns, url - -urlpatterns = patterns( - 'modoboa.extensions.sievefilters.views', - - url(r'^$', 'index', name="index"), - url(r'^savefs/(?P.+)/$', 'savefs', name="fs_save"), - url(r'^newfs/$', 'new_filters_set', name="fs_add"), - url(r'^removefs/(?P.+)/$', 'remove_filters_set', name="fs_delete"), - url(r'^activatefs/(?P.+)/$', 'activate_filters_set', - name="fs_activate"), - url(r'^downloadfs/(?P.+)/$', 'download_filters_set', - name="fs_download"), - url(r'^templates/(?P\w+)/$', 'get_templates', - name="templates_get"), - url(r'^(?P.+)/newfilter/$', 'newfilter', - name="filter_add"), - url(r'^(?P.+)/editfilter/(?P.+)/$', 'editfilter', - name="filter_change"), - url(r'^(?P.+)/removefilter/(?P.+)/$', 'removefilter', - name="filter_delete"), - url(r'^(?P.+)/togglestate/(?P.+)/$', - 'toggle_filter_state', name="filter_toggle_state"), - url(r'^(?P.+)/moveup/(?P.+)/$', - 'move_filter_up', name="filter_move_up"), - url(r'^(?P.+)/movedown/(?P.+)/$', - 'move_filter_down', name="filter_move_down"), - url(r'^(?P.+)/$', 'getfs', name="fs_get"), -) diff --git a/modoboa/extensions/sievefilters/views.py b/modoboa/extensions/sievefilters/views.py deleted file mode 100644 index 2a97b479b..000000000 --- a/modoboa/extensions/sievefilters/views.py +++ /dev/null @@ -1,337 +0,0 @@ -# coding: utf-8 - -"""Custom views.""" - -from rfc6266 import build_header -from sievelib.commands import BadArgument, BadValue -from sievelib.managesieve import Error - -from django.contrib.auth.decorators import login_required -from django.core.urlresolvers import reverse -from django.http import HttpResponse -from django.shortcuts import render -from django.template.loader import render_to_string -from django.utils.translation import ugettext as _ - -from .forms import ( - FilterForm, build_filter_form_from_qdict, build_filter_form_from_filter, - FiltersSetForm -) -from .lib import SieveClient, SieveClientError -from .templatetags.sfilters_tags import fset_menu -from modoboa.extensions.admin.lib import needs_mailbox -from modoboa.lib import parameters -from modoboa.lib.connections import ConnectionError -from modoboa.lib.exceptions import BadRequest -from modoboa.lib.web_utils import ( - _render_error, ajax_response, render_to_json_response -) - - -@login_required -@needs_mailbox() -def index(request, tplname="sievefilters/index.html"): - from modoboa.extensions.webmail.lib import get_imapconnector - - try: - sc = SieveClient(user=request.user.username, - password=request.session["password"]) - except ConnectionError as e: - return _render_error(request, user_context={"error": e}) - - try: - active_script, scripts = sc.listscripts() - except Error as e: - return _render_error(request, user_context={"error": e}) - - if active_script is None: - active_script = "" - default_script = "%s/" % scripts[0] if len(scripts) else "" - else: - default_script = "%s/" % active_script - return render(request, tplname, { - "selection": "user", - "active_script": active_script, - "default_script": default_script, - "scripts": sorted(scripts), - "hdelimiter": get_imapconnector(request).hdelimiter - }) - - -@login_required -@needs_mailbox() -def get_templates(request, ftype): - if ftype == "condition": - return render_to_json_response( - FilterForm([], [], request).cond_templates - ) - return render_to_json_response( - FilterForm([], [], request).action_templates - ) - - -@login_required -@needs_mailbox() -def getfs(request, name): - sc = SieveClient(user=request.user.username, - password=request.session["password"]) - editormode = parameters.get_user(request.user, "EDITOR_MODE") - error = None - try: - content = sc.getscript(name, format=editormode) - except SieveClientError as e: - error = str(e) - else: - if content is None: - error = _("Failed to retrieve filters set") - - if error is not None: - return ajax_response(request, "ko", respmsg=error) - - if editormode == "raw": - htmlcontent = render_to_string("sievefilters/rawfilter.html", dict( - name=name, scriptcontent=content - )) - else: - htmlcontent = render_to_string("sievefilters/guieditor.html", dict( - fs=content - )) - - menu = '' % \ - (_("Actions"), fset_menu(editormode, name)) - resp = dict(menu=menu, content=htmlcontent) - return render_to_json_response(resp) - - -def build_filter_ctx(ctx, form): - ctx["form"] = form - ctx["conds_nb"] = range(form.conds_cnt) - ctx["actions_nb"] = range(form.actions_cnt) - return ctx - - -def submitfilter( - request, setname, okmsg, tplname, tplctx, update=False, sc=None): - form = build_filter_form_from_qdict(request) - if form.is_valid(): - if sc is None: - sc = SieveClient(user=request.user.username, - password=request.session["password"]) - fset = sc.getscript(setname, format="fset") - conditions, actions = form.tofilter() - match_type = form.cleaned_data["match_type"] - if match_type == "all": - match_type = "anyof" - conditions = [("true",)] - fltname = form.cleaned_data["name"].encode("utf-8") - try: - if not update: - fset.addfilter(fltname, conditions, actions, - match_type) - else: - oldname = request.POST["oldname"].encode("utf-8") - fset.updatefilter( - oldname, fltname, conditions, actions, match_type - ) - except (BadArgument, BadValue) as inst: - raise BadRequest(str(inst)) - sc.pushscript(fset.name, str(fset)) - return render_to_json_response(okmsg) - - return render_to_json_response({'form_errors': form.errors}, status=400) - - -@login_required -@needs_mailbox() -def newfilter(request, setname, tplname="sievefilters/filter.html"): - ctx = dict( - title=_("New filter"), - formid="filterform", - action=reverse("sievefilters:filter_add", args=[setname]), - action_label=_("Create"), - action_classes="submit" - ) - if request.method == "POST": - return submitfilter( - request, setname, _("Filter created"), tplname, ctx - ) - - conds = [("Subject", "contains", "")] - actions = [("fileinto", "")] - form = FilterForm(conds, actions, request) - ctx = build_filter_ctx(ctx, form) - return render(request, tplname, ctx) - - -@login_required -@needs_mailbox() -def editfilter(request, setname, fname, tplname="sievefilters/filter.html"): - ctx = dict( - title=_("Edit filter"), - formid="filterform", - action=reverse("sievefilters:filter_change", args=[setname, fname]), - action_label=_("Update"), - action_classes="submit" - ) - sc = SieveClient(user=request.user.username, - password=request.session["password"]) - if request.method == "POST": - return submitfilter( - request, setname, _("Filter modified"), tplname, ctx, - update=True, sc=sc - ) - - fset = sc.getscript(setname, format="fset") - if isinstance(fname, unicode): - fname = fname.encode("utf-8") - f = fset.getfilter(fname) - form = build_filter_form_from_filter(request, fname, f) - ctx = build_filter_ctx(ctx, form) - ctx["oldname"] = fname - ctx["hidestyle"] = "none" \ - if form.fields["match_type"].initial == "all" else "block" - return render(request, tplname, ctx) - - -@login_required -@needs_mailbox() -def removefilter(request, setname, fname): - sc = SieveClient(user=request.user.username, - password=request.session["password"]) - fset = sc.getscript(setname, format="fset") - if fset.removefilter(fname.encode("utf-8")): - sc.pushscript(fset.name, str(fset)) - return render_to_json_response(_("Filter removed")) - return render_to_json_response(_("Failed to remove filter"), status=500) - - -@login_required -@needs_mailbox() -def savefs(request, name): - if "scriptcontent" not in request.POST: - return - sc = SieveClient(user=request.user.username, - password=request.session["password"]) - try: - sc.pushscript(name, request.POST["scriptcontent"]) - except SieveClientError as e: - error = str(e) - return ajax_response(request, "ko", respmsg=error) - return ajax_response(request, respmsg=_("Filters set saved")) - - -@login_required -@needs_mailbox() -def new_filters_set(request, tplname="common/generic_modal_form.html"): - if request.method == "POST": - form = FiltersSetForm(request.POST) - if form.is_valid(): - sc = SieveClient(user=request.user.username, - password=request.session["password"]) - sc.pushscript(form.cleaned_data["name"], "# Empty script", - form.cleaned_data["active"]) - return render_to_json_response({ - "url": form.cleaned_data["name"], - "active": form.cleaned_data["active"], - "respmsg": _("Filters set created") - }) - return render_to_json_response({'form_errors': form.errors}, status=400) - - ctx = {"title": _("Create a new filters set"), - "formid": "newfiltersset", - "action_label": _("Create"), - "action_classes": "submit", - "action": reverse("sievefilters:fs_add"), - "withmenu": False, - "withunseen": False, - "form": FiltersSetForm()} - return render(request, tplname, ctx) - - -@login_required -@needs_mailbox() -def remove_filters_set(request, name): - sc = SieveClient(user=request.user.username, - password=request.session["password"]) - sc.deletescript(name) - acs, scripts = sc.listscripts() - return render_to_json_response(dict( - respmsg=_("Filters set deleted"), newfs=acs - )) - - -@login_required -@needs_mailbox() -def activate_filters_set(request, name): - sc = SieveClient(user=request.user.username, - password=request.session["password"]) - try: - sc.activatescript(name) - except SieveClientError as e: - return ajax_response(request, "ko", respmsg=str(e)) - return ajax_response(request, respmsg=_("Filters set activated")) - - -@login_required -@needs_mailbox() -def download_filters_set(request, name): - sc = SieveClient(user=request.user.username, - password=request.session["password"]) - try: - script = sc.getscript(name) - except SieveClientError as e: - return ajax_response(request, "ko", respmsg=str(e)) - - resp = HttpResponse(script) - resp["Content-Type"] = "text/plain; charset=utf-8" - resp["Content-Length"] = len(script) - resp["Content-Disposition"] = build_header('%s.txt' % name) - return resp - - -@login_required -@needs_mailbox() -def toggle_filter_state(request, setname, fname): - sc = SieveClient(user=request.user.username, - password=request.session["password"]) - if isinstance(fname, unicode): - fname = fname.encode("utf-8") - fset = sc.getscript(setname, format="fset") - if fset.is_filter_disabled(fname): - ret = fset.enablefilter(fname) - newstate = _("yes") - color = "green" - else: - ret = fset.disablefilter(fname) - newstate = _("no") - color = "red" - if not ret: - pass - sc.pushscript(setname, str(fset)) - return render_to_json_response({ - "label": newstate, - "color": color - }) - - -def move_filter(request, setname, fname, direction): - sc = SieveClient(user=request.user.username, - password=request.session["password"]) - fset = sc.getscript(setname, format="fset") - fset.movefilter(fname.encode("utf-8"), direction) - sc.pushscript(setname, str(fset)) - return ajax_response( - request, template="sievefilters/guieditor.html", fs=fset - ) - - -@login_required -@needs_mailbox() -def move_filter_up(request, setname, fname): - return move_filter(request, setname, fname, "up") - - -@login_required -@needs_mailbox() -def move_filter_down(request, setname, fname): - return move_filter(request, setname, fname, "down")