, 2018
+# controlcde, 2015
+# Patrick Koetter , 2010
+msgid ""
+msgstr ""
+"Project-Id-Version: Modoboa\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2017-12-01 18:04+0100\n"
+"PO-Revision-Date: 2018-04-25 14:02+0000\n"
+"Last-Translator: Boris Andratzek \n"
+"Language-Team: German (http://www.transifex.com/tonio/modoboa/language/de/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: de\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: constants.py:6
+msgid "contains"
+msgstr "enthält"
+
+#: constants.py:7
+msgid "does not contain"
+msgstr "enthält nicht"
+
+#: constants.py:8
+msgid "is"
+msgstr "ist"
+
+#: constants.py:9
+msgid "is not"
+msgstr "ist nicht"
+
+#: constants.py:14
+msgid "Subject"
+msgstr "Betreff"
+
+#: constants.py:17
+msgid "Sender"
+msgstr "Sender"
+
+#: constants.py:20
+msgid "Recipient"
+msgstr "Empfänger"
+
+#: constants.py:23
+msgid "Cc"
+msgstr "Cc"
+
+#: constants.py:25
+msgid "Size"
+msgstr "Größe"
+
+#: constants.py:26
+msgid "is greater than"
+msgstr "ist größer als"
+
+#: constants.py:27
+msgid "is less than"
+msgstr "ist kleiner als"
+
+#: constants.py:31
+msgid "Move message to"
+msgstr "Verschiebe Nachricht nach"
+
+#: constants.py:36 constants.py:44
+msgid "Keep local copy"
+msgstr "Behalte lokale Kopie"
+
+#: constants.py:40
+msgid "Redirect message to"
+msgstr "Leite Nachricht um zu"
+
+#: constants.py:48
+msgid "Reject message"
+msgstr "E-Mail ablehnen"
+
+#: constants.py:50
+msgid "Stop processing"
+msgstr "Stoppe Bearbeitung"
+
+#: forms.py:33
+msgid "Check to activate this filters set"
+msgstr "Häkchen setzen, um den Filter-Satz zu aktivieren"
+
+#: forms.py:87 templates/modoboa_sievefilters/guieditor.html:6
+msgid "Name"
+msgstr "Name"
+
+#: forms.py:89
+msgid "Match type"
+msgstr "Vergleichte Typ"
+
+#: forms.py:90
+msgid "All of the following"
+msgstr "Alle der folgenden"
+
+#: forms.py:91
+msgid "Any of the following"
+msgstr "Irgendeines der folgenden"
+
+#: forms.py:92
+msgid "All messages"
+msgstr "Alle Nachrichten"
+
+#: forms.py:107
+msgid "Wrong filter name"
+msgstr "Falscher Filtername"
+
+#: forms.py:351
+msgid "ManageSieve settings"
+msgstr "ManageSieve-Einstellungen"
+
+#: forms.py:354 forms.py:384
+msgid "Server address"
+msgstr "Server-Adresse"
+
+#: forms.py:356
+msgid "Address of your MANAGESIEVE server"
+msgstr "Adresse Ihres MANAGESIEVE-Servers"
+
+#: forms.py:361 forms.py:396
+msgid "Server port"
+msgstr "Server-Port"
+
+#: forms.py:363
+msgid "Listening port of your MANAGESIEVE server"
+msgstr "TCP-Port Ihres MANAGESIEVE-Servers"
+
+#: forms.py:368
+msgid "Connect using STARTTLS"
+msgstr "STARTTLS für Verbindungsaufbau nutzen"
+
+#: forms.py:370
+msgid "Use the STARTTLS extension"
+msgstr "STARTTLS benutzen"
+
+#: forms.py:374
+msgid "Authentication mechanism"
+msgstr "Authentifizierungsmechanismus"
+
+#: forms.py:377
+msgid "Prefered authentication mechanism"
+msgstr "Bevorzugte Authentifizierungsmethode"
+
+#: forms.py:381
+msgid "IMAP settings"
+msgstr "IMAP-Einstellungen"
+
+#: forms.py:386
+msgid "Address of your IMAP server"
+msgstr "Addresse Ihres IMAP-Servers"
+
+#: forms.py:390
+msgid "Use a secured connection"
+msgstr "Benutze eine sichere Verbindung"
+
+#: forms.py:392
+msgid "Use a secured connection to access IMAP server"
+msgstr "Benutze eine gesicherte Verbindung zum Zugriff auf den IMAP Server"
+
+#: forms.py:398
+msgid "Listening port of your IMAP server"
+msgstr "TCPIP Port Ihres IMAP Servers"
+
+#: forms.py:405
+msgid "General"
+msgstr "Allgemein"
+
+#: forms.py:409
+msgid "Editor mode"
+msgstr "Editor-Modus"
+
+#: forms.py:411
+msgid "Select the mode you want the editor to work in"
+msgstr "Wählen Sie den Modus aus, in dem der Editor arbeiten soll"
+
+#: forms.py:415
+msgid "Mailboxes"
+msgstr "E-Mail-Postfächer"
+
+#: forms.py:419
+msgid "Trash folder"
+msgstr "Papierkorb-Ordner"
+
+#: forms.py:420
+msgid "Folder where deleted messages go"
+msgstr "Ordner, in den gelöschte Nachrichten gehen"
+
+#: forms.py:425
+msgid "Sent folder"
+msgstr "Gesendet-Ordner"
+
+#: forms.py:426
+msgid "Folder where copies of sent messages go"
+msgstr "Ordner, in den Kopien gesendeter Nachrichten gehen"
+
+#: forms.py:431
+msgid "Drafts folder"
+msgstr "Entwürfe-Ordner"
+
+#: forms.py:432
+msgid "Folder where drafts go"
+msgstr "Ordner für Entwürfe"
+
+#: handlers.py:19 modo_extension.py:26
+#: templates/modoboa_sievefilters/index.html:4
+msgid "Message filters"
+msgstr "Nachrichten-Filter"
+
+#: imaputils.py:99
+msgid "Failed to retrieve hierarchy delimiter"
+msgstr ""
+
+#: imaputils.py:135
+#, python-format
+msgid "Connection to IMAP server failed: %s"
+msgstr "Verbindung zum IMAP-Server gescheitert: %s"
+
+#: lib.py:54
+msgid "Connection to MANAGESIEVE server failed, check your configuration"
+msgstr "Verbindung zu MANAGESIEVE-Server fehlgeschlagen. Überprüfen Sie Ihre Konfiguration."
+
+#: lib.py:98
+msgid "Not enough space on server"
+msgstr "Kein weiterer Platz auf Server verfügbar"
+
+#: modo_extension.py:18
+msgid "Plugin to easily create server-side filters"
+msgstr "Plugin, um auf einfache Weise serverseitige Filter zu erstellen"
+
+#: modo_extension.py:24
+msgid "Sieve filters"
+msgstr "SIEVE-Filter"
+
+#: templates/modoboa_sievefilters/filter.html:9
+msgid "Conditions"
+msgstr "Bedingungen"
+
+#: templates/modoboa_sievefilters/filter.html:20
+#: templates/modoboa_sievefilters/guieditor.html:5 views.py:104
+msgid "Actions"
+msgstr "Aktionen"
+
+#: templates/modoboa_sievefilters/guieditor.html:7
+msgid "Active"
+msgstr "Aktiv"
+
+#: templates/modoboa_sievefilters/guieditor.html:24
+msgid "No filter defined yet"
+msgstr "Noch keine Filter definiert"
+
+#: templates/modoboa_sievefilters/index.html:82
+msgid "Filter sets"
+msgstr "Filter-Sätze"
+
+#: templates/modoboa_sievefilters/index.html:86
+msgid "active"
+msgstr "aktiv"
+
+#: templates/modoboa_sievefilters/index.html:101
+msgid ""
+"No filters set defined yet. You must create one in order to define filters."
+msgstr "Noch keine Filter-Sätze definiert. Sie müssen einen Satz erstellen, um diesem Filter hinzufügen zu können."
+
+#: templatetags/sfilters_tags.py:21
+msgid "New filters set"
+msgstr "Neuer Filter-Satz"
+
+#: templatetags/sfilters_tags.py:39 views.py:153
+msgid "New filter"
+msgstr "Neuer Filter"
+
+#: templatetags/sfilters_tags.py:50
+msgid "Save filters set"
+msgstr "Filter-Satz speichern"
+
+#: templatetags/sfilters_tags.py:58
+msgid "Activate filters set"
+msgstr "Filter-Satz aktivieren"
+
+#: templatetags/sfilters_tags.py:63
+msgid "Remove filters set"
+msgstr "Filter-Satz entfernen"
+
+#: templatetags/sfilters_tags.py:67
+msgid "Download"
+msgstr "Herunterladen"
+
+#: templatetags/sfilters_tags.py:82 views.py:175
+msgid "Edit filter"
+msgstr "Filter bearbeiten"
+
+#: templatetags/sfilters_tags.py:90
+msgid "Remove this filter"
+msgstr "Filter entfernen"
+
+#: templatetags/sfilters_tags.py:99
+msgid "Move this filter up"
+msgstr "Filter nach oben verschieben"
+
+#: templatetags/sfilters_tags.py:108
+msgid "Move this filter down"
+msgstr "Filter nach unten verschieben"
+
+#: views.py:87
+msgid "Failed to retrieve filters set"
+msgstr "Konnte Filter-Satz nicht laden"
+
+#: views.py:156 views.py:248
+msgid "Create"
+msgstr "Erstellen"
+
+#: views.py:161
+msgid "Filter created"
+msgstr "Filter erstellt"
+
+#: views.py:179
+msgid "Update"
+msgstr "Aktualisieren"
+
+#: views.py:186
+msgid "Filter modified"
+msgstr "Filter verändert"
+
+#: views.py:209
+msgid "Filter removed"
+msgstr "Filter entfernt"
+
+#: views.py:210
+msgid "Failed to remove filter"
+msgstr "Konnte Filter nicht entfernen"
+
+#: views.py:225
+msgid "Filters set saved"
+msgstr "Filter-Satz gespeichert"
+
+#: views.py:241
+msgid "Filters set created"
+msgstr "Filter-Satz erstellt"
+
+#: views.py:246
+msgid "Create a new filters set"
+msgstr "Neuen Filter-Satz erstellen"
+
+#: views.py:265
+msgid "Filters set deleted"
+msgstr "Filter-Satz entfernt"
+
+#: views.py:278
+msgid "Filters set activated"
+msgstr "Filter-Satz aktiviert"
+
+#: views.py:307
+msgid "yes"
+msgstr "Ja"
+
+#: views.py:311
+msgid "no"
+msgstr "Nein"
diff --git a/modoboa/sievefilters/locale/de/LC_MESSAGES/djangojs.po b/modoboa/sievefilters/locale/de/LC_MESSAGES/djangojs.po
new file mode 100644
index 000000000..00a55759c
--- /dev/null
+++ b/modoboa/sievefilters/locale/de/LC_MESSAGES/djangojs.po
@@ -0,0 +1,42 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# Arvedui , 2014
+# controlcde, 2015
+# Patrick Koetter , 2010
+msgid ""
+msgstr ""
+"Project-Id-Version: Modoboa\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2015-02-11 13:54+0100\n"
+"PO-Revision-Date: 2017-09-22 09:57+0000\n"
+"Last-Translator: controlcde\n"
+"Language-Team: German (http://www.transifex.com/tonio/modoboa/language/de/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: de\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: static/modoboa_sievefilters/js/lib.js:14
+msgid "Remove this filter?"
+msgstr "Diesen Filter entfernen?"
+
+#: static/modoboa_sievefilters/js/lib.js:107
+msgid "Save changes?"
+msgstr "Änderungen speichern?"
+
+#: static/modoboa_sievefilters/js/lib.js:129
+msgid "Remove filters set?"
+msgstr "Diesen Filter-Satz entfernen?"
+
+#: static/modoboa_sievefilters/js/lib.js:146
+msgid "Activate this filters set?"
+msgstr "Diesen Filter-Satz aktivieren?"
+
+#: static/modoboa_sievefilters/js/lib.js:154
+#: static/modoboa_sievefilters/js/lib.js:203
+msgid "active"
+msgstr "Aktiv"
diff --git a/modoboa/sievefilters/locale/el_GR/LC_MESSAGES/django.po b/modoboa/sievefilters/locale/el_GR/LC_MESSAGES/django.po
new file mode 100644
index 000000000..c73ce79e4
--- /dev/null
+++ b/modoboa/sievefilters/locale/el_GR/LC_MESSAGES/django.po
@@ -0,0 +1,368 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# Giannis Kapetanakis , 2016
+# Kostas Moumouris , 2017
+msgid ""
+msgstr ""
+"Project-Id-Version: Modoboa\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2017-12-01 18:04+0100\n"
+"PO-Revision-Date: 2017-10-12 13:12+0000\n"
+"Last-Translator: Kostas Moumouris \n"
+"Language-Team: Greek (Greece) (http://www.transifex.com/tonio/modoboa/"
+"language/el_GR/)\n"
+"Language: el_GR\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: constants.py:6
+msgid "contains"
+msgstr "περιέχει"
+
+#: constants.py:7
+msgid "does not contain"
+msgstr "δεν περιέχει"
+
+#: constants.py:8
+msgid "is"
+msgstr "είναι"
+
+#: constants.py:9
+msgid "is not"
+msgstr "δεν είναι"
+
+#: constants.py:14
+msgid "Subject"
+msgstr "Τίτλος"
+
+#: constants.py:17
+msgid "Sender"
+msgstr "Αποστολέας"
+
+#: constants.py:20
+msgid "Recipient"
+msgstr "Παραλήπτης"
+
+#: constants.py:23
+msgid "Cc"
+msgstr "Cc"
+
+#: constants.py:25
+msgid "Size"
+msgstr "Μέγεθος"
+
+#: constants.py:26
+msgid "is greater than"
+msgstr "είναι μεγαλύτερο από"
+
+#: constants.py:27
+msgid "is less than"
+msgstr "είναι μικρότερο από"
+
+#: constants.py:31
+msgid "Move message to"
+msgstr "Μετακίνηση μηνυμάτων προς"
+
+#: constants.py:36 constants.py:44
+msgid "Keep local copy"
+msgstr ""
+
+#: constants.py:40
+msgid "Redirect message to"
+msgstr "Ανακατεύθυνση μηνυμάτων προς"
+
+#: constants.py:48
+msgid "Reject message"
+msgstr "Απόρριψη μηνύματος"
+
+#: constants.py:50
+msgid "Stop processing"
+msgstr "Ακύρωση επεξεργασίας"
+
+#: forms.py:33
+msgid "Check to activate this filters set"
+msgstr "Επιλέξτε για να ενεργοποιηθεί αυτό το σετ φίλτρων"
+
+#: forms.py:87 templates/modoboa_sievefilters/guieditor.html:6
+msgid "Name"
+msgstr "Όνομα"
+
+#: forms.py:89
+msgid "Match type"
+msgstr ""
+
+#: forms.py:90
+msgid "All of the following"
+msgstr "Όλα τα παρακάτω"
+
+#: forms.py:91
+msgid "Any of the following"
+msgstr "Οποιοδήποτε από τα παρακάτων"
+
+#: forms.py:92
+msgid "All messages"
+msgstr "Όλα τα μηνύματα"
+
+#: forms.py:107
+msgid "Wrong filter name"
+msgstr "Λάθος όνομα φίλτρου"
+
+#: forms.py:351
+msgid "ManageSieve settings"
+msgstr "Ρυθμίσεις ManageSieve"
+
+#: forms.py:354 forms.py:384
+msgid "Server address"
+msgstr "Διεύθυνση εξυπηρετητή"
+
+#: forms.py:356
+msgid "Address of your MANAGESIEVE server"
+msgstr "Η διεύθυνση του εξυπηρετητή MANAGESIEVE"
+
+#: forms.py:361 forms.py:396
+msgid "Server port"
+msgstr "Πόρτα εξυπηρετητή"
+
+#: forms.py:363
+msgid "Listening port of your MANAGESIEVE server"
+msgstr "Η πόρτα λειτουργίας του MANAGESIEVE εξυπηρετητή σας"
+
+#: forms.py:368
+msgid "Connect using STARTTLS"
+msgstr "Σύνδεση με χρήση STARTTLS"
+
+#: forms.py:370
+msgid "Use the STARTTLS extension"
+msgstr "Χρήση του extension STARTTLS"
+
+#: forms.py:374
+msgid "Authentication mechanism"
+msgstr "Μηχανισμός πιστοποίησης"
+
+#: forms.py:377
+msgid "Prefered authentication mechanism"
+msgstr "Επιλεγμένος μηχανισμός πιστοποίησης"
+
+#: forms.py:381
+msgid "IMAP settings"
+msgstr "ρύθμισης IMAP"
+
+#: forms.py:386
+msgid "Address of your IMAP server"
+msgstr "Διεύθυνση του διακομιστή IMAP"
+
+#: forms.py:390
+msgid "Use a secured connection"
+msgstr "Χρησιμοποιήστε μια ασφαλή σύνδεση"
+
+#: forms.py:392
+msgid "Use a secured connection to access IMAP server"
+msgstr "Χρησιμοποιήστε μια ασφαλή σύνδεση για πρόσβαση στον διακομιστή IMAP"
+
+#: forms.py:398
+msgid "Listening port of your IMAP server"
+msgstr "Η θύρα που ακούει ο IMAP server σας"
+
+#: forms.py:405
+msgid "General"
+msgstr "Γενικά"
+
+#: forms.py:409
+msgid "Editor mode"
+msgstr "Λειτουργία συντάκτη"
+
+#: forms.py:411
+msgid "Select the mode you want the editor to work in"
+msgstr "Επιλέξτε τη λειτουργία στην οποία θέλετε να εργάζεται ο συντάκτης"
+
+#: forms.py:415
+msgid "Mailboxes"
+msgstr "Γραμματοκιβώτια"
+
+#: forms.py:419
+msgid "Trash folder"
+msgstr "Φάκελος σκουπιδιών"
+
+#: forms.py:420
+msgid "Folder where deleted messages go"
+msgstr "Φάκελος που πηγαίνουν τα σβησμένα μηνύματα"
+
+#: forms.py:425
+msgid "Sent folder"
+msgstr "Φάκελος απεσταλμένων"
+
+#: forms.py:426
+msgid "Folder where copies of sent messages go"
+msgstr "Φάκελος όπου πηγαίνουν αντίγραφα των απεσταλμένων μηνυμάτων"
+
+#: forms.py:431
+msgid "Drafts folder"
+msgstr "Φάκελος πρόχειρων"
+
+#: forms.py:432
+msgid "Folder where drafts go"
+msgstr "Ο φάκελος που θα πηγαίνουν τα πρόχειρα"
+
+#: handlers.py:19 modo_extension.py:26
+#: templates/modoboa_sievefilters/index.html:4
+msgid "Message filters"
+msgstr "Φίλτρα μηνυμάτων"
+
+#: imaputils.py:99
+msgid "Failed to retrieve hierarchy delimiter"
+msgstr "Αποτυχία κατά την ανάκτηση της οροθετημένης ιεραρχίας"
+
+#: imaputils.py:135
+#, python-format
+msgid "Connection to IMAP server failed: %s"
+msgstr "Η σύνδεση στο διακομιστή IMAP απέτυχε:%s"
+
+#: lib.py:54
+msgid "Connection to MANAGESIEVE server failed, check your configuration"
+msgstr ""
+"Η σύνδεση με τον εξυπηρετητή MANAGESIEVE απέτυχε, ελέγξτε τις ρυθμίσεις σας "
+
+#: lib.py:98
+msgid "Not enough space on server"
+msgstr "Δεν υπάρχει διαθέσιμος χώρος στον εξυπηρετητή"
+
+#: modo_extension.py:18
+msgid "Plugin to easily create server-side filters"
+msgstr "Πρόσθετο για εύκολη δημιουργία φίλτρων από την πλευρά του διακομιστή"
+
+#: modo_extension.py:24
+msgid "Sieve filters"
+msgstr "Φίλτρα Sieve"
+
+#: templates/modoboa_sievefilters/filter.html:9
+msgid "Conditions"
+msgstr "Συνθήκες"
+
+#: templates/modoboa_sievefilters/filter.html:20
+#: templates/modoboa_sievefilters/guieditor.html:5 views.py:104
+msgid "Actions"
+msgstr "Ενέργειες"
+
+#: templates/modoboa_sievefilters/guieditor.html:7
+msgid "Active"
+msgstr "Ενεργό"
+
+#: templates/modoboa_sievefilters/guieditor.html:24
+msgid "No filter defined yet"
+msgstr "Δεν υπάρχει καθορισμένο φίλτρο"
+
+#: templates/modoboa_sievefilters/index.html:82
+msgid "Filter sets"
+msgstr "Σετ φίλτρων"
+
+#: templates/modoboa_sievefilters/index.html:86
+msgid "active"
+msgstr "ενεργό"
+
+#: templates/modoboa_sievefilters/index.html:101
+msgid ""
+"No filters set defined yet. You must create one in order to define filters."
+msgstr ""
+"Δεν έχουν οριστεί ακόμη φίλτρα. Πρέπει να δημιουργήσετε τουλάχιστον ένα για "
+"να καθοριστούν τα φίλτρα"
+
+#: templatetags/sfilters_tags.py:21
+msgid "New filters set"
+msgstr "Νέο σετ φίλτρων"
+
+#: templatetags/sfilters_tags.py:39 views.py:153
+msgid "New filter"
+msgstr "Νέο φίλτρο"
+
+#: templatetags/sfilters_tags.py:50
+msgid "Save filters set"
+msgstr "Αποθήκευση του σετ φίλτρων"
+
+#: templatetags/sfilters_tags.py:58
+msgid "Activate filters set"
+msgstr "Ενεργοποίηση του σετ φίλτρων"
+
+#: templatetags/sfilters_tags.py:63
+msgid "Remove filters set"
+msgstr "Αφαίρεση του σετ φίλτρων"
+
+#: templatetags/sfilters_tags.py:67
+msgid "Download"
+msgstr "Λήψη"
+
+#: templatetags/sfilters_tags.py:82 views.py:175
+msgid "Edit filter"
+msgstr "Επεξεργασία φίλτρου"
+
+#: templatetags/sfilters_tags.py:90
+msgid "Remove this filter"
+msgstr "Αφαίρεση αυτού του φίλτρου"
+
+#: templatetags/sfilters_tags.py:99
+msgid "Move this filter up"
+msgstr "Μετακίνηση αυτού του φίλτρου πάνω"
+
+#: templatetags/sfilters_tags.py:108
+msgid "Move this filter down"
+msgstr "Μετακίνηση αυτού του φίλτρου κάτω"
+
+#: views.py:87
+msgid "Failed to retrieve filters set"
+msgstr "Σφάλμα κατά την την λήψη του σετ φίλτρων"
+
+#: views.py:156 views.py:248
+msgid "Create"
+msgstr "Δημιουργία"
+
+#: views.py:161
+msgid "Filter created"
+msgstr "Το φίλτρο δημιουργήθηκε"
+
+#: views.py:179
+msgid "Update"
+msgstr "Ενημέρωση"
+
+#: views.py:186
+msgid "Filter modified"
+msgstr "Το φίλτρο άλλαξε"
+
+#: views.py:209
+msgid "Filter removed"
+msgstr "Το φίλτρο αφαιρέθηκε "
+
+#: views.py:210
+msgid "Failed to remove filter"
+msgstr "Σφάλμα κατά την αφαίρεση του φίλτρου"
+
+#: views.py:225
+msgid "Filters set saved"
+msgstr "Το σετ φίλτρων αποθηκεύτηκε"
+
+#: views.py:241
+msgid "Filters set created"
+msgstr "Το σετ φίλτρων δημιουργήθηκε"
+
+#: views.py:246
+msgid "Create a new filters set"
+msgstr "Δημιουργία νέου σετ φίλτρων"
+
+#: views.py:265
+msgid "Filters set deleted"
+msgstr "Το σετ φίλτρων διαγράφηκε"
+
+#: views.py:278
+msgid "Filters set activated"
+msgstr "Το σετ φίλτρων ενεργοποιήθηκε"
+
+#: views.py:307
+msgid "yes"
+msgstr "ναι"
+
+#: views.py:311
+msgid "no"
+msgstr "όχι"
diff --git a/modoboa/sievefilters/locale/el_GR/LC_MESSAGES/djangojs.po b/modoboa/sievefilters/locale/el_GR/LC_MESSAGES/djangojs.po
new file mode 100644
index 000000000..d32830a74
--- /dev/null
+++ b/modoboa/sievefilters/locale/el_GR/LC_MESSAGES/djangojs.po
@@ -0,0 +1,40 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# Giannis Kapetanakis , 2016
+msgid ""
+msgstr ""
+"Project-Id-Version: Modoboa\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2017-03-03 09:34+0100\n"
+"PO-Revision-Date: 2017-09-22 22:21+0000\n"
+"Last-Translator: Giannis Kapetanakis \n"
+"Language-Team: Greek (Greece) (http://www.transifex.com/tonio/modoboa/language/el_GR/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: el_GR\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: static/modoboa_sievefilters/js/lib.js:14
+msgid "Remove this filter?"
+msgstr "Αφαίρεση αυτού του φίλτρου;"
+
+#: static/modoboa_sievefilters/js/lib.js:107
+msgid "Save changes?"
+msgstr "Αποθήκευση αλλαγών;"
+
+#: static/modoboa_sievefilters/js/lib.js:129
+msgid "Remove filters set?"
+msgstr "Αφαίρεση αυτού του σετ φίλτρων;"
+
+#: static/modoboa_sievefilters/js/lib.js:146
+msgid "Activate this filters set?"
+msgstr "Ενεργοποίηση αυτού του σετ φίλτρων;"
+
+#: static/modoboa_sievefilters/js/lib.js:154
+#: static/modoboa_sievefilters/js/lib.js:203
+msgid "active"
+msgstr "ενεργό"
diff --git a/modoboa/sievefilters/locale/en/LC_MESSAGES/django.po b/modoboa/sievefilters/locale/en/LC_MESSAGES/django.po
new file mode 100644
index 000000000..8d511c3b5
--- /dev/null
+++ b/modoboa/sievefilters/locale/en/LC_MESSAGES/django.po
@@ -0,0 +1,362 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR , YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2017-12-01 18:04+0100\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME \n"
+"Language-Team: LANGUAGE \n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: constants.py:6
+msgid "contains"
+msgstr ""
+
+#: constants.py:7
+msgid "does not contain"
+msgstr ""
+
+#: constants.py:8
+msgid "is"
+msgstr ""
+
+#: constants.py:9
+msgid "is not"
+msgstr ""
+
+#: constants.py:14
+msgid "Subject"
+msgstr ""
+
+#: constants.py:17
+msgid "Sender"
+msgstr ""
+
+#: constants.py:20
+msgid "Recipient"
+msgstr ""
+
+#: constants.py:23
+msgid "Cc"
+msgstr ""
+
+#: constants.py:25
+msgid "Size"
+msgstr ""
+
+#: constants.py:26
+msgid "is greater than"
+msgstr ""
+
+#: constants.py:27
+msgid "is less than"
+msgstr ""
+
+#: constants.py:31
+msgid "Move message to"
+msgstr ""
+
+#: constants.py:36 constants.py:44
+msgid "Keep local copy"
+msgstr ""
+
+#: constants.py:40
+msgid "Redirect message to"
+msgstr ""
+
+#: constants.py:48
+msgid "Reject message"
+msgstr ""
+
+#: constants.py:50
+msgid "Stop processing"
+msgstr ""
+
+#: forms.py:33
+msgid "Check to activate this filters set"
+msgstr ""
+
+#: forms.py:87 templates/modoboa_sievefilters/guieditor.html:6
+msgid "Name"
+msgstr ""
+
+#: forms.py:89
+msgid "Match type"
+msgstr ""
+
+#: forms.py:90
+msgid "All of the following"
+msgstr ""
+
+#: forms.py:91
+msgid "Any of the following"
+msgstr ""
+
+#: forms.py:92
+msgid "All messages"
+msgstr ""
+
+#: forms.py:107
+msgid "Wrong filter name"
+msgstr ""
+
+#: forms.py:351
+msgid "ManageSieve settings"
+msgstr ""
+
+#: forms.py:354 forms.py:384
+msgid "Server address"
+msgstr ""
+
+#: forms.py:356
+msgid "Address of your MANAGESIEVE server"
+msgstr ""
+
+#: forms.py:361 forms.py:396
+msgid "Server port"
+msgstr ""
+
+#: forms.py:363
+msgid "Listening port of your MANAGESIEVE server"
+msgstr ""
+
+#: forms.py:368
+msgid "Connect using STARTTLS"
+msgstr ""
+
+#: forms.py:370
+msgid "Use the STARTTLS extension"
+msgstr ""
+
+#: forms.py:374
+msgid "Authentication mechanism"
+msgstr ""
+
+#: forms.py:377
+msgid "Prefered authentication mechanism"
+msgstr ""
+
+#: forms.py:381
+msgid "IMAP settings"
+msgstr ""
+
+#: forms.py:386
+msgid "Address of your IMAP server"
+msgstr ""
+
+#: forms.py:390
+msgid "Use a secured connection"
+msgstr ""
+
+#: forms.py:392
+msgid "Use a secured connection to access IMAP server"
+msgstr ""
+
+#: forms.py:398
+msgid "Listening port of your IMAP server"
+msgstr ""
+
+#: forms.py:405
+msgid "General"
+msgstr ""
+
+#: forms.py:409
+msgid "Editor mode"
+msgstr ""
+
+#: forms.py:411
+msgid "Select the mode you want the editor to work in"
+msgstr ""
+
+#: forms.py:415
+msgid "Mailboxes"
+msgstr ""
+
+#: forms.py:419
+msgid "Trash folder"
+msgstr ""
+
+#: forms.py:420
+msgid "Folder where deleted messages go"
+msgstr ""
+
+#: forms.py:425
+msgid "Sent folder"
+msgstr ""
+
+#: forms.py:426
+msgid "Folder where copies of sent messages go"
+msgstr ""
+
+#: forms.py:431
+msgid "Drafts folder"
+msgstr ""
+
+#: forms.py:432
+msgid "Folder where drafts go"
+msgstr ""
+
+#: handlers.py:19 modo_extension.py:26
+#: templates/modoboa_sievefilters/index.html:4
+msgid "Message filters"
+msgstr ""
+
+#: imaputils.py:99
+msgid "Failed to retrieve hierarchy delimiter"
+msgstr ""
+
+#: imaputils.py:135
+#, python-format
+msgid "Connection to IMAP server failed: %s"
+msgstr ""
+
+#: lib.py:54
+msgid "Connection to MANAGESIEVE server failed, check your configuration"
+msgstr ""
+
+#: lib.py:98
+msgid "Not enough space on server"
+msgstr ""
+
+#: modo_extension.py:18
+msgid "Plugin to easily create server-side filters"
+msgstr ""
+
+#: modo_extension.py:24
+msgid "Sieve filters"
+msgstr ""
+
+#: templates/modoboa_sievefilters/filter.html:9
+msgid "Conditions"
+msgstr ""
+
+#: templates/modoboa_sievefilters/filter.html:20
+#: templates/modoboa_sievefilters/guieditor.html:5 views.py:104
+msgid "Actions"
+msgstr ""
+
+#: templates/modoboa_sievefilters/guieditor.html:7
+msgid "Active"
+msgstr ""
+
+#: templates/modoboa_sievefilters/guieditor.html:24
+msgid "No filter defined yet"
+msgstr ""
+
+#: templates/modoboa_sievefilters/index.html:82
+msgid "Filter sets"
+msgstr ""
+
+#: templates/modoboa_sievefilters/index.html:86
+msgid "active"
+msgstr ""
+
+#: templates/modoboa_sievefilters/index.html:101
+msgid ""
+"No filters set defined yet. You must create one in order to define filters."
+msgstr ""
+
+#: templatetags/sfilters_tags.py:21
+msgid "New filters set"
+msgstr ""
+
+#: templatetags/sfilters_tags.py:39 views.py:153
+msgid "New filter"
+msgstr ""
+
+#: templatetags/sfilters_tags.py:50
+msgid "Save filters set"
+msgstr ""
+
+#: templatetags/sfilters_tags.py:58
+msgid "Activate filters set"
+msgstr ""
+
+#: templatetags/sfilters_tags.py:63
+msgid "Remove filters set"
+msgstr ""
+
+#: templatetags/sfilters_tags.py:67
+msgid "Download"
+msgstr ""
+
+#: templatetags/sfilters_tags.py:82 views.py:175
+msgid "Edit filter"
+msgstr ""
+
+#: templatetags/sfilters_tags.py:90
+msgid "Remove this filter"
+msgstr ""
+
+#: templatetags/sfilters_tags.py:99
+msgid "Move this filter up"
+msgstr ""
+
+#: templatetags/sfilters_tags.py:108
+msgid "Move this filter down"
+msgstr ""
+
+#: views.py:87
+msgid "Failed to retrieve filters set"
+msgstr ""
+
+#: views.py:156 views.py:248
+msgid "Create"
+msgstr ""
+
+#: views.py:161
+msgid "Filter created"
+msgstr ""
+
+#: views.py:179
+msgid "Update"
+msgstr ""
+
+#: views.py:186
+msgid "Filter modified"
+msgstr ""
+
+#: views.py:209
+msgid "Filter removed"
+msgstr ""
+
+#: views.py:210
+msgid "Failed to remove filter"
+msgstr ""
+
+#: views.py:225
+msgid "Filters set saved"
+msgstr ""
+
+#: views.py:241
+msgid "Filters set created"
+msgstr ""
+
+#: views.py:246
+msgid "Create a new filters set"
+msgstr ""
+
+#: views.py:265
+msgid "Filters set deleted"
+msgstr ""
+
+#: views.py:278
+msgid "Filters set activated"
+msgstr ""
+
+#: views.py:307
+msgid "yes"
+msgstr ""
+
+#: views.py:311
+msgid "no"
+msgstr ""
diff --git a/modoboa/sievefilters/locale/en/LC_MESSAGES/djangojs.po b/modoboa/sievefilters/locale/en/LC_MESSAGES/djangojs.po
new file mode 100644
index 000000000..a7c3f457c
--- /dev/null
+++ b/modoboa/sievefilters/locale/en/LC_MESSAGES/djangojs.po
@@ -0,0 +1,34 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR , YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2015-02-11 13:54+0100\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME \n"
+"Language-Team: LANGUAGE \n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+#: static/modoboa_sievefilters/js/lib.js:14
+msgid "Remove this filter?"
+msgstr ""
+#: static/modoboa_sievefilters/js/lib.js:107
+msgid "Save changes?"
+msgstr ""
+#: static/modoboa_sievefilters/js/lib.js:129
+msgid "Remove filters set?"
+msgstr ""
+#: static/modoboa_sievefilters/js/lib.js:146
+msgid "Activate this filters set?"
+msgstr ""
+#: static/modoboa_sievefilters/js/lib.js:154
+#: static/modoboa_sievefilters/js/lib.js:203
+msgid "active"
+msgstr ""
diff --git a/modoboa/sievefilters/locale/es/LC_MESSAGES/django.po b/modoboa/sievefilters/locale/es/LC_MESSAGES/django.po
new file mode 100644
index 000000000..7a319918e
--- /dev/null
+++ b/modoboa/sievefilters/locale/es/LC_MESSAGES/django.po
@@ -0,0 +1,364 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# Evilham , 2017
+# Pedro Gracia , 2016
+msgid ""
+msgstr ""
+"Project-Id-Version: Modoboa\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2017-12-01 18:04+0100\n"
+"PO-Revision-Date: 2017-12-01 17:05+0000\n"
+"Last-Translator: Antoine Nguyen \n"
+"Language-Team: Spanish (http://www.transifex.com/tonio/modoboa/language/es/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: es\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: constants.py:6
+msgid "contains"
+msgstr "contiene"
+
+#: constants.py:7
+msgid "does not contain"
+msgstr "no contiene"
+
+#: constants.py:8
+msgid "is"
+msgstr "es"
+
+#: constants.py:9
+msgid "is not"
+msgstr "no es"
+
+#: constants.py:14
+msgid "Subject"
+msgstr "Tema"
+
+#: constants.py:17
+msgid "Sender"
+msgstr "Remitente"
+
+#: constants.py:20
+msgid "Recipient"
+msgstr "Destinatario"
+
+#: constants.py:23
+msgid "Cc"
+msgstr "Cc"
+
+#: constants.py:25
+msgid "Size"
+msgstr "Tamaño"
+
+#: constants.py:26
+msgid "is greater than"
+msgstr "es mayor que"
+
+#: constants.py:27
+msgid "is less than"
+msgstr "es menor que"
+
+#: constants.py:31
+msgid "Move message to"
+msgstr "Mover el mensaje a"
+
+#: constants.py:36 constants.py:44
+msgid "Keep local copy"
+msgstr ""
+
+#: constants.py:40
+msgid "Redirect message to"
+msgstr "Redirigir el mensaje a"
+
+#: constants.py:48
+msgid "Reject message"
+msgstr "Bloquear mensaje"
+
+#: constants.py:50
+msgid "Stop processing"
+msgstr "Detener procesamiento"
+
+#: forms.py:33
+msgid "Check to activate this filters set"
+msgstr "Marcar para activar este conjunto de filtros"
+
+#: forms.py:87 templates/modoboa_sievefilters/guieditor.html:6
+msgid "Name"
+msgstr "Nombre"
+
+#: forms.py:89
+msgid "Match type"
+msgstr ""
+
+#: forms.py:90
+msgid "All of the following"
+msgstr "Todos los siguientes"
+
+#: forms.py:91
+msgid "Any of the following"
+msgstr "Cualquiera de los siguientes"
+
+#: forms.py:92
+msgid "All messages"
+msgstr "Todos los mensajes"
+
+#: forms.py:107
+msgid "Wrong filter name"
+msgstr "Nombre de filtro erróneo"
+
+#: forms.py:351
+msgid "ManageSieve settings"
+msgstr "Configuración de ManageSieve"
+
+#: forms.py:354 forms.py:384
+msgid "Server address"
+msgstr "Dirección del servidor"
+
+#: forms.py:356
+msgid "Address of your MANAGESIEVE server"
+msgstr "Dirección de su servidor MANAGESIEVE"
+
+#: forms.py:361 forms.py:396
+msgid "Server port"
+msgstr "Puerto del servidor"
+
+#: forms.py:363
+msgid "Listening port of your MANAGESIEVE server"
+msgstr "Puerto a la escucha de su servidor MANAGESIEVE"
+
+#: forms.py:368
+msgid "Connect using STARTTLS"
+msgstr "Conectar usando STARTTLS"
+
+#: forms.py:370
+msgid "Use the STARTTLS extension"
+msgstr "Usar la extensión STARTTLS"
+
+#: forms.py:374
+msgid "Authentication mechanism"
+msgstr "Mecanismos de autenticación"
+
+#: forms.py:377
+msgid "Prefered authentication mechanism"
+msgstr "Mecanismo de autenticación preferido"
+
+#: forms.py:381
+msgid "IMAP settings"
+msgstr "Configuración de IMAP"
+
+#: forms.py:386
+msgid "Address of your IMAP server"
+msgstr "Dirección de su servidor IMAP"
+
+#: forms.py:390
+msgid "Use a secured connection"
+msgstr "Usar una conexión segura"
+
+#: forms.py:392
+msgid "Use a secured connection to access IMAP server"
+msgstr "Usar una conexión segura para acceder al servidor IMAP"
+
+#: forms.py:398
+msgid "Listening port of your IMAP server"
+msgstr "Puerto de su servidor IMAP"
+
+#: forms.py:405
+msgid "General"
+msgstr "General"
+
+#: forms.py:409
+msgid "Editor mode"
+msgstr "Modo editor"
+
+#: forms.py:411
+msgid "Select the mode you want the editor to work in"
+msgstr "Seleccione el modo en el que desea que el editor trabaje"
+
+#: forms.py:415
+msgid "Mailboxes"
+msgstr "Mailboxes"
+
+#: forms.py:419
+msgid "Trash folder"
+msgstr "Carpeta de basura"
+
+#: forms.py:420
+msgid "Folder where deleted messages go"
+msgstr "Carpeta dónde van los mensajes eliminados"
+
+#: forms.py:425
+msgid "Sent folder"
+msgstr "Carpeta de enviados"
+
+#: forms.py:426
+msgid "Folder where copies of sent messages go"
+msgstr "Carpeta dónde van las copias de los correos enviados"
+
+#: forms.py:431
+msgid "Drafts folder"
+msgstr "Carpeta de borradores"
+
+#: forms.py:432
+msgid "Folder where drafts go"
+msgstr "Carpeta dónde van los borradores"
+
+#: handlers.py:19 modo_extension.py:26
+#: templates/modoboa_sievefilters/index.html:4
+msgid "Message filters"
+msgstr "Filtros de mensajes"
+
+#: imaputils.py:99
+msgid "Failed to retrieve hierarchy delimiter"
+msgstr "Fallo al recuperar el delimitador jerárquico"
+
+#: imaputils.py:135
+#, python-format
+msgid "Connection to IMAP server failed: %s"
+msgstr "Falló la conexión con el servidor IMAP: %s"
+
+#: lib.py:54
+msgid "Connection to MANAGESIEVE server failed, check your configuration"
+msgstr "La conexión al servidor MANAGESIEVE falló, verifique su configuración."
+
+#: lib.py:98
+msgid "Not enough space on server"
+msgstr "No hay suficiente espacio en el servidor"
+
+#: modo_extension.py:18
+msgid "Plugin to easily create server-side filters"
+msgstr "Extensión para crear filtros en el servidor de forma sencilla"
+
+#: modo_extension.py:24
+msgid "Sieve filters"
+msgstr "filtros Sieve"
+
+#: templates/modoboa_sievefilters/filter.html:9
+msgid "Conditions"
+msgstr "Condiciones"
+
+#: templates/modoboa_sievefilters/filter.html:20
+#: templates/modoboa_sievefilters/guieditor.html:5 views.py:104
+msgid "Actions"
+msgstr "Acciones"
+
+#: templates/modoboa_sievefilters/guieditor.html:7
+msgid "Active"
+msgstr "Activo"
+
+#: templates/modoboa_sievefilters/guieditor.html:24
+msgid "No filter defined yet"
+msgstr "No hay un filtro definido aún"
+
+#: templates/modoboa_sievefilters/index.html:82
+msgid "Filter sets"
+msgstr "Conjunto de filtros"
+
+#: templates/modoboa_sievefilters/index.html:86
+msgid "active"
+msgstr "activo"
+
+#: templates/modoboa_sievefilters/index.html:101
+msgid ""
+"No filters set defined yet. You must create one in order to define filters."
+msgstr "No hay un conjunto de filtros definido aún. Debe crear uno para poder definir filtros."
+
+#: templatetags/sfilters_tags.py:21
+msgid "New filters set"
+msgstr "Nuevo conjunto de filtros"
+
+#: templatetags/sfilters_tags.py:39 views.py:153
+msgid "New filter"
+msgstr "Nuevo filtro"
+
+#: templatetags/sfilters_tags.py:50
+msgid "Save filters set"
+msgstr "Guardar conjunto de filtros"
+
+#: templatetags/sfilters_tags.py:58
+msgid "Activate filters set"
+msgstr "Activar conjunto de filtros"
+
+#: templatetags/sfilters_tags.py:63
+msgid "Remove filters set"
+msgstr "Eliminar conjunto de filtros"
+
+#: templatetags/sfilters_tags.py:67
+msgid "Download"
+msgstr "Descargar"
+
+#: templatetags/sfilters_tags.py:82 views.py:175
+msgid "Edit filter"
+msgstr "Editar filtro"
+
+#: templatetags/sfilters_tags.py:90
+msgid "Remove this filter"
+msgstr "Eliminar este filtro"
+
+#: templatetags/sfilters_tags.py:99
+msgid "Move this filter up"
+msgstr "Subir este filtro"
+
+#: templatetags/sfilters_tags.py:108
+msgid "Move this filter down"
+msgstr "Bajar este filtro"
+
+#: views.py:87
+msgid "Failed to retrieve filters set"
+msgstr "Fallo en la recuperación de un conjunto de filtros"
+
+#: views.py:156 views.py:248
+msgid "Create"
+msgstr "Crear"
+
+#: views.py:161
+msgid "Filter created"
+msgstr "Filtro creado"
+
+#: views.py:179
+msgid "Update"
+msgstr "Actualizar"
+
+#: views.py:186
+msgid "Filter modified"
+msgstr "Filtro modificado"
+
+#: views.py:209
+msgid "Filter removed"
+msgstr "Filtro eliminado"
+
+#: views.py:210
+msgid "Failed to remove filter"
+msgstr "La eliminación del filtro falló"
+
+#: views.py:225
+msgid "Filters set saved"
+msgstr "Filtros guardados"
+
+#: views.py:241
+msgid "Filters set created"
+msgstr "Conjunto de filtros creado"
+
+#: views.py:246
+msgid "Create a new filters set"
+msgstr "Crear un nuevo conjunto de filtros"
+
+#: views.py:265
+msgid "Filters set deleted"
+msgstr "Conjunto de filtros eliminado"
+
+#: views.py:278
+msgid "Filters set activated"
+msgstr "Conjunto de filtros activado"
+
+#: views.py:307
+msgid "yes"
+msgstr "sí"
+
+#: views.py:311
+msgid "no"
+msgstr "no"
diff --git a/modoboa/sievefilters/locale/es/LC_MESSAGES/djangojs.po b/modoboa/sievefilters/locale/es/LC_MESSAGES/djangojs.po
new file mode 100644
index 000000000..22af1f1f0
--- /dev/null
+++ b/modoboa/sievefilters/locale/es/LC_MESSAGES/djangojs.po
@@ -0,0 +1,41 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# Pedro Gracia , 2011,2013
+# Pedro Gracia , 2010-2011
+msgid ""
+msgstr ""
+"Project-Id-Version: Modoboa\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2015-02-11 13:54+0100\n"
+"PO-Revision-Date: 2017-09-22 09:57+0000\n"
+"Last-Translator: Antoine Nguyen \n"
+"Language-Team: Spanish (http://www.transifex.com/tonio/modoboa/language/es/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: es\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: static/modoboa_sievefilters/js/lib.js:14
+msgid "Remove this filter?"
+msgstr "¿Eliminar este filtro?"
+
+#: static/modoboa_sievefilters/js/lib.js:107
+msgid "Save changes?"
+msgstr "¿Guardar cambios?"
+
+#: static/modoboa_sievefilters/js/lib.js:129
+msgid "Remove filters set?"
+msgstr "¿Eliminar este conjunto de filtros?"
+
+#: static/modoboa_sievefilters/js/lib.js:146
+msgid "Activate this filters set?"
+msgstr "¿Activar este conjunto de filtros?"
+
+#: static/modoboa_sievefilters/js/lib.js:154
+#: static/modoboa_sievefilters/js/lib.js:203
+msgid "active"
+msgstr "activo"
diff --git a/modoboa/sievefilters/locale/fr/LC_MESSAGES/django.po b/modoboa/sievefilters/locale/fr/LC_MESSAGES/django.po
new file mode 100644
index 000000000..23a9600b2
--- /dev/null
+++ b/modoboa/sievefilters/locale/fr/LC_MESSAGES/django.po
@@ -0,0 +1,366 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# Antoine Nguyen , 2017
+msgid ""
+msgstr ""
+"Project-Id-Version: Modoboa\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2017-12-01 18:04+0100\n"
+"PO-Revision-Date: 2017-12-01 18:06+0100\n"
+"Last-Translator: Antoine Nguyen \n"
+"Language-Team: French (http://www.transifex.com/tonio/modoboa/language/fr/)\n"
+"Language: fr\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+
+#: constants.py:6
+msgid "contains"
+msgstr "contient"
+
+#: constants.py:7
+msgid "does not contain"
+msgstr "ne contient pas"
+
+#: constants.py:8
+msgid "is"
+msgstr "est"
+
+#: constants.py:9
+msgid "is not"
+msgstr "n'est pas"
+
+#: constants.py:14
+msgid "Subject"
+msgstr "Sujet"
+
+#: constants.py:17
+msgid "Sender"
+msgstr "Expéditeur"
+
+#: constants.py:20
+msgid "Recipient"
+msgstr "Destinataire"
+
+#: constants.py:23
+msgid "Cc"
+msgstr "Cc"
+
+#: constants.py:25
+msgid "Size"
+msgstr "Taille"
+
+#: constants.py:26
+msgid "is greater than"
+msgstr "est supérieure à"
+
+#: constants.py:27
+msgid "is less than"
+msgstr "est inférieure à"
+
+#: constants.py:31
+msgid "Move message to"
+msgstr "Déplacer le message vers"
+
+#: constants.py:36 constants.py:44
+msgid "Keep local copy"
+msgstr "Conserver une copie locale"
+
+#: constants.py:40
+msgid "Redirect message to"
+msgstr "Rediriger le message vers"
+
+#: constants.py:48
+msgid "Reject message"
+msgstr "Rejeter le message"
+
+#: constants.py:50
+msgid "Stop processing"
+msgstr "Arrêter le traitement"
+
+#: forms.py:33
+msgid "Check to activate this filters set"
+msgstr "Cocher pour activer ce jeu de filtres"
+
+#: forms.py:87 templates/modoboa_sievefilters/guieditor.html:6
+msgid "Name"
+msgstr "Nom"
+
+#: forms.py:89
+msgid "Match type"
+msgstr "Correspondance"
+
+#: forms.py:90
+msgid "All of the following"
+msgstr "Toutes les conditions suivantes"
+
+#: forms.py:91
+msgid "Any of the following"
+msgstr "Au moins une des conditions suivantes"
+
+#: forms.py:92
+msgid "All messages"
+msgstr "Tous les messages"
+
+#: forms.py:107
+msgid "Wrong filter name"
+msgstr "Nom de filtre invalide"
+
+#: forms.py:351
+msgid "ManageSieve settings"
+msgstr "Paramètres ManageSieve"
+
+#: forms.py:354 forms.py:384
+msgid "Server address"
+msgstr "Adresse du serveur"
+
+#: forms.py:356
+msgid "Address of your MANAGESIEVE server"
+msgstr "Adresse de votre serveur ManageSieve"
+
+#: forms.py:361 forms.py:396
+msgid "Server port"
+msgstr "Port utilisé par le serveur"
+
+#: forms.py:363
+msgid "Listening port of your MANAGESIEVE server"
+msgstr "Port d'écoute de votre serveur ManageSieve"
+
+#: forms.py:368
+msgid "Connect using STARTTLS"
+msgstr "Se connecter en utilisant STARTTLS"
+
+#: forms.py:370
+msgid "Use the STARTTLS extension"
+msgstr "Utiliser l'extension STARTTLS"
+
+#: forms.py:374
+msgid "Authentication mechanism"
+msgstr "Méthode d'authentification"
+
+#: forms.py:377
+msgid "Prefered authentication mechanism"
+msgstr "Méthode d'authentification préférée"
+
+#: forms.py:381
+msgid "IMAP settings"
+msgstr "Paramètres IMAP"
+
+#: forms.py:386
+msgid "Address of your IMAP server"
+msgstr "Adresse de votre serveur IMAP"
+
+#: forms.py:390
+msgid "Use a secured connection"
+msgstr "Utiliser une connexion sécurisée"
+
+#: forms.py:392
+msgid "Use a secured connection to access IMAP server"
+msgstr "Utiliser une connexion sécurisée pour accéder au serveur IMAP"
+
+#: forms.py:398
+msgid "Listening port of your IMAP server"
+msgstr "Port d'écoute de votre serveur IMAP"
+
+#: forms.py:405
+msgid "General"
+msgstr "Général"
+
+#: forms.py:409
+msgid "Editor mode"
+msgstr "Mode de l'editeur"
+
+#: forms.py:411
+msgid "Select the mode you want the editor to work in"
+msgstr "Sélectionner le mode de fonctionnement de l'éditeur"
+
+#: forms.py:415
+msgid "Mailboxes"
+msgstr "Boîtes aux lettres"
+
+#: forms.py:419
+msgid "Trash folder"
+msgstr "Dossier corbeille"
+
+#: forms.py:420
+msgid "Folder where deleted messages go"
+msgstr "Dossier où vont les messages supprimés"
+
+#: forms.py:425
+msgid "Sent folder"
+msgstr "Dossier d'envoi"
+
+#: forms.py:426
+msgid "Folder where copies of sent messages go"
+msgstr "Dossier où sont copiés les messages envoyés"
+
+#: forms.py:431
+msgid "Drafts folder"
+msgstr "Dossier brouillon"
+
+#: forms.py:432
+msgid "Folder where drafts go"
+msgstr "Dossier où sont stockés les brouillons"
+
+#: handlers.py:19 modo_extension.py:26
+#: templates/modoboa_sievefilters/index.html:4
+msgid "Message filters"
+msgstr "Filtres de messages"
+
+#: imaputils.py:99
+msgid "Failed to retrieve hierarchy delimiter"
+msgstr "Impossible de récupérer le délimiteur de hierarchie"
+
+#: imaputils.py:135
+#, python-format
+msgid "Connection to IMAP server failed: %s"
+msgstr "Échec de connexion au serveur IMAP : %s"
+
+#: lib.py:54
+msgid "Connection to MANAGESIEVE server failed, check your configuration"
+msgstr ""
+"La connexion au serveur ManageSieve a échoué, vérifiez votre configuration"
+
+#: lib.py:98
+msgid "Not enough space on server"
+msgstr "Pas assez d'espace sur le serveur"
+
+#: modo_extension.py:18
+msgid "Plugin to easily create server-side filters"
+msgstr "Extension pour créer simplement des filtres côté serveur"
+
+#: modo_extension.py:24
+msgid "Sieve filters"
+msgstr "Filtres Sieve"
+
+#: templates/modoboa_sievefilters/filter.html:9
+msgid "Conditions"
+msgstr "Conditions"
+
+#: templates/modoboa_sievefilters/filter.html:20
+#: templates/modoboa_sievefilters/guieditor.html:5 views.py:104
+msgid "Actions"
+msgstr "Actions"
+
+#: templates/modoboa_sievefilters/guieditor.html:7
+msgid "Active"
+msgstr "Actif"
+
+#: templates/modoboa_sievefilters/guieditor.html:24
+msgid "No filter defined yet"
+msgstr "Aucun filtre défini."
+
+#: templates/modoboa_sievefilters/index.html:82
+msgid "Filter sets"
+msgstr "Jeux de filtres"
+
+#: templates/modoboa_sievefilters/index.html:86
+msgid "active"
+msgstr "actif"
+
+#: templates/modoboa_sievefilters/index.html:101
+msgid ""
+"No filters set defined yet. You must create one in order to define filters."
+msgstr ""
+"Aucun jeu de filtres défini. Vous devez en créer un pour pouvoir définir des "
+"filtres."
+
+#: templatetags/sfilters_tags.py:21
+msgid "New filters set"
+msgstr "Nouveau jeu de filtres"
+
+#: templatetags/sfilters_tags.py:39 views.py:153
+msgid "New filter"
+msgstr "Nouveau filtre"
+
+#: templatetags/sfilters_tags.py:50
+msgid "Save filters set"
+msgstr "Sauvegarder le jeu de filtres"
+
+#: templatetags/sfilters_tags.py:58
+msgid "Activate filters set"
+msgstr "Activer le jeu de filtres"
+
+#: templatetags/sfilters_tags.py:63
+msgid "Remove filters set"
+msgstr "Supprimer le jeu de filtres"
+
+#: templatetags/sfilters_tags.py:67
+msgid "Download"
+msgstr "Télécharger"
+
+#: templatetags/sfilters_tags.py:82 views.py:175
+msgid "Edit filter"
+msgstr "Editer le filtre"
+
+#: templatetags/sfilters_tags.py:90
+msgid "Remove this filter"
+msgstr "Supprimer ce filtre"
+
+#: templatetags/sfilters_tags.py:99
+msgid "Move this filter up"
+msgstr "Déplacer ce filtre vers le haut"
+
+#: templatetags/sfilters_tags.py:108
+msgid "Move this filter down"
+msgstr "Déplacer ce filtre vers le bas"
+
+#: views.py:87
+msgid "Failed to retrieve filters set"
+msgstr "Impossible de récuperer le jeu de filtres"
+
+#: views.py:156 views.py:248
+msgid "Create"
+msgstr "Créer"
+
+#: views.py:161
+msgid "Filter created"
+msgstr "Filtre créé"
+
+#: views.py:179
+msgid "Update"
+msgstr "Mettre à jour"
+
+#: views.py:186
+msgid "Filter modified"
+msgstr "Filtre modifié"
+
+#: views.py:209
+msgid "Filter removed"
+msgstr "Filtre supprimé"
+
+#: views.py:210
+msgid "Failed to remove filter"
+msgstr "Impossible de supprimer le filtre"
+
+#: views.py:225
+msgid "Filters set saved"
+msgstr "Jeu de filtres sauvegardé"
+
+#: views.py:241
+msgid "Filters set created"
+msgstr "Jeu de filtres créé"
+
+#: views.py:246
+msgid "Create a new filters set"
+msgstr "Créer un nouveau jeu de filtres"
+
+#: views.py:265
+msgid "Filters set deleted"
+msgstr "Jeu de filtres supprimé"
+
+#: views.py:278
+msgid "Filters set activated"
+msgstr "Jeu de filtres activé"
+
+#: views.py:307
+msgid "yes"
+msgstr "oui"
+
+#: views.py:311
+msgid "no"
+msgstr "non"
diff --git a/modoboa/sievefilters/locale/fr/LC_MESSAGES/djangojs.po b/modoboa/sievefilters/locale/fr/LC_MESSAGES/djangojs.po
new file mode 100644
index 000000000..a5d1a80bb
--- /dev/null
+++ b/modoboa/sievefilters/locale/fr/LC_MESSAGES/djangojs.po
@@ -0,0 +1,39 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+msgid ""
+msgstr ""
+"Project-Id-Version: Modoboa\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2015-02-11 13:54+0100\n"
+"PO-Revision-Date: 2017-09-22 09:57+0000\n"
+"Last-Translator: Antoine Nguyen \n"
+"Language-Team: French (http://www.transifex.com/tonio/modoboa/language/fr/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: fr\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+
+#: static/modoboa_sievefilters/js/lib.js:14
+msgid "Remove this filter?"
+msgstr "Supprimer ce filtre?"
+
+#: static/modoboa_sievefilters/js/lib.js:107
+msgid "Save changes?"
+msgstr "Enregistrer les changements?"
+
+#: static/modoboa_sievefilters/js/lib.js:129
+msgid "Remove filters set?"
+msgstr "Supprimer ce jeu de filtres?"
+
+#: static/modoboa_sievefilters/js/lib.js:146
+msgid "Activate this filters set?"
+msgstr "Activer ce jeu de filtres?"
+
+#: static/modoboa_sievefilters/js/lib.js:154
+#: static/modoboa_sievefilters/js/lib.js:203
+msgid "active"
+msgstr "actif"
diff --git a/modoboa/sievefilters/locale/it/LC_MESSAGES/django.po b/modoboa/sievefilters/locale/it/LC_MESSAGES/django.po
new file mode 100644
index 000000000..b9c99de6c
--- /dev/null
+++ b/modoboa/sievefilters/locale/it/LC_MESSAGES/django.po
@@ -0,0 +1,365 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# Giancarlo Gaifas , 2013
+# marcotrevisan , 2018
+# Rocco , 2015
+msgid ""
+msgstr ""
+"Project-Id-Version: Modoboa\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2017-12-01 18:04+0100\n"
+"PO-Revision-Date: 2018-11-01 22:22+0000\n"
+"Last-Translator: marcotrevisan \n"
+"Language-Team: Italian (http://www.transifex.com/tonio/modoboa/language/it/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: it\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: constants.py:6
+msgid "contains"
+msgstr "contiene"
+
+#: constants.py:7
+msgid "does not contain"
+msgstr "non contiene"
+
+#: constants.py:8
+msgid "is"
+msgstr "è"
+
+#: constants.py:9
+msgid "is not"
+msgstr "non è"
+
+#: constants.py:14
+msgid "Subject"
+msgstr "Oggetto"
+
+#: constants.py:17
+msgid "Sender"
+msgstr "Mittente"
+
+#: constants.py:20
+msgid "Recipient"
+msgstr "Destinatario"
+
+#: constants.py:23
+msgid "Cc"
+msgstr "Cc"
+
+#: constants.py:25
+msgid "Size"
+msgstr "Dimensione"
+
+#: constants.py:26
+msgid "is greater than"
+msgstr "è maggiore di"
+
+#: constants.py:27
+msgid "is less than"
+msgstr "è minore di"
+
+#: constants.py:31
+msgid "Move message to"
+msgstr "Sposta il messaggio in"
+
+#: constants.py:36 constants.py:44
+msgid "Keep local copy"
+msgstr "Mantieni copia locale"
+
+#: constants.py:40
+msgid "Redirect message to"
+msgstr "Ridireziona il messaggio a"
+
+#: constants.py:48
+msgid "Reject message"
+msgstr "Rifiuta il messaggio"
+
+#: constants.py:50
+msgid "Stop processing"
+msgstr "Termina l'elaborazione"
+
+#: forms.py:33
+msgid "Check to activate this filters set"
+msgstr "Seleziona per attivare questo insieme di filtri"
+
+#: forms.py:87 templates/modoboa_sievefilters/guieditor.html:6
+msgid "Name"
+msgstr "Nome"
+
+#: forms.py:89
+msgid "Match type"
+msgstr "Tipo di confronto"
+
+#: forms.py:90
+msgid "All of the following"
+msgstr "Tutti i seguenti"
+
+#: forms.py:91
+msgid "Any of the following"
+msgstr "Alcuni dei seguenti"
+
+#: forms.py:92
+msgid "All messages"
+msgstr "Tutti i messaggi"
+
+#: forms.py:107
+msgid "Wrong filter name"
+msgstr "Nome del filtro errato"
+
+#: forms.py:351
+msgid "ManageSieve settings"
+msgstr "Impostazioni ManageSieve"
+
+#: forms.py:354 forms.py:384
+msgid "Server address"
+msgstr "Indirizzo del server"
+
+#: forms.py:356
+msgid "Address of your MANAGESIEVE server"
+msgstr "Indirizzo del tuo server MANAGESIEVE"
+
+#: forms.py:361 forms.py:396
+msgid "Server port"
+msgstr "Porta del server"
+
+#: forms.py:363
+msgid "Listening port of your MANAGESIEVE server"
+msgstr "Porta di ascolto del tuo servere MANAGESIEVE"
+
+#: forms.py:368
+msgid "Connect using STARTTLS"
+msgstr "Connetti utilizzando STARTTLS"
+
+#: forms.py:370
+msgid "Use the STARTTLS extension"
+msgstr "Usa l'estensione STARTTLS"
+
+#: forms.py:374
+msgid "Authentication mechanism"
+msgstr "Meccanismo di autenticazione"
+
+#: forms.py:377
+msgid "Prefered authentication mechanism"
+msgstr "Meccanismo di autenticazione preferito"
+
+#: forms.py:381
+msgid "IMAP settings"
+msgstr "Impostazioni IMAP"
+
+#: forms.py:386
+msgid "Address of your IMAP server"
+msgstr "Indirizzo del server IMAP"
+
+#: forms.py:390
+msgid "Use a secured connection"
+msgstr "Utilizza connessione sicura"
+
+#: forms.py:392
+msgid "Use a secured connection to access IMAP server"
+msgstr "Utilizza una connessione sicura per l'accesso al server IMAP"
+
+#: forms.py:398
+msgid "Listening port of your IMAP server"
+msgstr "Porta in ascolto del server IMAP"
+
+#: forms.py:405
+msgid "General"
+msgstr "Generale"
+
+#: forms.py:409
+msgid "Editor mode"
+msgstr "Modo editor"
+
+#: forms.py:411
+msgid "Select the mode you want the editor to work in"
+msgstr "Seleziona la modalità di lavoro che desideri per l'editor"
+
+#: forms.py:415
+msgid "Mailboxes"
+msgstr "Caselle di posta"
+
+#: forms.py:419
+msgid "Trash folder"
+msgstr "Cestino"
+
+#: forms.py:420
+msgid "Folder where deleted messages go"
+msgstr "Cartella dove finiscono i messaggi eliminati"
+
+#: forms.py:425
+msgid "Sent folder"
+msgstr "Inviati"
+
+#: forms.py:426
+msgid "Folder where copies of sent messages go"
+msgstr "Cartella dove finiscono le copie dei messaggi spediti"
+
+#: forms.py:431
+msgid "Drafts folder"
+msgstr "Bozze"
+
+#: forms.py:432
+msgid "Folder where drafts go"
+msgstr "Cartella dove finiscono le bozze"
+
+#: handlers.py:19 modo_extension.py:26
+#: templates/modoboa_sievefilters/index.html:4
+msgid "Message filters"
+msgstr "Filtri messaggi"
+
+#: imaputils.py:99
+msgid "Failed to retrieve hierarchy delimiter"
+msgstr "Impossibile recuperare il delimitatore delle gerarchie"
+
+#: imaputils.py:135
+#, python-format
+msgid "Connection to IMAP server failed: %s"
+msgstr "Connessione al server IMAP fallita: %s"
+
+#: lib.py:54
+msgid "Connection to MANAGESIEVE server failed, check your configuration"
+msgstr "Connessione al server MANAGESIEVE fallita, controlla la tua configurazione"
+
+#: lib.py:98
+msgid "Not enough space on server"
+msgstr "Non c'è spazio sufficiente nel server"
+
+#: modo_extension.py:18
+msgid "Plugin to easily create server-side filters"
+msgstr "Plugin per creare facilmente filtri lato-server"
+
+#: modo_extension.py:24
+msgid "Sieve filters"
+msgstr "Filtri Sieve"
+
+#: templates/modoboa_sievefilters/filter.html:9
+msgid "Conditions"
+msgstr "Condizioni"
+
+#: templates/modoboa_sievefilters/filter.html:20
+#: templates/modoboa_sievefilters/guieditor.html:5 views.py:104
+msgid "Actions"
+msgstr "Azioni"
+
+#: templates/modoboa_sievefilters/guieditor.html:7
+msgid "Active"
+msgstr "Attivo"
+
+#: templates/modoboa_sievefilters/guieditor.html:24
+msgid "No filter defined yet"
+msgstr "Non ci sono ancora filtri definiti"
+
+#: templates/modoboa_sievefilters/index.html:82
+msgid "Filter sets"
+msgstr "Impostazioni dei filtri"
+
+#: templates/modoboa_sievefilters/index.html:86
+msgid "active"
+msgstr "attivo"
+
+#: templates/modoboa_sievefilters/index.html:101
+msgid ""
+"No filters set defined yet. You must create one in order to define filters."
+msgstr "Non è ancora stato definito alcun gruppo di filtri. Devi crearne uno per definire dei filtri"
+
+#: templatetags/sfilters_tags.py:21
+msgid "New filters set"
+msgstr "Nuovo gruppo di filtri"
+
+#: templatetags/sfilters_tags.py:39 views.py:153
+msgid "New filter"
+msgstr "Nuovo filtro"
+
+#: templatetags/sfilters_tags.py:50
+msgid "Save filters set"
+msgstr "Salva il gruppo di filtri"
+
+#: templatetags/sfilters_tags.py:58
+msgid "Activate filters set"
+msgstr "Attiva gruppo di filtri"
+
+#: templatetags/sfilters_tags.py:63
+msgid "Remove filters set"
+msgstr "Elimina gruppo di filtri"
+
+#: templatetags/sfilters_tags.py:67
+msgid "Download"
+msgstr "Download"
+
+#: templatetags/sfilters_tags.py:82 views.py:175
+msgid "Edit filter"
+msgstr "Modifica filtro"
+
+#: templatetags/sfilters_tags.py:90
+msgid "Remove this filter"
+msgstr "Elimina questo filtro"
+
+#: templatetags/sfilters_tags.py:99
+msgid "Move this filter up"
+msgstr "Sposta questo filtro in alto"
+
+#: templatetags/sfilters_tags.py:108
+msgid "Move this filter down"
+msgstr "Sposta questo filtro in basso "
+
+#: views.py:87
+msgid "Failed to retrieve filters set"
+msgstr "Recupero delle impostazioni di filtro fallito"
+
+#: views.py:156 views.py:248
+msgid "Create"
+msgstr "Crea"
+
+#: views.py:161
+msgid "Filter created"
+msgstr "Filtro creato"
+
+#: views.py:179
+msgid "Update"
+msgstr "Aggiorna"
+
+#: views.py:186
+msgid "Filter modified"
+msgstr "Filtro modificato"
+
+#: views.py:209
+msgid "Filter removed"
+msgstr "Filtro eliminato"
+
+#: views.py:210
+msgid "Failed to remove filter"
+msgstr "Rimozione del filtro fallita"
+
+#: views.py:225
+msgid "Filters set saved"
+msgstr "Gruppo filtri salvato"
+
+#: views.py:241
+msgid "Filters set created"
+msgstr "Gruppo filtri creato"
+
+#: views.py:246
+msgid "Create a new filters set"
+msgstr "Crea un nuovo gruppo di filtri"
+
+#: views.py:265
+msgid "Filters set deleted"
+msgstr "Gruppo filtri eliminato"
+
+#: views.py:278
+msgid "Filters set activated"
+msgstr "Gruppo filtri attivato"
+
+#: views.py:307
+msgid "yes"
+msgstr "si"
+
+#: views.py:311
+msgid "no"
+msgstr "no"
diff --git a/modoboa/sievefilters/locale/it/LC_MESSAGES/djangojs.po b/modoboa/sievefilters/locale/it/LC_MESSAGES/djangojs.po
new file mode 100644
index 000000000..4544e1079
--- /dev/null
+++ b/modoboa/sievefilters/locale/it/LC_MESSAGES/djangojs.po
@@ -0,0 +1,39 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+msgid ""
+msgstr ""
+"Project-Id-Version: Modoboa\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2015-02-11 13:54+0100\n"
+"PO-Revision-Date: 2017-09-22 09:57+0000\n"
+"Last-Translator: Antoine Nguyen \n"
+"Language-Team: Italian (http://www.transifex.com/tonio/modoboa/language/it/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: it\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: static/modoboa_sievefilters/js/lib.js:14
+msgid "Remove this filter?"
+msgstr "Rimuovere questo filtro?"
+
+#: static/modoboa_sievefilters/js/lib.js:107
+msgid "Save changes?"
+msgstr "Salvare le modifiche?"
+
+#: static/modoboa_sievefilters/js/lib.js:129
+msgid "Remove filters set?"
+msgstr "Rimuovere il gruppo di filtri?"
+
+#: static/modoboa_sievefilters/js/lib.js:146
+msgid "Activate this filters set?"
+msgstr "Attivare il gruppo di filtri?"
+
+#: static/modoboa_sievefilters/js/lib.js:154
+#: static/modoboa_sievefilters/js/lib.js:203
+msgid "active"
+msgstr "attivo"
diff --git a/modoboa/sievefilters/locale/nl_NL/LC_MESSAGES/django.po b/modoboa/sievefilters/locale/nl_NL/LC_MESSAGES/django.po
new file mode 100644
index 000000000..bdf421920
--- /dev/null
+++ b/modoboa/sievefilters/locale/nl_NL/LC_MESSAGES/django.po
@@ -0,0 +1,380 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# Andrew , 2014
+# TuxBrother , 2014
+msgid ""
+msgstr ""
+"Project-Id-Version: Modoboa\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2017-12-01 18:04+0100\n"
+"PO-Revision-Date: 2014-12-31 11:37+0000\n"
+"Last-Translator: TuxBrother \n"
+"Language-Team: Dutch (Netherlands) (http://www.transifex.com/projects/p/"
+"modoboa/language/nl_NL/)\n"
+"Language: nl_NL\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: constants.py:6
+msgid "contains"
+msgstr "bevat"
+
+#: constants.py:7
+msgid "does not contain"
+msgstr "bevat niet"
+
+#: constants.py:8
+msgid "is"
+msgstr "is"
+
+#: constants.py:9
+msgid "is not"
+msgstr "is niet"
+
+#: constants.py:14
+msgid "Subject"
+msgstr "Onderwerp"
+
+#: constants.py:17
+msgid "Sender"
+msgstr "Afzender"
+
+#: constants.py:20
+msgid "Recipient"
+msgstr "Ontvanger"
+
+#: constants.py:23
+msgid "Cc"
+msgstr "CC"
+
+#: constants.py:25
+msgid "Size"
+msgstr "Grootte"
+
+#: constants.py:26
+msgid "is greater than"
+msgstr "is groter dan"
+
+#: constants.py:27
+msgid "is less than"
+msgstr "is minder dan"
+
+#: constants.py:31
+msgid "Move message to"
+msgstr "Verplaats bericht naar"
+
+#: constants.py:36 constants.py:44
+msgid "Keep local copy"
+msgstr ""
+
+#: constants.py:40
+msgid "Redirect message to"
+msgstr "Bericht doorsturen naar"
+
+#: constants.py:48
+#, fuzzy
+#| msgid "Redirect message to"
+msgid "Reject message"
+msgstr "Bericht doorsturen naar"
+
+#: constants.py:50
+msgid "Stop processing"
+msgstr ""
+
+#: forms.py:33
+msgid "Check to activate this filters set"
+msgstr "Aanvinken om deze filterset te activeren"
+
+#: forms.py:87 templates/modoboa_sievefilters/guieditor.html:6
+msgid "Name"
+msgstr "Naam"
+
+#: forms.py:89
+msgid "Match type"
+msgstr ""
+
+#: forms.py:90
+msgid "All of the following"
+msgstr "Alles van de volgende"
+
+#: forms.py:91
+msgid "Any of the following"
+msgstr "Elke van het volgende"
+
+#: forms.py:92
+msgid "All messages"
+msgstr "Alle berichten"
+
+#: forms.py:107
+msgid "Wrong filter name"
+msgstr "Verkeerde filter naam"
+
+#: forms.py:351
+msgid "ManageSieve settings"
+msgstr "ManageSieve instellingen"
+
+#: forms.py:354 forms.py:384
+msgid "Server address"
+msgstr "Server adres"
+
+#: forms.py:356
+msgid "Address of your MANAGESIEVE server"
+msgstr "Adres van uw MANAGESIEVE server"
+
+#: forms.py:361 forms.py:396
+msgid "Server port"
+msgstr "Server poort"
+
+#: forms.py:363
+msgid "Listening port of your MANAGESIEVE server"
+msgstr "Poort van uw MANAGESIEVE server"
+
+#: forms.py:368
+msgid "Connect using STARTTLS"
+msgstr "Verbind dmv. STARTTLS"
+
+#: forms.py:370
+msgid "Use the STARTTLS extension"
+msgstr "Gebruik de STARTTLS extensie (aanbevolen)"
+
+#: forms.py:374
+msgid "Authentication mechanism"
+msgstr "Authenticatie mechanisme"
+
+#: forms.py:377
+msgid "Prefered authentication mechanism"
+msgstr "Geprefereerde authenticatie mechanisme"
+
+#: forms.py:381
+#, fuzzy
+#| msgid "ManageSieve settings"
+msgid "IMAP settings"
+msgstr "ManageSieve instellingen"
+
+#: forms.py:386
+#, fuzzy
+#| msgid "Address of your MANAGESIEVE server"
+msgid "Address of your IMAP server"
+msgstr "Adres van uw MANAGESIEVE server"
+
+#: forms.py:390
+msgid "Use a secured connection"
+msgstr ""
+
+#: forms.py:392
+msgid "Use a secured connection to access IMAP server"
+msgstr ""
+
+#: forms.py:398
+#, fuzzy
+#| msgid "Listening port of your MANAGESIEVE server"
+msgid "Listening port of your IMAP server"
+msgstr "Poort van uw MANAGESIEVE server"
+
+#: forms.py:405
+msgid "General"
+msgstr "Algemeen"
+
+#: forms.py:409
+msgid "Editor mode"
+msgstr "Editor mode"
+
+#: forms.py:411
+msgid "Select the mode you want the editor to work in"
+msgstr "Selecteer de mode waarin u de editor wilt hebben"
+
+#: forms.py:415
+msgid "Mailboxes"
+msgstr ""
+
+#: forms.py:419
+msgid "Trash folder"
+msgstr ""
+
+#: forms.py:420
+msgid "Folder where deleted messages go"
+msgstr ""
+
+#: forms.py:425
+msgid "Sent folder"
+msgstr ""
+
+#: forms.py:426
+msgid "Folder where copies of sent messages go"
+msgstr ""
+
+#: forms.py:431
+msgid "Drafts folder"
+msgstr ""
+
+#: forms.py:432
+msgid "Folder where drafts go"
+msgstr ""
+
+#: handlers.py:19 modo_extension.py:26
+#: templates/modoboa_sievefilters/index.html:4
+msgid "Message filters"
+msgstr "Berichtfilters"
+
+#: imaputils.py:99
+#, fuzzy
+#| msgid "Failed to retrieve filters set"
+msgid "Failed to retrieve hierarchy delimiter"
+msgstr "Mislukt om de filterset te te laden"
+
+#: imaputils.py:135
+#, fuzzy, python-format
+#| msgid "Connection to MANAGESIEVE server failed, check your configuration"
+msgid "Connection to IMAP server failed: %s"
+msgstr "Verbinding naar MANAGESIEVE server mislukt, controleer uw configuratie"
+
+#: lib.py:54
+msgid "Connection to MANAGESIEVE server failed, check your configuration"
+msgstr "Verbinding naar MANAGESIEVE server mislukt, controleer uw configuratie"
+
+#: lib.py:98
+msgid "Not enough space on server"
+msgstr "Niet genoeg ruimte beschikbaar op de server"
+
+#: modo_extension.py:18
+msgid "Plugin to easily create server-side filters"
+msgstr ""
+"Plugin om gemakkelijk filters op de server in te stellen (bijvoorbeeld om uw "
+"mail te sorteren)"
+
+#: modo_extension.py:24
+msgid "Sieve filters"
+msgstr "Sieve filters"
+
+#: templates/modoboa_sievefilters/filter.html:9
+msgid "Conditions"
+msgstr "Voorwaarden"
+
+#: templates/modoboa_sievefilters/filter.html:20
+#: templates/modoboa_sievefilters/guieditor.html:5 views.py:104
+msgid "Actions"
+msgstr "Acties"
+
+#: templates/modoboa_sievefilters/guieditor.html:7
+msgid "Active"
+msgstr "Actief"
+
+#: templates/modoboa_sievefilters/guieditor.html:24
+msgid "No filter defined yet"
+msgstr "Nog geen filter aangemaakt"
+
+#: templates/modoboa_sievefilters/index.html:82
+msgid "Filter sets"
+msgstr "Filtersets"
+
+#: templates/modoboa_sievefilters/index.html:86
+msgid "active"
+msgstr "actief"
+
+#: templates/modoboa_sievefilters/index.html:101
+msgid ""
+"No filters set defined yet. You must create one in order to define filters."
+msgstr ""
+"Nog geen filterset gedefinieerd. U moet een filterset aanmaken om filters in "
+"te kunnen stellen."
+
+#: templatetags/sfilters_tags.py:21
+msgid "New filters set"
+msgstr "Nieuwe filterset"
+
+#: templatetags/sfilters_tags.py:39 views.py:153
+msgid "New filter"
+msgstr "Nieuw filter"
+
+#: templatetags/sfilters_tags.py:50
+msgid "Save filters set"
+msgstr "Filterset opslaan"
+
+#: templatetags/sfilters_tags.py:58
+msgid "Activate filters set"
+msgstr "Filterset activeren"
+
+#: templatetags/sfilters_tags.py:63
+msgid "Remove filters set"
+msgstr "Filterset verwijderen"
+
+#: templatetags/sfilters_tags.py:67
+msgid "Download"
+msgstr "Download"
+
+#: templatetags/sfilters_tags.py:82 views.py:175
+msgid "Edit filter"
+msgstr "Filter bewerken"
+
+#: templatetags/sfilters_tags.py:90
+msgid "Remove this filter"
+msgstr "Dit filter verwijderen"
+
+#: templatetags/sfilters_tags.py:99
+msgid "Move this filter up"
+msgstr "Dit filter omhoogplaatsen"
+
+#: templatetags/sfilters_tags.py:108
+msgid "Move this filter down"
+msgstr "Dit filter omlaagplaatsen"
+
+#: views.py:87
+msgid "Failed to retrieve filters set"
+msgstr "Mislukt om de filterset te te laden"
+
+#: views.py:156 views.py:248
+msgid "Create"
+msgstr "Aanmaken"
+
+#: views.py:161
+msgid "Filter created"
+msgstr "Filter aangemaakt"
+
+#: views.py:179
+msgid "Update"
+msgstr "Toepassen"
+
+#: views.py:186
+msgid "Filter modified"
+msgstr "Filter aangepast"
+
+#: views.py:209
+msgid "Filter removed"
+msgstr "Filter verwijderd"
+
+#: views.py:210
+msgid "Failed to remove filter"
+msgstr "Mislukt om het filter te verwijderen"
+
+#: views.py:225
+msgid "Filters set saved"
+msgstr "Filterset opgeslagen"
+
+#: views.py:241
+msgid "Filters set created"
+msgstr "Filterset aangemaakt"
+
+#: views.py:246
+msgid "Create a new filters set"
+msgstr "Maak een nieuwe filterset aan"
+
+#: views.py:265
+msgid "Filters set deleted"
+msgstr "Filterset verwijderd"
+
+#: views.py:278
+msgid "Filters set activated"
+msgstr "Filterset geactiveerd"
+
+#: views.py:307
+msgid "yes"
+msgstr "ja"
+
+#: views.py:311
+msgid "no"
+msgstr "nee"
diff --git a/modoboa/sievefilters/locale/nl_NL/LC_MESSAGES/djangojs.po b/modoboa/sievefilters/locale/nl_NL/LC_MESSAGES/djangojs.po
new file mode 100644
index 000000000..54073170c
--- /dev/null
+++ b/modoboa/sievefilters/locale/nl_NL/LC_MESSAGES/djangojs.po
@@ -0,0 +1,41 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# Ronald Otto , 2017
+# TuxBrother , 2014
+msgid ""
+msgstr ""
+"Project-Id-Version: Modoboa\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2015-02-11 13:54+0100\n"
+"PO-Revision-Date: 2017-09-22 09:57+0000\n"
+"Last-Translator: Ronald Otto \n"
+"Language-Team: Dutch (Netherlands) (http://www.transifex.com/tonio/modoboa/language/nl_NL/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: nl_NL\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: static/modoboa_sievefilters/js/lib.js:14
+msgid "Remove this filter?"
+msgstr "Dit filter verwijderen?"
+
+#: static/modoboa_sievefilters/js/lib.js:107
+msgid "Save changes?"
+msgstr "Wijzigingen opslaan?"
+
+#: static/modoboa_sievefilters/js/lib.js:129
+msgid "Remove filters set?"
+msgstr "Deze filterset verwijderen?"
+
+#: static/modoboa_sievefilters/js/lib.js:146
+msgid "Activate this filters set?"
+msgstr "Wilt u deze filterset activeren?"
+
+#: static/modoboa_sievefilters/js/lib.js:154
+#: static/modoboa_sievefilters/js/lib.js:203
+msgid "active"
+msgstr "actief"
diff --git a/modoboa/sievefilters/locale/pl_PL/LC_MESSAGES/django.po b/modoboa/sievefilters/locale/pl_PL/LC_MESSAGES/django.po
new file mode 100644
index 000000000..5811fa9eb
--- /dev/null
+++ b/modoboa/sievefilters/locale/pl_PL/LC_MESSAGES/django.po
@@ -0,0 +1,365 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# Artur Slowik , 2017
+# Dariusz Koryto , 2016
+# Tomasz Proć , 2017
+msgid ""
+msgstr ""
+"Project-Id-Version: Modoboa\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2017-12-01 18:04+0100\n"
+"PO-Revision-Date: 2017-12-02 10:16+0000\n"
+"Last-Translator: Tomasz Proć \n"
+"Language-Team: Polish (Poland) (http://www.transifex.com/tonio/modoboa/language/pl_PL/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: pl_PL\n"
+"Plural-Forms: nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);\n"
+
+#: constants.py:6
+msgid "contains"
+msgstr "zawiera"
+
+#: constants.py:7
+msgid "does not contain"
+msgstr "nie zawiera"
+
+#: constants.py:8
+msgid "is"
+msgstr "jest"
+
+#: constants.py:9
+msgid "is not"
+msgstr "nie jest"
+
+#: constants.py:14
+msgid "Subject"
+msgstr "Temat"
+
+#: constants.py:17
+msgid "Sender"
+msgstr "Nadawca"
+
+#: constants.py:20
+msgid "Recipient"
+msgstr "Odbioraca"
+
+#: constants.py:23
+msgid "Cc"
+msgstr "DW"
+
+#: constants.py:25
+msgid "Size"
+msgstr "Rozmiar"
+
+#: constants.py:26
+msgid "is greater than"
+msgstr "jest większe niż"
+
+#: constants.py:27
+msgid "is less than"
+msgstr "jest mniejsze niż"
+
+#: constants.py:31
+msgid "Move message to"
+msgstr "Przenieś wiadomość do"
+
+#: constants.py:36 constants.py:44
+msgid "Keep local copy"
+msgstr "Zachowaj kopię"
+
+#: constants.py:40
+msgid "Redirect message to"
+msgstr "Przekieruj wiadomość do"
+
+#: constants.py:48
+msgid "Reject message"
+msgstr "Odrzuć wiadomość"
+
+#: constants.py:50
+msgid "Stop processing"
+msgstr "Zatrzymaj przetwarzanie"
+
+#: forms.py:33
+msgid "Check to activate this filters set"
+msgstr "Zaznacz aby uruchomić ten zestaw filtrów"
+
+#: forms.py:87 templates/modoboa_sievefilters/guieditor.html:6
+msgid "Name"
+msgstr "Nazwa"
+
+#: forms.py:89
+msgid "Match type"
+msgstr "Typ dopasowania"
+
+#: forms.py:90
+msgid "All of the following"
+msgstr "Wszystkie poniższe"
+
+#: forms.py:91
+msgid "Any of the following"
+msgstr "Żadne z poniższych"
+
+#: forms.py:92
+msgid "All messages"
+msgstr "Wszystkie wiadomości"
+
+#: forms.py:107
+msgid "Wrong filter name"
+msgstr "Zła nazwa filtru"
+
+#: forms.py:351
+msgid "ManageSieve settings"
+msgstr "Ustawienia ManageSieve"
+
+#: forms.py:354 forms.py:384
+msgid "Server address"
+msgstr "Adres serwera"
+
+#: forms.py:356
+msgid "Address of your MANAGESIEVE server"
+msgstr "Addres twojego serwera MANAGESIEVE"
+
+#: forms.py:361 forms.py:396
+msgid "Server port"
+msgstr "Port serwera"
+
+#: forms.py:363
+msgid "Listening port of your MANAGESIEVE server"
+msgstr "Port twojego serwera MANAGESIEVE"
+
+#: forms.py:368
+msgid "Connect using STARTTLS"
+msgstr "Połącz używając STARTTLS"
+
+#: forms.py:370
+msgid "Use the STARTTLS extension"
+msgstr "Użyj rozszerzenia STARTTLS"
+
+#: forms.py:374
+msgid "Authentication mechanism"
+msgstr "Mechanizm autentykacji"
+
+#: forms.py:377
+msgid "Prefered authentication mechanism"
+msgstr "Preferowany mechanizm uwierzytelnienia"
+
+#: forms.py:381
+msgid "IMAP settings"
+msgstr "Ustawienia IMAP"
+
+#: forms.py:386
+msgid "Address of your IMAP server"
+msgstr "Adres serwera IMAP"
+
+#: forms.py:390
+msgid "Use a secured connection"
+msgstr "Użyj bezpiecznego polączenia"
+
+#: forms.py:392
+msgid "Use a secured connection to access IMAP server"
+msgstr "Użyj bezpiecznego połączenia do serwera IMAP"
+
+#: forms.py:398
+msgid "Listening port of your IMAP server"
+msgstr "Port, na którym nasłuchuje twój serwer IMAP"
+
+#: forms.py:405
+msgid "General"
+msgstr "Ogólne"
+
+#: forms.py:409
+msgid "Editor mode"
+msgstr "Tryb edycji"
+
+#: forms.py:411
+msgid "Select the mode you want the editor to work in"
+msgstr "Wybierz tryb w jakim ma działać edytor"
+
+#: forms.py:415
+msgid "Mailboxes"
+msgstr "Skrzynki pocztowe"
+
+#: forms.py:419
+msgid "Trash folder"
+msgstr "Folder kosza"
+
+#: forms.py:420
+msgid "Folder where deleted messages go"
+msgstr "Folder, do którego trafiają usunięte wiadomości"
+
+#: forms.py:425
+msgid "Sent folder"
+msgstr "Folder wysłane"
+
+#: forms.py:426
+msgid "Folder where copies of sent messages go"
+msgstr "Folder, do którego trafiają kopie wysłanych wiadomości"
+
+#: forms.py:431
+msgid "Drafts folder"
+msgstr "Folder kopie robocze"
+
+#: forms.py:432
+msgid "Folder where drafts go"
+msgstr "Folder, do którego trafiają kopie robocze"
+
+#: handlers.py:19 modo_extension.py:26
+#: templates/modoboa_sievefilters/index.html:4
+msgid "Message filters"
+msgstr "Filtry wiadomości"
+
+#: imaputils.py:99
+msgid "Failed to retrieve hierarchy delimiter"
+msgstr "Nie udało się rozpoznać hierarchii separatora"
+
+#: imaputils.py:135
+#, python-format
+msgid "Connection to IMAP server failed: %s"
+msgstr "Błąd połączenia do serwera IMAP: %s"
+
+#: lib.py:54
+msgid "Connection to MANAGESIEVE server failed, check your configuration"
+msgstr "Błąd połączenia do serwera MANAGESIEVE: %s, sprawdź konfigurację"
+
+#: lib.py:98
+msgid "Not enough space on server"
+msgstr "Brak miejsca na serwerze"
+
+#: modo_extension.py:18
+msgid "Plugin to easily create server-side filters"
+msgstr "Wtyczka do łatwego tworzenia filtrów po stronie serwera"
+
+#: modo_extension.py:24
+msgid "Sieve filters"
+msgstr "Filtry Sieve"
+
+#: templates/modoboa_sievefilters/filter.html:9
+msgid "Conditions"
+msgstr "Warunki"
+
+#: templates/modoboa_sievefilters/filter.html:20
+#: templates/modoboa_sievefilters/guieditor.html:5 views.py:104
+msgid "Actions"
+msgstr "Akcje"
+
+#: templates/modoboa_sievefilters/guieditor.html:7
+msgid "Active"
+msgstr "Aktywne"
+
+#: templates/modoboa_sievefilters/guieditor.html:24
+msgid "No filter defined yet"
+msgstr "Brak zdefiniowanych filtrów"
+
+#: templates/modoboa_sievefilters/index.html:82
+msgid "Filter sets"
+msgstr "Zestaw filtrów"
+
+#: templates/modoboa_sievefilters/index.html:86
+msgid "active"
+msgstr "aktywny"
+
+#: templates/modoboa_sievefilters/index.html:101
+msgid ""
+"No filters set defined yet. You must create one in order to define filters."
+msgstr "Nie zdefiniowano zestawu filtrów. Musisz utworzyć przynajmniej jeden."
+
+#: templatetags/sfilters_tags.py:21
+msgid "New filters set"
+msgstr "Nowy zestaw filtrów"
+
+#: templatetags/sfilters_tags.py:39 views.py:153
+msgid "New filter"
+msgstr "Nowy filter"
+
+#: templatetags/sfilters_tags.py:50
+msgid "Save filters set"
+msgstr "Zapisz zestaw filtrów"
+
+#: templatetags/sfilters_tags.py:58
+msgid "Activate filters set"
+msgstr "Uruchom zestaw filtrów"
+
+#: templatetags/sfilters_tags.py:63
+msgid "Remove filters set"
+msgstr "Usuń zestaw filtrów"
+
+#: templatetags/sfilters_tags.py:67
+msgid "Download"
+msgstr "Pobierz"
+
+#: templatetags/sfilters_tags.py:82 views.py:175
+msgid "Edit filter"
+msgstr "Edytuj filtr"
+
+#: templatetags/sfilters_tags.py:90
+msgid "Remove this filter"
+msgstr "Usuń ten filtr"
+
+#: templatetags/sfilters_tags.py:99
+msgid "Move this filter up"
+msgstr "Przenieś ten filtr wyżej"
+
+#: templatetags/sfilters_tags.py:108
+msgid "Move this filter down"
+msgstr "Przenieś ten filtr niżej"
+
+#: views.py:87
+msgid "Failed to retrieve filters set"
+msgstr "Nie udało się pobrać zestawu filtrów"
+
+#: views.py:156 views.py:248
+msgid "Create"
+msgstr "Utwórz"
+
+#: views.py:161
+msgid "Filter created"
+msgstr "Filtr utworzony"
+
+#: views.py:179
+msgid "Update"
+msgstr "Zaktualizuj"
+
+#: views.py:186
+msgid "Filter modified"
+msgstr "Filtr zmodyfikowano"
+
+#: views.py:209
+msgid "Filter removed"
+msgstr "Filtr usunięto"
+
+#: views.py:210
+msgid "Failed to remove filter"
+msgstr "Nie udało się usunąć filtru"
+
+#: views.py:225
+msgid "Filters set saved"
+msgstr "Zestaw filtrów zapisano"
+
+#: views.py:241
+msgid "Filters set created"
+msgstr "Zestaw filtrów utworzono"
+
+#: views.py:246
+msgid "Create a new filters set"
+msgstr "Utwórz nowy zestaw filtrów"
+
+#: views.py:265
+msgid "Filters set deleted"
+msgstr "Filtry skasowano"
+
+#: views.py:278
+msgid "Filters set activated"
+msgstr "Filtry usunięto"
+
+#: views.py:307
+msgid "yes"
+msgstr "tak"
+
+#: views.py:311
+msgid "no"
+msgstr "nie"
diff --git a/modoboa/sievefilters/locale/pl_PL/LC_MESSAGES/djangojs.po b/modoboa/sievefilters/locale/pl_PL/LC_MESSAGES/djangojs.po
new file mode 100644
index 000000000..e14691c6f
--- /dev/null
+++ b/modoboa/sievefilters/locale/pl_PL/LC_MESSAGES/djangojs.po
@@ -0,0 +1,41 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# Dariusz Koryto , 2016
+# Tomasz Proć , 2017
+msgid ""
+msgstr ""
+"Project-Id-Version: Modoboa\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2015-02-11 13:54+0100\n"
+"PO-Revision-Date: 2017-12-01 16:15+0000\n"
+"Last-Translator: Tomasz Proć \n"
+"Language-Team: Polish (Poland) (http://www.transifex.com/tonio/modoboa/language/pl_PL/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: pl_PL\n"
+"Plural-Forms: nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);\n"
+
+#: static/modoboa_sievefilters/js/lib.js:14
+msgid "Remove this filter?"
+msgstr "Usunać ten filter?"
+
+#: static/modoboa_sievefilters/js/lib.js:107
+msgid "Save changes?"
+msgstr "Zapisać zmiany?"
+
+#: static/modoboa_sievefilters/js/lib.js:129
+msgid "Remove filters set?"
+msgstr "Usunąć zestaw filtrów?"
+
+#: static/modoboa_sievefilters/js/lib.js:146
+msgid "Activate this filters set?"
+msgstr "Aktywować ten zestaw filtrów? "
+
+#: static/modoboa_sievefilters/js/lib.js:154
+#: static/modoboa_sievefilters/js/lib.js:203
+msgid "active"
+msgstr "aktywne"
diff --git a/modoboa/sievefilters/locale/pt_BR/LC_MESSAGES/django.po b/modoboa/sievefilters/locale/pt_BR/LC_MESSAGES/django.po
new file mode 100644
index 000000000..9e95ab8a5
--- /dev/null
+++ b/modoboa/sievefilters/locale/pt_BR/LC_MESSAGES/django.po
@@ -0,0 +1,367 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# csmk, 2014
+# Felipe Morato , 2017
+# Paulino Michelazzo , 2014-2015
+# Rafael Barretto , 2013
+# Rafael Barretto , 2017-2018
+msgid ""
+msgstr ""
+"Project-Id-Version: Modoboa\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2017-12-01 18:04+0100\n"
+"PO-Revision-Date: 2018-09-25 03:25+0000\n"
+"Last-Translator: Rafael Barretto \n"
+"Language-Team: Portuguese (Brazil) (http://www.transifex.com/tonio/modoboa/language/pt_BR/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: pt_BR\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+
+#: constants.py:6
+msgid "contains"
+msgstr "contém"
+
+#: constants.py:7
+msgid "does not contain"
+msgstr "não contém"
+
+#: constants.py:8
+msgid "is"
+msgstr "é"
+
+#: constants.py:9
+msgid "is not"
+msgstr "não é"
+
+#: constants.py:14
+msgid "Subject"
+msgstr "Assunto"
+
+#: constants.py:17
+msgid "Sender"
+msgstr "Remetente"
+
+#: constants.py:20
+msgid "Recipient"
+msgstr "Destinatário"
+
+#: constants.py:23
+msgid "Cc"
+msgstr "Cc"
+
+#: constants.py:25
+msgid "Size"
+msgstr "Tamanho"
+
+#: constants.py:26
+msgid "is greater than"
+msgstr "é maior que"
+
+#: constants.py:27
+msgid "is less than"
+msgstr "é menor que"
+
+#: constants.py:31
+msgid "Move message to"
+msgstr "Mover mensagem para"
+
+#: constants.py:36 constants.py:44
+msgid "Keep local copy"
+msgstr "Manter cópia local"
+
+#: constants.py:40
+msgid "Redirect message to"
+msgstr "Redirecionar mensagem para"
+
+#: constants.py:48
+msgid "Reject message"
+msgstr "Rejeitar mensagem"
+
+#: constants.py:50
+msgid "Stop processing"
+msgstr "Parar processo"
+
+#: forms.py:33
+msgid "Check to activate this filters set"
+msgstr "Marque para ativar esse conjunto de filtros"
+
+#: forms.py:87 templates/modoboa_sievefilters/guieditor.html:6
+msgid "Name"
+msgstr "Nome"
+
+#: forms.py:89
+msgid "Match type"
+msgstr ""
+
+#: forms.py:90
+msgid "All of the following"
+msgstr "Todas as seguintes"
+
+#: forms.py:91
+msgid "Any of the following"
+msgstr "Uma das seguintes"
+
+#: forms.py:92
+msgid "All messages"
+msgstr "Todas as mensagens"
+
+#: forms.py:107
+msgid "Wrong filter name"
+msgstr "Nome errado do filtro"
+
+#: forms.py:351
+msgid "ManageSieve settings"
+msgstr "Configurações do ManageSieve"
+
+#: forms.py:354 forms.py:384
+msgid "Server address"
+msgstr "Endereço do servidor"
+
+#: forms.py:356
+msgid "Address of your MANAGESIEVE server"
+msgstr "Endereço do servidor MANAGESIEVE"
+
+#: forms.py:361 forms.py:396
+msgid "Server port"
+msgstr "Porta do servidor"
+
+#: forms.py:363
+msgid "Listening port of your MANAGESIEVE server"
+msgstr "Porta de escuta do servidor MANAGESIEVE"
+
+#: forms.py:368
+msgid "Connect using STARTTLS"
+msgstr "Conectar usando STARTTLS"
+
+#: forms.py:370
+msgid "Use the STARTTLS extension"
+msgstr "Usar a extensão STARTTLS "
+
+#: forms.py:374
+msgid "Authentication mechanism"
+msgstr "Mecanismo de autenticação"
+
+#: forms.py:377
+msgid "Prefered authentication mechanism"
+msgstr "Mecanismo de autenticação preferencial"
+
+#: forms.py:381
+msgid "IMAP settings"
+msgstr "Configurações IMAP"
+
+#: forms.py:386
+msgid "Address of your IMAP server"
+msgstr "Endereço do seu servidor IMAP"
+
+#: forms.py:390
+msgid "Use a secured connection"
+msgstr "Usar uma conexão segura"
+
+#: forms.py:392
+msgid "Use a secured connection to access IMAP server"
+msgstr "Usar uma conexão segura para acessar o servidor IMAP"
+
+#: forms.py:398
+msgid "Listening port of your IMAP server"
+msgstr "Porta de escuta do seu servidor IMAP"
+
+#: forms.py:405
+msgid "General"
+msgstr "Geral"
+
+#: forms.py:409
+msgid "Editor mode"
+msgstr "Modo editor"
+
+#: forms.py:411
+msgid "Select the mode you want the editor to work in"
+msgstr "Selecione o modo que você deseja que o editor trabalhe"
+
+#: forms.py:415
+msgid "Mailboxes"
+msgstr "Caixas de correio"
+
+#: forms.py:419
+msgid "Trash folder"
+msgstr "Pasta para Itens Deletados"
+
+#: forms.py:420
+msgid "Folder where deleted messages go"
+msgstr "Pasta que irão as mensagens deletadas"
+
+#: forms.py:425
+msgid "Sent folder"
+msgstr "Pasta para Itens Enviados"
+
+#: forms.py:426
+msgid "Folder where copies of sent messages go"
+msgstr "Pasta onde irão as cópias de mensagens enviadas"
+
+#: forms.py:431
+msgid "Drafts folder"
+msgstr "Pasta para Rascunhos"
+
+#: forms.py:432
+msgid "Folder where drafts go"
+msgstr "Pasta onde irão os rascunhos"
+
+#: handlers.py:19 modo_extension.py:26
+#: templates/modoboa_sievefilters/index.html:4
+msgid "Message filters"
+msgstr "Filtros de mensagem"
+
+#: imaputils.py:99
+msgid "Failed to retrieve hierarchy delimiter"
+msgstr "Falha ao recuperar o delimitador de hierarquia"
+
+#: imaputils.py:135
+#, python-format
+msgid "Connection to IMAP server failed: %s"
+msgstr "Falha ao conectar no servidor IMAP: %s"
+
+#: lib.py:54
+msgid "Connection to MANAGESIEVE server failed, check your configuration"
+msgstr "Conexão com o servidor MANAGESIEVE falhou, verifique sua configuração"
+
+#: lib.py:98
+msgid "Not enough space on server"
+msgstr "Espaço no servidor insuficiente"
+
+#: modo_extension.py:18
+msgid "Plugin to easily create server-side filters"
+msgstr "Plugin para criar facilmente filtros 'server-side'"
+
+#: modo_extension.py:24
+msgid "Sieve filters"
+msgstr "Filtros do Sieve"
+
+#: templates/modoboa_sievefilters/filter.html:9
+msgid "Conditions"
+msgstr "Condições"
+
+#: templates/modoboa_sievefilters/filter.html:20
+#: templates/modoboa_sievefilters/guieditor.html:5 views.py:104
+msgid "Actions"
+msgstr "Ações"
+
+#: templates/modoboa_sievefilters/guieditor.html:7
+msgid "Active"
+msgstr "Ativo"
+
+#: templates/modoboa_sievefilters/guieditor.html:24
+msgid "No filter defined yet"
+msgstr "Sem filtros definidos"
+
+#: templates/modoboa_sievefilters/index.html:82
+msgid "Filter sets"
+msgstr "Conjuntos de filtros"
+
+#: templates/modoboa_sievefilters/index.html:86
+msgid "active"
+msgstr "ativo"
+
+#: templates/modoboa_sievefilters/index.html:101
+msgid ""
+"No filters set defined yet. You must create one in order to define filters."
+msgstr "Nenhum conjunto de filtros ainda definido. Você deve criar um para poder definir filtros."
+
+#: templatetags/sfilters_tags.py:21
+msgid "New filters set"
+msgstr "Novo conjunto de filtros"
+
+#: templatetags/sfilters_tags.py:39 views.py:153
+msgid "New filter"
+msgstr "Novo filtro"
+
+#: templatetags/sfilters_tags.py:50
+msgid "Save filters set"
+msgstr "Salvar conjunto de filtros"
+
+#: templatetags/sfilters_tags.py:58
+msgid "Activate filters set"
+msgstr "Ativar conjunto de filtros"
+
+#: templatetags/sfilters_tags.py:63
+msgid "Remove filters set"
+msgstr "Remover conjunto de filtros"
+
+#: templatetags/sfilters_tags.py:67
+msgid "Download"
+msgstr "Baixar"
+
+#: templatetags/sfilters_tags.py:82 views.py:175
+msgid "Edit filter"
+msgstr "Editar filtro"
+
+#: templatetags/sfilters_tags.py:90
+msgid "Remove this filter"
+msgstr "Remover esse filtro"
+
+#: templatetags/sfilters_tags.py:99
+msgid "Move this filter up"
+msgstr "Mover esse filtro para cima"
+
+#: templatetags/sfilters_tags.py:108
+msgid "Move this filter down"
+msgstr "Mover esse filtro para baixo"
+
+#: views.py:87
+msgid "Failed to retrieve filters set"
+msgstr "Falha ao recuperar conjunto de filtros"
+
+#: views.py:156 views.py:248
+msgid "Create"
+msgstr "Criar"
+
+#: views.py:161
+msgid "Filter created"
+msgstr "Filtro criado"
+
+#: views.py:179
+msgid "Update"
+msgstr "Atualizar"
+
+#: views.py:186
+msgid "Filter modified"
+msgstr "Filtro modificado"
+
+#: views.py:209
+msgid "Filter removed"
+msgstr "Filtro removido"
+
+#: views.py:210
+msgid "Failed to remove filter"
+msgstr "Falha ao remover filtro"
+
+#: views.py:225
+msgid "Filters set saved"
+msgstr "Conjunto de filtros salvo"
+
+#: views.py:241
+msgid "Filters set created"
+msgstr "Conjunto de filtros criado"
+
+#: views.py:246
+msgid "Create a new filters set"
+msgstr "Criar um novo conjunto de filtros"
+
+#: views.py:265
+msgid "Filters set deleted"
+msgstr "Conjunto de filtros apagados"
+
+#: views.py:278
+msgid "Filters set activated"
+msgstr "Conjuntos de filtros ativados"
+
+#: views.py:307
+msgid "yes"
+msgstr "sim"
+
+#: views.py:311
+msgid "no"
+msgstr "não"
diff --git a/modoboa/sievefilters/locale/pt_BR/LC_MESSAGES/djangojs.po b/modoboa/sievefilters/locale/pt_BR/LC_MESSAGES/djangojs.po
new file mode 100644
index 000000000..c47186dfe
--- /dev/null
+++ b/modoboa/sievefilters/locale/pt_BR/LC_MESSAGES/djangojs.po
@@ -0,0 +1,40 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# Paulino Michelazzo , 2014
+msgid ""
+msgstr ""
+"Project-Id-Version: Modoboa\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2015-02-11 13:54+0100\n"
+"PO-Revision-Date: 2017-09-23 21:21+0000\n"
+"Last-Translator: Paulino Michelazzo \n"
+"Language-Team: Portuguese (Brazil) (http://www.transifex.com/tonio/modoboa/language/pt_BR/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: pt_BR\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+
+#: static/modoboa_sievefilters/js/lib.js:14
+msgid "Remove this filter?"
+msgstr "Remover este filtro?"
+
+#: static/modoboa_sievefilters/js/lib.js:107
+msgid "Save changes?"
+msgstr "Salvar alterações?"
+
+#: static/modoboa_sievefilters/js/lib.js:129
+msgid "Remove filters set?"
+msgstr "Remover conjunto de filtros?"
+
+#: static/modoboa_sievefilters/js/lib.js:146
+msgid "Activate this filters set?"
+msgstr "Ativar este conjunto de filtros?"
+
+#: static/modoboa_sievefilters/js/lib.js:154
+#: static/modoboa_sievefilters/js/lib.js:203
+msgid "active"
+msgstr "ativo"
diff --git a/modoboa/sievefilters/locale/pt_PT/LC_MESSAGES/django.po b/modoboa/sievefilters/locale/pt_PT/LC_MESSAGES/django.po
new file mode 100644
index 000000000..a7ed3d719
--- /dev/null
+++ b/modoboa/sievefilters/locale/pt_PT/LC_MESSAGES/django.po
@@ -0,0 +1,381 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# Damien Duponchelle , 2013
+# lusitan , 2013
+# Mike C. , 2012
+# Mike C. , 2013-2014
+# Sandra Ribeiro , 2012-2013
+# Sandra Ribeiro , 2012
+msgid ""
+msgstr ""
+"Project-Id-Version: Modoboa\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2017-12-01 18:04+0100\n"
+"PO-Revision-Date: 2014-12-29 12:51+0000\n"
+"Last-Translator: Mike C. \n"
+"Language-Team: Portuguese (Portugal) (http://www.transifex.com/projects/p/"
+"modoboa/language/pt_PT/)\n"
+"Language: pt_PT\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: constants.py:6
+msgid "contains"
+msgstr "contém"
+
+#: constants.py:7
+msgid "does not contain"
+msgstr "não contém"
+
+#: constants.py:8
+msgid "is"
+msgstr "é"
+
+#: constants.py:9
+msgid "is not"
+msgstr "não é"
+
+#: constants.py:14
+msgid "Subject"
+msgstr "Assunto"
+
+#: constants.py:17
+msgid "Sender"
+msgstr "Remetente"
+
+#: constants.py:20
+msgid "Recipient"
+msgstr "Destinatário"
+
+#: constants.py:23
+msgid "Cc"
+msgstr "Cc"
+
+#: constants.py:25
+msgid "Size"
+msgstr "Tamanho"
+
+#: constants.py:26
+msgid "is greater than"
+msgstr "é maior do que"
+
+#: constants.py:27
+msgid "is less than"
+msgstr "é menor do que"
+
+#: constants.py:31
+msgid "Move message to"
+msgstr "Mover mensagens para"
+
+#: constants.py:36 constants.py:44
+msgid "Keep local copy"
+msgstr ""
+
+#: constants.py:40
+msgid "Redirect message to"
+msgstr "Reencaminhar mensagens para"
+
+#: constants.py:48
+#, fuzzy
+#| msgid "Redirect message to"
+msgid "Reject message"
+msgstr "Reencaminhar mensagens para"
+
+#: constants.py:50
+msgid "Stop processing"
+msgstr ""
+
+#: forms.py:33
+msgid "Check to activate this filters set"
+msgstr "Marque para ativar estes filtros"
+
+#: forms.py:87 templates/modoboa_sievefilters/guieditor.html:6
+msgid "Name"
+msgstr "Nome"
+
+#: forms.py:89
+msgid "Match type"
+msgstr ""
+
+#: forms.py:90
+msgid "All of the following"
+msgstr "Todos estes"
+
+#: forms.py:91
+msgid "Any of the following"
+msgstr "Algum destes"
+
+#: forms.py:92
+msgid "All messages"
+msgstr "Todas as mensagens"
+
+#: forms.py:107
+msgid "Wrong filter name"
+msgstr "Filtro inválido"
+
+#: forms.py:351
+msgid "ManageSieve settings"
+msgstr "Definições do MANAGESIEVE"
+
+#: forms.py:354 forms.py:384
+msgid "Server address"
+msgstr "Endereço do Servidor"
+
+#: forms.py:356
+msgid "Address of your MANAGESIEVE server"
+msgstr "Endereço do servidor MANAGESIEVE"
+
+#: forms.py:361 forms.py:396
+msgid "Server port"
+msgstr "Porta do Servidor"
+
+#: forms.py:363
+msgid "Listening port of your MANAGESIEVE server"
+msgstr "Porta atribuída ao servidor MANAGESIEVE"
+
+#: forms.py:368
+msgid "Connect using STARTTLS"
+msgstr "Ligar via STARTTLS"
+
+#: forms.py:370
+msgid "Use the STARTTLS extension"
+msgstr "Usar a extensão STARTLS"
+
+#: forms.py:374
+msgid "Authentication mechanism"
+msgstr "Mecanismo de autenticação"
+
+#: forms.py:377
+msgid "Prefered authentication mechanism"
+msgstr "Método de autenticação preferencial"
+
+#: forms.py:381
+#, fuzzy
+#| msgid "ManageSieve settings"
+msgid "IMAP settings"
+msgstr "Definições do MANAGESIEVE"
+
+#: forms.py:386
+#, fuzzy
+#| msgid "Address of your MANAGESIEVE server"
+msgid "Address of your IMAP server"
+msgstr "Endereço do servidor MANAGESIEVE"
+
+#: forms.py:390
+msgid "Use a secured connection"
+msgstr ""
+
+#: forms.py:392
+msgid "Use a secured connection to access IMAP server"
+msgstr ""
+
+#: forms.py:398
+#, fuzzy
+#| msgid "Listening port of your MANAGESIEVE server"
+msgid "Listening port of your IMAP server"
+msgstr "Porta atribuída ao servidor MANAGESIEVE"
+
+#: forms.py:405
+msgid "General"
+msgstr "Geral"
+
+#: forms.py:409
+msgid "Editor mode"
+msgstr "Modo de edição"
+
+#: forms.py:411
+msgid "Select the mode you want the editor to work in"
+msgstr "Seleccione o modo de funcionamento do editor"
+
+#: forms.py:415
+msgid "Mailboxes"
+msgstr ""
+
+#: forms.py:419
+msgid "Trash folder"
+msgstr ""
+
+#: forms.py:420
+msgid "Folder where deleted messages go"
+msgstr ""
+
+#: forms.py:425
+msgid "Sent folder"
+msgstr ""
+
+#: forms.py:426
+msgid "Folder where copies of sent messages go"
+msgstr ""
+
+#: forms.py:431
+msgid "Drafts folder"
+msgstr ""
+
+#: forms.py:432
+msgid "Folder where drafts go"
+msgstr ""
+
+#: handlers.py:19 modo_extension.py:26
+#: templates/modoboa_sievefilters/index.html:4
+msgid "Message filters"
+msgstr "Gerir filtros"
+
+#: imaputils.py:99
+#, fuzzy
+#| msgid "Failed to retrieve filters set"
+msgid "Failed to retrieve hierarchy delimiter"
+msgstr "Falha ao recuperar os filtros definidos"
+
+#: imaputils.py:135
+#, fuzzy, python-format
+#| msgid "Connection to MANAGESIEVE server failed, check your configuration"
+msgid "Connection to IMAP server failed: %s"
+msgstr "Ligação ao servidor MANAGESIEVE falhou, valide a configuração"
+
+#: lib.py:54
+msgid "Connection to MANAGESIEVE server failed, check your configuration"
+msgstr "Ligação ao servidor MANAGESIEVE falhou, valide a configuração"
+
+#: lib.py:98
+msgid "Not enough space on server"
+msgstr "Espaço insuficiente no servidor"
+
+#: modo_extension.py:18
+msgid "Plugin to easily create server-side filters"
+msgstr "Plugin para criar facilmente filtros 'server-side'"
+
+#: modo_extension.py:24
+msgid "Sieve filters"
+msgstr "Filtros Sieve"
+
+#: templates/modoboa_sievefilters/filter.html:9
+msgid "Conditions"
+msgstr "Condições"
+
+#: templates/modoboa_sievefilters/filter.html:20
+#: templates/modoboa_sievefilters/guieditor.html:5 views.py:104
+msgid "Actions"
+msgstr "Ações"
+
+#: templates/modoboa_sievefilters/guieditor.html:7
+msgid "Active"
+msgstr "Ativo"
+
+#: templates/modoboa_sievefilters/guieditor.html:24
+msgid "No filter defined yet"
+msgstr "Ainda não existe nenhum filtro definido"
+
+#: templates/modoboa_sievefilters/index.html:82
+msgid "Filter sets"
+msgstr "Grupos de filtros"
+
+#: templates/modoboa_sievefilters/index.html:86
+msgid "active"
+msgstr "ativo"
+
+#: templates/modoboa_sievefilters/index.html:101
+msgid ""
+"No filters set defined yet. You must create one in order to define filters."
+msgstr ""
+"Não existem grupos de filtros. Terá de criar um para poder definir filtros."
+
+#: templatetags/sfilters_tags.py:21
+msgid "New filters set"
+msgstr "Novo grupo de filtros"
+
+#: templatetags/sfilters_tags.py:39 views.py:153
+msgid "New filter"
+msgstr "Novo filtro"
+
+#: templatetags/sfilters_tags.py:50
+msgid "Save filters set"
+msgstr "Guardar grupo de filtros"
+
+#: templatetags/sfilters_tags.py:58
+msgid "Activate filters set"
+msgstr "Ativar grupo de filtros"
+
+#: templatetags/sfilters_tags.py:63
+msgid "Remove filters set"
+msgstr "Eliminar grupo de filtros"
+
+#: templatetags/sfilters_tags.py:67
+msgid "Download"
+msgstr "Descarregar"
+
+#: templatetags/sfilters_tags.py:82 views.py:175
+msgid "Edit filter"
+msgstr "Editar filtro"
+
+#: templatetags/sfilters_tags.py:90
+msgid "Remove this filter"
+msgstr "Eliminar este filtro"
+
+#: templatetags/sfilters_tags.py:99
+msgid "Move this filter up"
+msgstr "Mover este filtro para cima"
+
+#: templatetags/sfilters_tags.py:108
+msgid "Move this filter down"
+msgstr "Mover este filtro para baixo"
+
+#: views.py:87
+msgid "Failed to retrieve filters set"
+msgstr "Falha ao recuperar os filtros definidos"
+
+#: views.py:156 views.py:248
+msgid "Create"
+msgstr "Criar"
+
+#: views.py:161
+msgid "Filter created"
+msgstr "Filtro criado"
+
+#: views.py:179
+msgid "Update"
+msgstr "Actualizar"
+
+#: views.py:186
+msgid "Filter modified"
+msgstr "Filtro modificado"
+
+#: views.py:209
+msgid "Filter removed"
+msgstr "Filtro removido"
+
+#: views.py:210
+msgid "Failed to remove filter"
+msgstr "Falha ao remover filtro"
+
+#: views.py:225
+msgid "Filters set saved"
+msgstr "Grupo de filtros guardado"
+
+#: views.py:241
+msgid "Filters set created"
+msgstr "Grupo de filtros criado"
+
+#: views.py:246
+msgid "Create a new filters set"
+msgstr "Criar novo grupo de filtros"
+
+#: views.py:265
+msgid "Filters set deleted"
+msgstr "Grupo de filtros eliminado"
+
+#: views.py:278
+msgid "Filters set activated"
+msgstr "Grupo de filtros ativado"
+
+#: views.py:307
+msgid "yes"
+msgstr "sim"
+
+#: views.py:311
+msgid "no"
+msgstr "não"
diff --git a/modoboa/sievefilters/locale/pt_PT/LC_MESSAGES/djangojs.po b/modoboa/sievefilters/locale/pt_PT/LC_MESSAGES/djangojs.po
new file mode 100644
index 000000000..5958ad167
--- /dev/null
+++ b/modoboa/sievefilters/locale/pt_PT/LC_MESSAGES/djangojs.po
@@ -0,0 +1,42 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# lusitan , 2013
+# Mike C. , 2012,2014
+# Sandra Ribeiro , 2013
+msgid ""
+msgstr ""
+"Project-Id-Version: Modoboa\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2015-02-11 13:54+0100\n"
+"PO-Revision-Date: 2017-09-22 09:57+0000\n"
+"Last-Translator: Antoine Nguyen \n"
+"Language-Team: Portuguese (Portugal) (http://www.transifex.com/tonio/modoboa/language/pt_PT/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: pt_PT\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: static/modoboa_sievefilters/js/lib.js:14
+msgid "Remove this filter?"
+msgstr "Remover este filtro?"
+
+#: static/modoboa_sievefilters/js/lib.js:107
+msgid "Save changes?"
+msgstr "Guardar alterações?"
+
+#: static/modoboa_sievefilters/js/lib.js:129
+msgid "Remove filters set?"
+msgstr "Limpar filtros definidos?"
+
+#: static/modoboa_sievefilters/js/lib.js:146
+msgid "Activate this filters set?"
+msgstr "Activar estes filtros?"
+
+#: static/modoboa_sievefilters/js/lib.js:154
+#: static/modoboa_sievefilters/js/lib.js:203
+msgid "active"
+msgstr "activo"
diff --git a/modoboa/sievefilters/locale/ru/LC_MESSAGES/django.po b/modoboa/sievefilters/locale/ru/LC_MESSAGES/django.po
new file mode 100644
index 000000000..827376069
--- /dev/null
+++ b/modoboa/sievefilters/locale/ru/LC_MESSAGES/django.po
@@ -0,0 +1,364 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# Ravil Kadyrbayev, 2015
+# Yuriy Matskanyuk , 2018
+msgid ""
+msgstr ""
+"Project-Id-Version: Modoboa\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2017-12-01 18:04+0100\n"
+"PO-Revision-Date: 2018-11-27 18:02+0000\n"
+"Last-Translator: Yuriy Matskanyuk \n"
+"Language-Team: Russian (http://www.transifex.com/tonio/modoboa/language/ru/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: ru\n"
+"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);\n"
+
+#: constants.py:6
+msgid "contains"
+msgstr "содержит"
+
+#: constants.py:7
+msgid "does not contain"
+msgstr "не содержит"
+
+#: constants.py:8
+msgid "is"
+msgstr "является"
+
+#: constants.py:9
+msgid "is not"
+msgstr "не"
+
+#: constants.py:14
+msgid "Subject"
+msgstr "Тема"
+
+#: constants.py:17
+msgid "Sender"
+msgstr "Отправитель"
+
+#: constants.py:20
+msgid "Recipient"
+msgstr "Получатель"
+
+#: constants.py:23
+msgid "Cc"
+msgstr "Копия"
+
+#: constants.py:25
+msgid "Size"
+msgstr "размер"
+
+#: constants.py:26
+msgid "is greater than"
+msgstr "больше"
+
+#: constants.py:27
+msgid "is less than"
+msgstr "меньше"
+
+#: constants.py:31
+msgid "Move message to"
+msgstr "Переместить сообщение"
+
+#: constants.py:36 constants.py:44
+msgid "Keep local copy"
+msgstr ""
+
+#: constants.py:40
+msgid "Redirect message to"
+msgstr "Перенаправление сообщение для"
+
+#: constants.py:48
+msgid "Reject message"
+msgstr ""
+
+#: constants.py:50
+msgid "Stop processing"
+msgstr "Остановить обработку"
+
+#: forms.py:33
+msgid "Check to activate this filters set"
+msgstr "Проверьте, чтобы активировать этот набор фильтров"
+
+#: forms.py:87 templates/modoboa_sievefilters/guieditor.html:6
+msgid "Name"
+msgstr "Логин"
+
+#: forms.py:89
+msgid "Match type"
+msgstr ""
+
+#: forms.py:90
+msgid "All of the following"
+msgstr "Любое из следующих"
+
+#: forms.py:91
+msgid "Any of the following"
+msgstr "Любое из следующих"
+
+#: forms.py:92
+msgid "All messages"
+msgstr "Все сообщения"
+
+#: forms.py:107
+msgid "Wrong filter name"
+msgstr "Неверное имя фильтра"
+
+#: forms.py:351
+msgid "ManageSieve settings"
+msgstr "Настройки фильтров содержания"
+
+#: forms.py:354 forms.py:384
+msgid "Server address"
+msgstr "Адрес сервера"
+
+#: forms.py:356
+msgid "Address of your MANAGESIEVE server"
+msgstr "Адрес вашего MANAGESIEVE сервера"
+
+#: forms.py:361 forms.py:396
+msgid "Server port"
+msgstr "Порт сервера"
+
+#: forms.py:363
+msgid "Listening port of your MANAGESIEVE server"
+msgstr "Порт вашего MANAGESIEVE сервера"
+
+#: forms.py:368
+msgid "Connect using STARTTLS"
+msgstr "Подключение с помощью STARTTLS"
+
+#: forms.py:370
+msgid "Use the STARTTLS extension"
+msgstr "Используйте расширение STARTTLS"
+
+#: forms.py:374
+msgid "Authentication mechanism"
+msgstr "Механизм аутентификации"
+
+#: forms.py:377
+msgid "Prefered authentication mechanism"
+msgstr "Предпочтительный механизм аутентификации"
+
+#: forms.py:381
+msgid "IMAP settings"
+msgstr ""
+
+#: forms.py:386
+msgid "Address of your IMAP server"
+msgstr ""
+
+#: forms.py:390
+msgid "Use a secured connection"
+msgstr "Использовать защищенное соединение"
+
+#: forms.py:392
+msgid "Use a secured connection to access IMAP server"
+msgstr ""
+
+#: forms.py:398
+msgid "Listening port of your IMAP server"
+msgstr ""
+
+#: forms.py:405
+msgid "General"
+msgstr "Основные"
+
+#: forms.py:409
+msgid "Editor mode"
+msgstr "Режим редактирования"
+
+#: forms.py:411
+msgid "Select the mode you want the editor to work in"
+msgstr "Выберите нужный режим для работы редактора"
+
+#: forms.py:415
+msgid "Mailboxes"
+msgstr "Почтовые ящики"
+
+#: forms.py:419
+msgid "Trash folder"
+msgstr "Корзина"
+
+#: forms.py:420
+msgid "Folder where deleted messages go"
+msgstr ""
+
+#: forms.py:425
+msgid "Sent folder"
+msgstr "Отправленные"
+
+#: forms.py:426
+msgid "Folder where copies of sent messages go"
+msgstr ""
+
+#: forms.py:431
+msgid "Drafts folder"
+msgstr "Черновики"
+
+#: forms.py:432
+msgid "Folder where drafts go"
+msgstr ""
+
+#: handlers.py:19 modo_extension.py:26
+#: templates/modoboa_sievefilters/index.html:4
+msgid "Message filters"
+msgstr "Фильтры сообщений"
+
+#: imaputils.py:99
+msgid "Failed to retrieve hierarchy delimiter"
+msgstr ""
+
+#: imaputils.py:135
+#, python-format
+msgid "Connection to IMAP server failed: %s"
+msgstr ""
+
+#: lib.py:54
+msgid "Connection to MANAGESIEVE server failed, check your configuration"
+msgstr "Соединение с сервером MANAGESIEVE не удалось, проверьте конфигурацию"
+
+#: lib.py:98
+msgid "Not enough space on server"
+msgstr "Нет свободного места на сервере"
+
+#: modo_extension.py:18
+msgid "Plugin to easily create server-side filters"
+msgstr "Плагин позволяет создавать фильтры на сервере"
+
+#: modo_extension.py:24
+msgid "Sieve filters"
+msgstr "Фильтры содержания"
+
+#: templates/modoboa_sievefilters/filter.html:9
+msgid "Conditions"
+msgstr "Соответствие"
+
+#: templates/modoboa_sievefilters/filter.html:20
+#: templates/modoboa_sievefilters/guieditor.html:5 views.py:104
+msgid "Actions"
+msgstr "Действие"
+
+#: templates/modoboa_sievefilters/guieditor.html:7
+msgid "Active"
+msgstr "Активно"
+
+#: templates/modoboa_sievefilters/guieditor.html:24
+msgid "No filter defined yet"
+msgstr "Фильтры не определены"
+
+#: templates/modoboa_sievefilters/index.html:82
+msgid "Filter sets"
+msgstr "Набор фильтров"
+
+#: templates/modoboa_sievefilters/index.html:86
+msgid "active"
+msgstr "Активно"
+
+#: templates/modoboa_sievefilters/index.html:101
+msgid ""
+"No filters set defined yet. You must create one in order to define filters."
+msgstr "Фильтры не определены. Вы должны определить и установить фильтры "
+
+#: templatetags/sfilters_tags.py:21
+msgid "New filters set"
+msgstr "Новый набор фильтров"
+
+#: templatetags/sfilters_tags.py:39 views.py:153
+msgid "New filter"
+msgstr "Новый фильтр"
+
+#: templatetags/sfilters_tags.py:50
+msgid "Save filters set"
+msgstr "Сохранить набор фильтров"
+
+#: templatetags/sfilters_tags.py:58
+msgid "Activate filters set"
+msgstr "Активировать набор фильтров"
+
+#: templatetags/sfilters_tags.py:63
+msgid "Remove filters set"
+msgstr "Удалить набор фильтров"
+
+#: templatetags/sfilters_tags.py:67
+msgid "Download"
+msgstr "Загрузить"
+
+#: templatetags/sfilters_tags.py:82 views.py:175
+msgid "Edit filter"
+msgstr "Редактировать фильтр"
+
+#: templatetags/sfilters_tags.py:90
+msgid "Remove this filter"
+msgstr "Удалить этот фильтр"
+
+#: templatetags/sfilters_tags.py:99
+msgid "Move this filter up"
+msgstr "Переместить этот фильтр выше"
+
+#: templatetags/sfilters_tags.py:108
+msgid "Move this filter down"
+msgstr "Переместить этот фильтр ниже"
+
+#: views.py:87
+msgid "Failed to retrieve filters set"
+msgstr "Не удалось получить набор фильтров"
+
+#: views.py:156 views.py:248
+msgid "Create"
+msgstr "Создать"
+
+#: views.py:161
+msgid "Filter created"
+msgstr "Фильтр создан"
+
+#: views.py:179
+msgid "Update"
+msgstr "Обновление"
+
+#: views.py:186
+msgid "Filter modified"
+msgstr "Фильтр модифицирован"
+
+#: views.py:209
+msgid "Filter removed"
+msgstr "Фильтр удален"
+
+#: views.py:210
+msgid "Failed to remove filter"
+msgstr "Ошибка удаления фильтра"
+
+#: views.py:225
+msgid "Filters set saved"
+msgstr "Набор фильтров сохранен"
+
+#: views.py:241
+msgid "Filters set created"
+msgstr "Набор фильтров создан"
+
+#: views.py:246
+msgid "Create a new filters set"
+msgstr "Создание нового набора фильтров"
+
+#: views.py:265
+msgid "Filters set deleted"
+msgstr "Набор фильтров удален"
+
+#: views.py:278
+msgid "Filters set activated"
+msgstr "Набор фильтров активирован"
+
+#: views.py:307
+msgid "yes"
+msgstr "Да"
+
+#: views.py:311
+msgid "no"
+msgstr "Нет"
diff --git a/modoboa/sievefilters/locale/ru/LC_MESSAGES/djangojs.po b/modoboa/sievefilters/locale/ru/LC_MESSAGES/djangojs.po
new file mode 100644
index 000000000..2764f4fba
--- /dev/null
+++ b/modoboa/sievefilters/locale/ru/LC_MESSAGES/djangojs.po
@@ -0,0 +1,39 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+msgid ""
+msgstr ""
+"Project-Id-Version: Modoboa\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2015-02-11 13:54+0100\n"
+"PO-Revision-Date: 2017-09-22 09:57+0000\n"
+"Last-Translator: Antoine Nguyen \n"
+"Language-Team: Russian (http://www.transifex.com/tonio/modoboa/language/ru/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: ru\n"
+"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);\n"
+
+#: static/modoboa_sievefilters/js/lib.js:14
+msgid "Remove this filter?"
+msgstr "Удалить фильтр?"
+
+#: static/modoboa_sievefilters/js/lib.js:107
+msgid "Save changes?"
+msgstr "Сохранить изменения?"
+
+#: static/modoboa_sievefilters/js/lib.js:129
+msgid "Remove filters set?"
+msgstr "Удалить набор фильтров?"
+
+#: static/modoboa_sievefilters/js/lib.js:146
+msgid "Activate this filters set?"
+msgstr "Активировать набор фильтров?"
+
+#: static/modoboa_sievefilters/js/lib.js:154
+#: static/modoboa_sievefilters/js/lib.js:203
+msgid "active"
+msgstr "активно"
diff --git a/modoboa/sievefilters/locale/sv/LC_MESSAGES/django.po b/modoboa/sievefilters/locale/sv/LC_MESSAGES/django.po
new file mode 100644
index 000000000..662d03955
--- /dev/null
+++ b/modoboa/sievefilters/locale/sv/LC_MESSAGES/django.po
@@ -0,0 +1,364 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# Martin Persson , 2014
+# Olle Gustafsson , 2013,2015,2017-2018
+msgid ""
+msgstr ""
+"Project-Id-Version: Modoboa\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2017-12-01 18:04+0100\n"
+"PO-Revision-Date: 2018-08-14 08:14+0000\n"
+"Last-Translator: Olle Gustafsson \n"
+"Language-Team: Swedish (http://www.transifex.com/tonio/modoboa/language/sv/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: sv\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: constants.py:6
+msgid "contains"
+msgstr "innehåller"
+
+#: constants.py:7
+msgid "does not contain"
+msgstr "innehåller inte"
+
+#: constants.py:8
+msgid "is"
+msgstr "är"
+
+#: constants.py:9
+msgid "is not"
+msgstr "är inte"
+
+#: constants.py:14
+msgid "Subject"
+msgstr "Ämne"
+
+#: constants.py:17
+msgid "Sender"
+msgstr "Avsändare"
+
+#: constants.py:20
+msgid "Recipient"
+msgstr "Mottagare"
+
+#: constants.py:23
+msgid "Cc"
+msgstr "Cc"
+
+#: constants.py:25
+msgid "Size"
+msgstr "Storlek"
+
+#: constants.py:26
+msgid "is greater than"
+msgstr "är större än"
+
+#: constants.py:27
+msgid "is less than"
+msgstr "är mindre än"
+
+#: constants.py:31
+msgid "Move message to"
+msgstr "Flytta meddelande till"
+
+#: constants.py:36 constants.py:44
+msgid "Keep local copy"
+msgstr "Behåll lokal kopia"
+
+#: constants.py:40
+msgid "Redirect message to"
+msgstr "Omdirigera meddelande till"
+
+#: constants.py:48
+msgid "Reject message"
+msgstr "Avvisa meddelande"
+
+#: constants.py:50
+msgid "Stop processing"
+msgstr "Sluta bearbeta"
+
+#: forms.py:33
+msgid "Check to activate this filters set"
+msgstr "Markera för att aktivera denna filter regel"
+
+#: forms.py:87 templates/modoboa_sievefilters/guieditor.html:6
+msgid "Name"
+msgstr "Namn"
+
+#: forms.py:89
+msgid "Match type"
+msgstr "Matcha typ"
+
+#: forms.py:90
+msgid "All of the following"
+msgstr "Alla av följande"
+
+#: forms.py:91
+msgid "Any of the following"
+msgstr "Någon av följande"
+
+#: forms.py:92
+msgid "All messages"
+msgstr "Alla meddelanden"
+
+#: forms.py:107
+msgid "Wrong filter name"
+msgstr "Fel filter namn"
+
+#: forms.py:351
+msgid "ManageSieve settings"
+msgstr "ManageSieve inställningar"
+
+#: forms.py:354 forms.py:384
+msgid "Server address"
+msgstr "Server adress"
+
+#: forms.py:356
+msgid "Address of your MANAGESIEVE server"
+msgstr "Adressen till din MANAGESIEVE server"
+
+#: forms.py:361 forms.py:396
+msgid "Server port"
+msgstr "Server port"
+
+#: forms.py:363
+msgid "Listening port of your MANAGESIEVE server"
+msgstr "MANAGESIEVE server lyssnar på port"
+
+#: forms.py:368
+msgid "Connect using STARTTLS"
+msgstr "Anslut med STARTTLS"
+
+#: forms.py:370
+msgid "Use the STARTTLS extension"
+msgstr "Använd STARTTLS"
+
+#: forms.py:374
+msgid "Authentication mechanism"
+msgstr "Autentiseringsmekanism"
+
+#: forms.py:377
+msgid "Prefered authentication mechanism"
+msgstr "Önskad autentiseringsmekanism"
+
+#: forms.py:381
+msgid "IMAP settings"
+msgstr "IMAP inställningar"
+
+#: forms.py:386
+msgid "Address of your IMAP server"
+msgstr "Adress för din IMAP server"
+
+#: forms.py:390
+msgid "Use a secured connection"
+msgstr "Använd en säker anslutning"
+
+#: forms.py:392
+msgid "Use a secured connection to access IMAP server"
+msgstr "Använd en säker anslutning för att ansluta till IMAP server"
+
+#: forms.py:398
+msgid "Listening port of your IMAP server"
+msgstr "Lyssningsport för din IMAP server"
+
+#: forms.py:405
+msgid "General"
+msgstr "Generellt"
+
+#: forms.py:409
+msgid "Editor mode"
+msgstr "Redigeringsläge"
+
+#: forms.py:411
+msgid "Select the mode you want the editor to work in"
+msgstr "Välj det läge du vill redigeraren att arbeta i"
+
+#: forms.py:415
+msgid "Mailboxes"
+msgstr "Brevlådor"
+
+#: forms.py:419
+msgid "Trash folder"
+msgstr "Skräpkatalog"
+
+#: forms.py:420
+msgid "Folder where deleted messages go"
+msgstr "Katalog där raderade meddelanden hamnar"
+
+#: forms.py:425
+msgid "Sent folder"
+msgstr "Skickat katalog"
+
+#: forms.py:426
+msgid "Folder where copies of sent messages go"
+msgstr "Katalog där en kopia av skickade meddelanden hamnar"
+
+#: forms.py:431
+msgid "Drafts folder"
+msgstr "Utkast katalog"
+
+#: forms.py:432
+msgid "Folder where drafts go"
+msgstr "Katalog där utkast sparas"
+
+#: handlers.py:19 modo_extension.py:26
+#: templates/modoboa_sievefilters/index.html:4
+msgid "Message filters"
+msgstr "Meddelandefilter"
+
+#: imaputils.py:99
+msgid "Failed to retrieve hierarchy delimiter"
+msgstr "Misslyckades med att hämta hierarkinavgränsaren"
+
+#: imaputils.py:135
+#, python-format
+msgid "Connection to IMAP server failed: %s"
+msgstr "Anslutningen till IMAP servern misslyckades: %s"
+
+#: lib.py:54
+msgid "Connection to MANAGESIEVE server failed, check your configuration"
+msgstr "Anslutning till MANAGESIEVE servern misslyckades, kontrollera din konfiguration"
+
+#: lib.py:98
+msgid "Not enough space on server"
+msgstr "Inte tillräckligt med utrymme på servern"
+
+#: modo_extension.py:18
+msgid "Plugin to easily create server-side filters"
+msgstr "Plugin för att enkelt skapa filter på serversidan"
+
+#: modo_extension.py:24
+msgid "Sieve filters"
+msgstr "Sieve filter"
+
+#: templates/modoboa_sievefilters/filter.html:9
+msgid "Conditions"
+msgstr "Villkor"
+
+#: templates/modoboa_sievefilters/filter.html:20
+#: templates/modoboa_sievefilters/guieditor.html:5 views.py:104
+msgid "Actions"
+msgstr "Åtgärder"
+
+#: templates/modoboa_sievefilters/guieditor.html:7
+msgid "Active"
+msgstr "Aktivera"
+
+#: templates/modoboa_sievefilters/guieditor.html:24
+msgid "No filter defined yet"
+msgstr "Inga filter definierade än"
+
+#: templates/modoboa_sievefilters/index.html:82
+msgid "Filter sets"
+msgstr "Filter uppsättning"
+
+#: templates/modoboa_sievefilters/index.html:86
+msgid "active"
+msgstr "aktivera"
+
+#: templates/modoboa_sievefilters/index.html:101
+msgid ""
+"No filters set defined yet. You must create one in order to define filters."
+msgstr "Inga filter uppsättningar definierade. Du måste skapa en uppsättning för att kunna definiera filter."
+
+#: templatetags/sfilters_tags.py:21
+msgid "New filters set"
+msgstr "Ny filter uppsättning"
+
+#: templatetags/sfilters_tags.py:39 views.py:153
+msgid "New filter"
+msgstr "Nytt filter"
+
+#: templatetags/sfilters_tags.py:50
+msgid "Save filters set"
+msgstr "Spara filter uppsättning"
+
+#: templatetags/sfilters_tags.py:58
+msgid "Activate filters set"
+msgstr "Aktivera filter uppsättning"
+
+#: templatetags/sfilters_tags.py:63
+msgid "Remove filters set"
+msgstr "Radera filter uppsättning"
+
+#: templatetags/sfilters_tags.py:67
+msgid "Download"
+msgstr "Ladda ner"
+
+#: templatetags/sfilters_tags.py:82 views.py:175
+msgid "Edit filter"
+msgstr "Redigera filter"
+
+#: templatetags/sfilters_tags.py:90
+msgid "Remove this filter"
+msgstr "Radera detta filter"
+
+#: templatetags/sfilters_tags.py:99
+msgid "Move this filter up"
+msgstr "Flytta upp detta filter"
+
+#: templatetags/sfilters_tags.py:108
+msgid "Move this filter down"
+msgstr "Flytta ner detta filter"
+
+#: views.py:87
+msgid "Failed to retrieve filters set"
+msgstr "Det gick inte att hämta filteruppsättning"
+
+#: views.py:156 views.py:248
+msgid "Create"
+msgstr "Skapa"
+
+#: views.py:161
+msgid "Filter created"
+msgstr "Filter krashade"
+
+#: views.py:179
+msgid "Update"
+msgstr "Uppdatera"
+
+#: views.py:186
+msgid "Filter modified"
+msgstr "Filter modifierat"
+
+#: views.py:209
+msgid "Filter removed"
+msgstr "Filter raderat"
+
+#: views.py:210
+msgid "Failed to remove filter"
+msgstr "Det gick inte att radera filtret"
+
+#: views.py:225
+msgid "Filters set saved"
+msgstr "Filter uppsättning sparat"
+
+#: views.py:241
+msgid "Filters set created"
+msgstr "Filter uppsättning skapat"
+
+#: views.py:246
+msgid "Create a new filters set"
+msgstr "Skapa ny filteruppsättning"
+
+#: views.py:265
+msgid "Filters set deleted"
+msgstr "Filter uppsättning raderad"
+
+#: views.py:278
+msgid "Filters set activated"
+msgstr "Filter uppsättning aktiverad"
+
+#: views.py:307
+msgid "yes"
+msgstr "ja"
+
+#: views.py:311
+msgid "no"
+msgstr "nej"
diff --git a/modoboa/sievefilters/locale/sv/LC_MESSAGES/djangojs.po b/modoboa/sievefilters/locale/sv/LC_MESSAGES/djangojs.po
new file mode 100644
index 000000000..844f08999
--- /dev/null
+++ b/modoboa/sievefilters/locale/sv/LC_MESSAGES/djangojs.po
@@ -0,0 +1,40 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# Olle Gustafsson , 2013,2015
+msgid ""
+msgstr ""
+"Project-Id-Version: Modoboa\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2015-02-11 13:54+0100\n"
+"PO-Revision-Date: 2017-09-22 09:57+0000\n"
+"Last-Translator: Antoine Nguyen \n"
+"Language-Team: Swedish (http://www.transifex.com/tonio/modoboa/language/sv/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: sv\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: static/modoboa_sievefilters/js/lib.js:14
+msgid "Remove this filter?"
+msgstr "Radera detta filter?"
+
+#: static/modoboa_sievefilters/js/lib.js:107
+msgid "Save changes?"
+msgstr "Spara ändringar?"
+
+#: static/modoboa_sievefilters/js/lib.js:129
+msgid "Remove filters set?"
+msgstr "Radera filteruppsättning?"
+
+#: static/modoboa_sievefilters/js/lib.js:146
+msgid "Activate this filters set?"
+msgstr "Aktivera filteruppsättning?"
+
+#: static/modoboa_sievefilters/js/lib.js:154
+#: static/modoboa_sievefilters/js/lib.js:203
+msgid "active"
+msgstr "aktivera"
diff --git a/modoboa/sievefilters/mocks.py b/modoboa/sievefilters/mocks.py
new file mode 100644
index 000000000..b2370a355
--- /dev/null
+++ b/modoboa/sievefilters/mocks.py
@@ -0,0 +1,91 @@
+# coding: utf-8
+
+"""Mock objects."""
+
+
+SAMPLE_SIEVE_SCRIPT = """require ["fileinto", "copy"];
+
+# Filter: test1
+if anyof (header :contains "To" "test1") {
+ fileinto :copy "Test1";
+}
+
+# Filter: test2
+if anyof (header :contains "To" "test2") {
+ fileinto "Test2";
+}
+"""
+
+SAMPLE_SIEVE_SCRIPT2 = """require ["fileinto"];
+
+# Filter: Tést
+if anyof (header :contains "Subject" "toto", not header :contains "To" "peé") {
+ fileinto "Administratif.Contrats.CIC";
+ stop;
+}
+"""
+
+
+class ManagesieveClientMock(object):
+ """Fake managesieve client."""
+
+ def __init__(self, *args, **kwargs):
+ self.scripts = {
+ "main_script": SAMPLE_SIEVE_SCRIPT,
+ "second_script": SAMPLE_SIEVE_SCRIPT,
+ "third_script": SAMPLE_SIEVE_SCRIPT2,
+ }
+
+ def connect(self, username, password, **kwargs):
+ return username == "user@test.com" and password == "toto"
+
+ def logout(self):
+ return True
+
+ def capability(self):
+ return """
+"IMPLEMENTATION" "Example1 ManageSieved v001"
+"VERSION" "1.0"
+"SASL" "PLAIN SCRAM-SHA-1 GSSAPI"
+"SIEVE" "fileinto vacation"
+"STARTTLS"
+"""
+
+ def havespace(self, name, size):
+ return True
+
+ def listscripts(self):
+ return ("main_script", ["second_script"])
+
+ def getscript(self, name):
+ return self.scripts.get(name)
+
+ def putscript(self, name, content):
+ self.scripts[name] = content
+ return True
+
+ def setactive(self, name):
+ return True
+
+ def deletescript(self, name):
+ return True
+
+
+class IMAP4Mock(object):
+ """Fake IMAP4 client."""
+
+ def __init__(self, *args, **kwargs):
+ self.untagged_responses = {}
+
+ def _quote(self, data):
+ return data
+
+ def _simple_command(self, name, *args, **kwargs):
+ if name == "CAPABILITY":
+ self.untagged_responses["CAPABILITY"] = [b""]
+ elif name == "LIST":
+ self.untagged_responses["LIST"] = [b'() "." "INBOX"']
+ return "OK", None
+
+ def list(self):
+ return "OK", [b'() "." "INBOX"']
diff --git a/modoboa/sievefilters/rfc6266.py b/modoboa/sievefilters/rfc6266.py
new file mode 100644
index 000000000..bbb973fd0
--- /dev/null
+++ b/modoboa/sievefilters/rfc6266.py
@@ -0,0 +1,108 @@
+"""
+Copy of the original rfc6266 package, just the generation part.
+
+Orginal code is available at https://github.com/g2p/rfc6266.
+"""
+
+from urllib.parse import quote
+
+
+# RFC 2616
+separator_chars = '()<>@,;:\\"/[]?={} \t'
+# RFC 5987
+attr_chars_nonalnum = "!#$&+-.^_`|~"
+
+
+def percent_encode(string, safe, encoding):
+ return quote(string, safe, encoding, errors="strict")
+
+
+def is_token_char(ch):
+ # Must be ascii, and neither a control char nor a separator char
+ asciicode = ord(ch)
+ # < 128 means ascii, exclude control chars at 0-31 and 127,
+ # exclude separator characters.
+ return 31 < asciicode < 127 and ch not in separator_chars
+
+
+def is_token(candidate):
+ return all(is_token_char(ch) for ch in candidate)
+
+
+def is_ascii(text):
+ return all(ord(ch) < 128 for ch in text)
+
+
+def fits_inside_codec(text, codec):
+ try:
+ text.encode(codec)
+ except UnicodeEncodeError:
+ return False
+ else:
+ return True
+
+
+def is_lws_safe(text):
+ return normalize_ws(text) == text
+
+
+def normalize_ws(text):
+ return " ".join(text.split())
+
+
+def qd_quote(text):
+ return text.replace("\\", "\\\\").replace('"', '\\"')
+
+
+def build_header(filename, disposition="attachment", filename_compat=None):
+ """Generate a Content-Disposition header for a given filename.
+ For legacy clients that don't understand the filename* parameter,
+ a filename_compat value may be given.
+ It should either be ascii-only (recommended) or iso-8859-1 only.
+ In the later case it should be a character string
+ (unicode in Python 2).
+ Options for generating filename_compat (only useful for legacy clients):
+ - ignore (will only send filename*);
+ - strip accents using unicode's decomposing normalisations,
+ which can be done from unicode data (stdlib), and keep only ascii;
+ - use the ascii transliteration tables from Unidecode (PyPI);
+ - use iso-8859-1
+ Ignore is the safest, and can be used to trigger a fallback
+ to the document location (which can be percent-encoded utf-8
+ if you control the URLs).
+ See https://tools.ietf.org/html/rfc6266#appendix-D
+ """
+
+ # While this method exists, it could also sanitize the filename
+ # by rejecting slashes or other weirdness that might upset a receiver.
+
+ if disposition != "attachment":
+ assert is_token(disposition)
+
+ rv = disposition
+
+ if is_token(filename):
+ rv += "; filename=%s" % (filename,)
+ return rv
+ elif is_ascii(filename) and is_lws_safe(filename):
+ qd_filename = qd_quote(filename)
+ rv += '; filename="%s"' % (qd_filename,)
+ if qd_filename == filename:
+ # RFC 6266 claims some implementations are iffy on qdtext's
+ # backslash-escaping, we'll include filename* in that case.
+ return rv
+ elif filename_compat:
+ if is_token(filename_compat):
+ rv += "; filename=%s" % (filename_compat,)
+ else:
+ assert is_lws_safe(filename_compat)
+ rv += '; filename="%s"' % (qd_quote(filename_compat),)
+
+ # alnum are already considered always-safe, but the rest isn't.
+ # Python encodes ~ when it shouldn't, for example.
+ rv += "; filename*=utf-8''%s" % (
+ percent_encode(filename, safe=attr_chars_nonalnum, encoding="utf-8"),
+ )
+
+ # This will only encode filename_compat, if it used non-ascii iso-8859-1.
+ return rv.encode("iso-8859-1")
diff --git a/modoboa/sievefilters/static/sievefilters/css/style.css b/modoboa/sievefilters/static/sievefilters/css/style.css
new file mode 100644
index 000000000..6ff656c85
--- /dev/null
+++ b/modoboa/sievefilters/static/sievefilters/css/style.css
@@ -0,0 +1,134 @@
+.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/sievefilters/static/sievefilters/js/jquery.dynfields.js b/modoboa/sievefilters/static/sievefilters/js/jquery.dynfields.js
new file mode 100644
index 000000000..35065de3a
--- /dev/null
+++ b/modoboa/sievefilters/static/sievefilters/js/jquery.dynfields.js
@@ -0,0 +1,362 @@
+;(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 = $('', {
+ value: tpl['operators'][ocpt][0],
+ html: tpl['operators'][ocpt][1],
+ })
+
+ $container.append($opt)
+ }
+ },
+
+ removefields: function (e) {
+ var $link = $(e.target).parent()
+ var id = $link.attr('id')
+
+ e.preventDefault()
+ $('#' + id.replace('_rmbtn', '')).remove()
+ this.fields_cnt--
+ },
+
+ newrmlink: function () {
+ return $('', {
+ 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_target_' + this.nextid,
+ name: 'cond_target_' + this.nextid,
+ class: 'form-control element-inline-block',
+ }).change($.proxy(this.target_change, this))
+ var $condoperator = $('', {
+ 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 = $('', {
+ value: tpl.name,
+ html: tpl.label,
+ })
+
+ $condtarget.append($opt)
+ if (tpl.name != this.options.defaultcond) {
+ continue
+ }
+ this.loadoperators($condoperator, tpl)
+ }
+
+ $div.append($condtarget, $condoperator, $condvalue, $rmlink)
+ $condtarget.wrap('')
+ $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 = $('', {
+ id: 'id_' + argname,
+ name: argname,
+ class: 'form-control',
+ })
+ if (tpl.args[acpt].vloader != undefined) {
+ this[tpl.args[acpt].vloader]($child)
+ }
+ } else if (tpl.args[acpt].type === 'boolean') {
+ $child = $('', { class: 'checkbox' })
+ var $label = $('', { html: tpl.args[acpt].label })
+ $label.appendTo($child)
+ $('', {
+ type: 'checkbox',
+ id: 'id_' + argname,
+ name: argname,
+ }).prependTo($label)
+ } else if (tpl.args[acpt].type == 'string') {
+ $child = $('', {
+ type: 'text',
+ id: 'id_' + argname,
+ name: argname,
+ class: 'form-control',
+ })
+ }
+ res.push($child)
+ }
+ return res
+ },
+
+ /**
+ * Remove current action argument(s) before a change.
+ */
+ deletePrevArgs: function (id) {
+ for (var cpt = 0; true; cpt++) {
+ var $arg = $('#id_action_arg_' + id + '_' + cpt)
+ if (!$arg.length) {
+ break
+ }
+ $arg.parent().remove()
+ }
+ },
+
+ /**
+ * Method called when the action is changed.
+ */
+ 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]
+ var $div = $('')
+ if (tpl.name != $target.val()) {
+ continue
+ }
+ $.each(this.loadargs(parts[2], tpl), function (idx, arg) {
+ arg.appendTo($div)
+ })
+ $pos.before($div)
+ }
+ },
+
+ 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 = $('', {
+ id: 'id_action_name_' + this.nextid,
+ name: 'action_name_' + this.nextid,
+ class: 'form-control element-inline-block',
+ })
+ var $rmlink = this.newrmlink()
+ var args = null
+
+ for (var cpt = 0; cpt < this.options.templates.length; cpt++) {
+ var tpl = this.options.templates[cpt]
+ var $opt = $('', {
+ value: tpl.name,
+ html: tpl.label,
+ })
+
+ $actioname.append($opt)
+ if (tpl.name != this.options.defaultaction) {
+ continue
+ }
+ args = this.loadargs(this.nextid, tpl)
+ }
+ $div.append($actioname)
+ $actioname.change($.proxy(this.name_change, this))
+ var $argsDiv = $('')
+ $.each(args, function (idx, element) {
+ $argsDiv.append(element)
+ })
+
+ $actioname.wrap('')
+ $div.append($argsDiv)
+ $div.append($rmlink)
+ this.$element.after($div)
+ this.nextid++
+ this.fields_cnt++
+ },
+
+ removefields: function (e) {
+ var $link = $(e.target).parent()
+ var id = $link.attr('id')
+
+ e.preventDefault()
+ $('#' + id.replace('_rmbtn', '')).remove()
+ this.fields_cnt--
+ },
+
+ userfolders: function ($container) {
+ this.$fdoptions.each(function () {
+ $container.append($(this).clone())
+ })
+ },
+ }
+
+ $.fn.dynaction = function (method) {
+ return this.each(function () {
+ var $this = $(this),
+ data = $this.data('dynaction'),
+ options = typeof method === 'object' && method
+
+ if (!data) {
+ $this.data('dynaction', new DynamicAction(this, options))
+ }
+ if (typeof method === 'string') {
+ data[method]()
+ }
+ })
+ }
+
+ $.fn.dynaction.defaults = {
+ defaultaction: 'fileinto',
+ hdelimiter: '.',
+ templates: [],
+ }
+})(jQuery)
diff --git a/modoboa/sievefilters/static/sievefilters/js/lib.js b/modoboa/sievefilters/static/sievefilters/js/lib.js
new file mode 100644
index 000000000..a402cd2b5
--- /dev/null
+++ b/modoboa/sievefilters/static/sievefilters/js/lib.js
@@ -0,0 +1,247 @@
+/*
+ * Plugin : "Sieve filters"
+ *
+ * Javascript utilities
+ */
+var curscript = null
+
+/*
+ * Remove a filter from a filters set.
+ *
+ */
+function removefilter(evt) {
+ evt.preventDefault()
+ if (!confirm(gettext('Remove this filter?'))) {
+ return
+ }
+ var $this = $(this)
+
+ $.ajax({
+ url: $this.attr('href'),
+ dataType: 'json',
+ }).done(function (response) {
+ histomanager.update(true)
+ $('body').notify('success', response, 2000)
+ })
+}
+
+/*
+ * Handler listening for the "change" event on the filters sets list.
+ */
+function changefs(evt) {
+ evt.preventDefault()
+ histomanager.baseurl($(this).val()).update()
+}
+
+/*
+ * Initializes buttons located inside the filters list
+ */
+function init_filters_list() {
+ $('a[name=togglestate]').click(toggle_filter_state)
+ $('a[name*=movefilter_]').click(move_filter)
+ $('a[name=removefilter]').click(removefilter)
+}
+
+/*
+ * Function called just after a new filters set has been loaded.
+ *
+ * It updates the middle DIV and initializes the user interface.
+ */
+function loadfs(response) {
+ curscript = histomanager.getbaseurl()
+ $('#curfset').val(curscript)
+ $('#set_content').html(response.content)
+
+ if ($('#filters_list') != undefined) {
+ init_filters_list()
+ }
+ if ($('#fsetmenu').length) {
+ $('#fsetmenu').remove()
+ }
+ $('#menu').after($(response.menu))
+ $('a[name=activatefs]').click(activatefs)
+ $('a[name=savefs]').click(savefs)
+ $('a[name=removefs]').click(removefs)
+}
+
+/*
+ * Common function to send a command that manipulates a filters set.
+ *
+ * (remove, activate)
+ */
+function send_command(cmd, extracb) {
+ $.ajax({
+ url: cmd,
+ dataType: 'json',
+ }).done(function (response) {
+ if (extracb != undefined) {
+ extracb(response)
+ }
+ if (!response.norefresh) {
+ histomanager.update(true)
+ }
+ $('body').notify('success', response.respmsg, 2000)
+ })
+}
+
+/*
+ * Common utility used by filters set manipulation functions to
+ * validate any new asked action. (activate, save, remove)
+ */
+function check_prereqs(evt, msg) {
+ evt.preventDefault()
+ if (!curscript) {
+ return false
+ }
+ if (msg != undefined && !confirm(msg)) {
+ return false
+ }
+ return true
+}
+
+/*
+ * Save the current filters set by applying the modifications to the
+ * server.
+ */
+function savefs(evt) {
+ if (!check_prereqs(evt, gettext('Save changes?'))) {
+ return
+ }
+ var $editor = $('#feditor')
+
+ $.ajax({
+ url: $editor.attr('action'),
+ type: $editor.attr('method'),
+ dataType: 'json',
+ data: $editor.serialize(),
+ }).done(function (response) {
+ $('body').notify('success', response.respmsg, 2000)
+ })
+}
+
+/*
+ * Remove the current filters set.
+ *
+ * On success, the user will be automatically redirected to the active
+ * filters set.
+ */
+function removefs(evt) {
+ if (!check_prereqs(evt, gettext('Remove filters set?'))) {
+ return
+ }
+ send_command($(this).attr('href'), function (response) {
+ var $curfset = $('#curfset')
+
+ $curfset.find("option[value='" + curscript + "']").remove()
+ histomanager.baseurl(response.newfs, 1)
+ })
+}
+
+/*
+ * Activate the current filters set.
+ */
+function activatefs(evt) {
+ var $this = $(this)
+
+ if (!check_prereqs(evt, gettext('Activate this filters set?'))) {
+ return
+ }
+ send_command($this.attr('href'), function (response) {
+ $('#curfset')
+ .find('option')
+ .each(function (index, element) {
+ var $element = $(element)
+
+ $element.val() == curscript
+ ? $element.html(curscript + ' (' + gettext('active') + ')')
+ : $element.html($element.val())
+ })
+ })
+}
+
+/*
+ * Enable/Disable a specific filter
+ */
+function toggle_filter_state(event) {
+ var $this = $(this)
+
+ event.preventDefault()
+ $.ajax({
+ url: $this.attr('href'),
+ dataType: 'json',
+ }).done(function (response) {
+ $this.html(response.label)
+ $this.attr('class', '')
+ $this.addClass(response.color)
+ })
+}
+
+function move_filter(event) {
+ var $this = $(this)
+
+ event.preventDefault()
+ $.ajax({
+ url: $this.attr('href'),
+ dataType: 'json',
+ }).done(function (response) {
+ $('#set_content').html(response.content)
+ init_filters_list()
+ })
+}
+
+function filterset_created(data) {
+ var name = data.url
+ var option = $('')
+ var curfset = $(parent.document).find('#curfset')
+
+ curfset.append(option)
+ curfset.val(name)
+
+ if (data.active) {
+ curfset.find('option').each(function (index, element) {
+ var $element = $(element)
+
+ if ($element.val() == name) {
+ $element.html(name + ' (' + gettext('active') + ')')
+ } else {
+ $element.html($element.val())
+ }
+ })
+ }
+ histomanager.baseurl(data.url, 1).update(1)
+}
+
+function filtersetform_cb() {
+ $('#newfiltersset')
+ .find('input')
+ .keypress(function (e) {
+ if (e.which == 13) e.preventDefault()
+ })
+ $('.submit').on('click', function (e) {
+ simple_ajax_form_post(e, {
+ formid: 'newfiltersset',
+ reload_on_success: false,
+ success_cb: filterset_created,
+ })
+ })
+}
+
+/*
+ * From here: specific functions used by the user-friendly form to
+ * create/edit filters.
+ */
+function fetch_templates(url, container) {
+ if (container) {
+ return container
+ }
+ var result
+
+ $.ajax({
+ url: url,
+ async: false,
+ dataType: 'json',
+ }).done(function (data) {
+ result = data
+ })
+ return result
+}
diff --git a/modoboa/sievefilters/templates/sievefilters/filter.html b/modoboa/sievefilters/templates/sievefilters/filter.html
new file mode 100644
index 000000000..e0476c0b4
--- /dev/null
+++ b/modoboa/sievefilters/templates/sievefilters/filter.html
@@ -0,0 +1,26 @@
+{% extends "common/generic_modal_form.html" %}
+{% load i18n form_tags sfilters_tags %}
+
+{% block modal_css_classes %}modal-lg{% endblock %}
+
+{% block formbody %}
+ {% if oldname %}{% 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/sievefilters/templates/sievefilters/guieditor.html b/modoboa/sievefilters/templates/sievefilters/guieditor.html
new file mode 100644
index 000000000..30bf5f117
--- /dev/null
+++ b/modoboa/sievefilters/templates/sievefilters/guieditor.html
@@ -0,0 +1,25 @@
+{% load i18n sfilters_tags %}
+{% if fs.filters %}
+
+
+ | {% trans "Actions" %} |
+ {% trans "Name" %} |
+ {% trans "Active" %} |
+
+ {% for filter in fs.filters %}
+
+ | {% filter_actions fs.name filter forloop.counter forloop.last %} |
+ {{ filter.name }} |
+
+
+ {{ filter.enabled|yesno }}
+
+ |
+
+ {% endfor %}
+
+{% else %}
+{% trans "No filter defined yet" %}
+{% endif %}
diff --git a/modoboa/sievefilters/templates/sievefilters/index.html b/modoboa/sievefilters/templates/sievefilters/index.html
new file mode 100644
index 000000000..9d7bebc73
--- /dev/null
+++ b/modoboa/sievefilters/templates/sievefilters/index.html
@@ -0,0 +1,104 @@
+{% extends "twocols.html" %}
+{% load i18n static sfilters_tags %}
+
+{% 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/sievefilters/templates/sievefilters/rawfilter.html b/modoboa/sievefilters/templates/sievefilters/rawfilter.html
new file mode 100644
index 000000000..0194f98f5
--- /dev/null
+++ b/modoboa/sievefilters/templates/sievefilters/rawfilter.html
@@ -0,0 +1,4 @@
+
diff --git a/modoboa/sievefilters/templatetags/__init__.py b/modoboa/sievefilters/templatetags/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/modoboa/sievefilters/templatetags/sfilters_tags.py b/modoboa/sievefilters/templatetags/sfilters_tags.py
new file mode 100644
index 000000000..c8892cdc3
--- /dev/null
+++ b/modoboa/sievefilters/templatetags/sfilters_tags.py
@@ -0,0 +1,213 @@
+"""Custom template tags."""
+
+from django import template
+from django.urls import reverse
+from django.template.loader import render_to_string
+from django.utils.translation import gettext as _
+
+from modoboa.lib.web_utils import render_actions
+from modoboa.lib.templatetags.form_tags import configure_field_classes
+
+from .. import lib
+
+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]
+ tpl = lib.find_action_template(action.initial)
+ configure_field_classes(action)
+ values = []
+ verrors = []
+ for pos, argtpl in enumerate(tpl.get("args", [])):
+ fieldname = "action_arg_{}_{}".format(cnt, pos)
+ if fieldname not in form.fields:
+ continue
+ field = form[fieldname]
+ configure_field_classes(field)
+ arg = {"field": field}
+ if field.errors:
+ verrors += field.errors
+ if argtpl["type"] == "boolean":
+ arg["checkbox"] = True
+ values += [arg]
+ t = template.Template(
+ """
+
+
+ {{ afield }}
+
+
+ {% for v in values %}{% if v.checkbox %}
{% else %}{{ v.field }}{% endif %}{% endfor %}
+ {{ verrors }}
+
+
+"""
+ )
+ return t.render(
+ template.Context(
+ {
+ "idx": cnt,
+ "afield": action,
+ "values": values,
+ "verrors": display_errors(verrors),
+ }
+ )
+ )
diff --git a/modoboa/sievefilters/tests.py b/modoboa/sievefilters/tests.py
new file mode 100644
index 000000000..998142514
--- /dev/null
+++ b/modoboa/sievefilters/tests.py
@@ -0,0 +1,165 @@
+# coding: utf-8
+
+"""Sievefilters tests."""
+
+from unittest import mock
+
+from django.urls import reverse
+
+from modoboa.admin import factories as admin_factories
+from modoboa.core import models as core_models
+from modoboa.lib.tests import ModoTestCase
+
+from . import mocks
+
+
+class SieveFiltersTestCase(ModoTestCase):
+ """Check sieve filters."""
+
+ @classmethod
+ def setUpTestData(cls):
+ """Create some users."""
+ super().setUpTestData()
+ admin_factories.populate_database()
+ cls.user = core_models.User.objects.get(username="user@test.com")
+
+ def setUp(self):
+ """Connect with a simpler user."""
+ patcher = mock.patch("sievelib.managesieve.Client")
+ self.mock_client = patcher.start()
+ self.mock_client.return_value = mocks.ManagesieveClientMock()
+ self.addCleanup(patcher.stop)
+
+ patcher = mock.patch("imaplib.IMAP4")
+ self.mock_imap4 = patcher.start()
+ self.mock_imap4.return_value = mocks.IMAP4Mock()
+ self.addCleanup(patcher.stop)
+
+ url = reverse("core:login")
+ data = {"username": self.user.username, "password": "toto"}
+ self.client.post(url, data)
+
+ def test_index(self):
+ """Test index view."""
+ response = self.client.get(reverse("sievefilters:index"))
+ self.assertContains(response, "main_script (active)")
+ response = self.client.post(reverse("core:logout"))
+ self.assertEqual(response.status_code, 302)
+
+ def test_getfs(self):
+ """Test getfs view."""
+ response = self.ajax_get(reverse("sievefilters:fs_get", args=["main_script"]))
+ self.assertIn("/sfilters/main_script/editfilter/test1/", response["content"])
+
+ def test_toggle_filter_state(self):
+ """Test toggle_filter_state view."""
+ url = reverse("sievefilters:filter_toggle_state", args=["main_script", "test1"])
+ response = self.ajax_get(url)
+ self.assertEqual(response["color"], "red")
+ response = self.ajax_get(url)
+ self.assertEqual(response["color"], "green")
+
+ def test_move_filter_up(self):
+ """Test move_filter_up view."""
+ url = reverse("sievefilters:filter_move_up", args=["main_script", "test2"])
+ response = self.ajax_get(url)
+ pos1 = response["content"].find("/sfilters/main_script/editfilter/test2/")
+ pos2 = response["content"].find("/sfilters/main_script/editfilter/test1/")
+ self.assertTrue(pos1 < pos2)
+
+ def test_move_filter_down(self):
+ """Test move_filter_down view."""
+ url = reverse("sievefilters:filter_move_down", args=["main_script", "test1"])
+ response = self.ajax_get(url)
+ pos1 = response["content"].find("/sfilters/main_script/editfilter/test2/")
+ pos2 = response["content"].find("/sfilters/main_script/editfilter/test1/")
+ self.assertTrue(pos1 < pos2)
+
+ def test_new_filter(self):
+ """Test new_filter view."""
+ url = reverse("sievefilters:filter_add", args=["main_script"])
+ response = self.client.get(url)
+ self.assertContains(response, "New filter")
+
+ data = {
+ "name": "tést filter",
+ "match_type": "anyof",
+ "conds": 1,
+ "cond_target_0": "Subject",
+ "cond_operator_0": "contains",
+ "cond_value_0": "Test",
+ "actions": 1,
+ "action_name_0": "fileinto",
+ "action_arg_0_0": "Trash",
+ }
+ response = self.ajax_post(url, data)
+ self.assertEqual(response, "Filter created")
+
+ def test_edit_filter(self):
+ """Test edit_filter view."""
+ url = reverse("sievefilters:filter_change", args=["main_script", "test1"])
+ response = self.client.get(url)
+ self.assertContains(response, "Edit filter")
+
+ data = {
+ "oldname": "test1",
+ "name": "test1",
+ "match_type": "all",
+ "conds": 1,
+ "cond_target_0": "To",
+ "cond_operator_0": "contains",
+ "cond_value_0": "test1",
+ "actions": 1,
+ "action_name_0": "fileinto",
+ "action_arg_0_0": "Trash",
+ "action_arg_0_1": True,
+ }
+ response = self.ajax_post(url, data)
+ self.assertEqual(response, "Filter modified")
+
+ def test_edit_filter_with_not(self):
+ """Try to edit a filter containing a not operator."""
+ url = reverse("sievefilters:filter_change", args=["third_script", "Tést"])
+ response = self.client.get(url)
+ self.assertContains(response, "Edit filter")
+
+ def test_remove_filter(self):
+ """Test removefilter view."""
+ url = reverse("sievefilters:filter_delete", args=["second_script", "test1"])
+ response = self.ajax_get(url)
+ self.assertEqual(response, "Filter removed")
+
+ def test_download_filters_set(self):
+ """Test download_filters_set view."""
+ url = reverse("sievefilters:fs_download", args=["main_script"])
+ response = self.client.get(url)
+ self.assertEqual(response.content.decode(), mocks.SAMPLE_SIEVE_SCRIPT)
+
+ def test_activate_filters_set(self):
+ """Test activate_filters_set view."""
+ url = reverse("sievefilters:fs_activate", args=["second_script"])
+ response = self.ajax_get(url)
+ self.assertEqual(response["respmsg"], "Filters set activated")
+
+ def test_remove_filters_set(self):
+ """Test remove_filters_set view."""
+ url = reverse("sievefilters:fs_delete", args=["second_script"])
+ response = self.ajax_get(url)
+ self.assertEqual(response["respmsg"], "Filters set deleted")
+
+ def test_new_filters_set(self):
+ """Test new_filters_set view."""
+ url = reverse("sievefilters:fs_add")
+ response = self.client.get(url)
+ self.assertContains(response, "Create a new filters set")
+
+ data = {"name": "new_script"}
+ response = self.ajax_post(url, data)
+ self.assertEqual(response["respmsg"], "Filters set created")
+
+ def test_savefs(self):
+ """Test savefs view."""
+ url = reverse("sievefilters:fs_save", args=["new_script"])
+ data = {"scriptcontent": mocks.SAMPLE_SIEVE_SCRIPT}
+ response = self.ajax_post(url, data)
+ self.assertEqual(response["respmsg"], "Filters set saved")
diff --git a/modoboa/sievefilters/urls.py b/modoboa/sievefilters/urls.py
new file mode 100644
index 000000000..d4a0ed0c6
--- /dev/null
+++ b/modoboa/sievefilters/urls.py
@@ -0,0 +1,42 @@
+"""Sieve urls."""
+
+from django.urls import path
+
+from . import views
+
+app_name = "sievefilters"
+
+urlpatterns = [
+ path("", views.index, name="index"),
+ path("savefs//", views.savefs, name="fs_save"),
+ path("newfs/", views.new_filters_set, name="fs_add"),
+ path("removefs//", views.remove_filters_set, name="fs_delete"),
+ path("activatefs//", views.activate_filters_set, name="fs_activate"),
+ path("downloadfs//", views.download_filters_set, name="fs_download"),
+ path("templates//", views.get_templates, name="templates_get"),
+ path("/newfilter/", views.newfilter, name="filter_add"),
+ path(
+ "/editfilter//", views.editfilter, name="filter_change"
+ ),
+ path(
+ "/removefilter//",
+ views.removefilter,
+ name="filter_delete",
+ ),
+ path(
+ "/togglestate//",
+ views.toggle_filter_state,
+ name="filter_toggle_state",
+ ),
+ path(
+ "/moveup//",
+ views.move_filter_up,
+ name="filter_move_up",
+ ),
+ path(
+ "/movedown//",
+ views.move_filter_down,
+ name="filter_move_down",
+ ),
+ path("/", views.getfs, name="fs_get"),
+]
diff --git a/modoboa/sievefilters/views.py b/modoboa/sievefilters/views.py
new file mode 100644
index 000000000..cc586c16d
--- /dev/null
+++ b/modoboa/sievefilters/views.py
@@ -0,0 +1,326 @@
+"""Custom views."""
+
+from sievelib.commands import BadArgument, BadValue
+from sievelib.managesieve import Error
+
+from django.contrib.auth.decorators import login_required
+from django.urls import reverse
+from django.http import HttpResponse, JsonResponse
+from django.shortcuts import render
+from django.template.loader import render_to_string
+from django.utils.encoding import smart_bytes, smart_str
+from django.utils.translation import gettext as _
+
+from modoboa.admin.lib import needs_mailbox
+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
+
+from . import constants
+from .forms import (
+ FilterForm,
+ build_filter_form_from_qdict,
+ build_filter_form_from_filter,
+ FiltersSetForm,
+)
+from .imaputils import get_imapconnector
+from .lib import SieveClient, SieveClientError
+from .rfc6266 import build_header
+from .templatetags.sfilters_tags import fset_menu
+
+
+@login_required
+@needs_mailbox()
+def index(request, tplname="sievefilters/index.html"):
+ 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":
+ data = constants.CONDITION_TEMPLATES
+ else:
+ data = constants.ACTION_TEMPLATES
+ return JsonResponse(data, safe=False)
+
+
+@login_required
+@needs_mailbox()
+def getfs(request, name):
+ sc = SieveClient(user=request.user.username, password=request.session["password"])
+ editormode = request.user.parameters.get_value("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", {"name": name, "scriptcontent": content}
+ )
+ else:
+ htmlcontent = render_to_string("sievefilters/guieditor.html", {"fs": content})
+
+ menu = (
+ "".format(
+ _("Actions"), fset_menu(editormode, name)
+ )
+ )
+ resp = {"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, "{}".format(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 = {
+ "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 = {
+ "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")
+ fname = smart_bytes(fname)
+ 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, "{}".format(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()
+ ctx = {
+ "respmsg": _("Filters set deleted"),
+ "newfs": acs,
+ }
+ return render_to_json_response(ctx)
+
+
+@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"])
+ fname = smart_str(fname)
+ 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, "{}".format(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")
diff --git a/modoboa/urls.py b/modoboa/urls.py
index 9f240ee04..bc6ad136c 100644
--- a/modoboa/urls.py
+++ b/modoboa/urls.py
@@ -29,6 +29,7 @@ urlpatterns = [
path("stats/", include("modoboa.maillog.urls")),
path("dmarc/", include("modoboa.dmarc.urls")),
path("imap_migration/", include("modoboa.imap_migration.urls")),
+ path("sfilters/", include("modoboa.sievefilters.urls")),
path("user/forward/", user_views.forward, name="user_forward"),
path(
"accounts/password_reset/",
@@ -100,6 +101,7 @@ urlpatterns += [
name="docs-index-v2",
),
path("api/schema-v2/redoc/", SpectacularRedocView.as_view(url_name="schema-v2")),
+ path("api/o/", include("oauth2_provider.urls", namespace="oauth2_provider")),
path("api/v1/", include("modoboa.urls_api_v1", namespace="v1")),
path("api/v2/", include("modoboa.urls_api_v2", namespace="v2")),
]
diff --git a/modoboa/urls_api_v2.py b/modoboa/urls_api_v2.py
index ab42765ee..5de4b5e0f 100644
--- a/modoboa/urls_api_v2.py
+++ b/modoboa/urls_api_v2.py
@@ -19,6 +19,7 @@ urlpatterns = [
path("", include("modoboa.transport.api.v2.urls")),
path("", include("modoboa.pdfcredentials.api.v2.urls")),
path("", include("modoboa.postfix_autoreply.api.v2.urls")),
+ path("", include("modoboa.sievefilters.api.v2.urls")),
]
urlpatterns += exts_pool.get_urls(category="api")
diff --git a/requirements.txt b/requirements.txt
index 13ed9a525..d02fc1a4b 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -13,6 +13,7 @@ djangorestframework>=3.14,<3.16
drf-spectacular
uritemplate
djangorestframework-simplejwt==5.3.1
+django-oauth-toolkit
passlib~=1.7.4
bcrypt # Requires libffi-dev and python-dev
@@ -48,3 +49,6 @@ python-magic>=0.4.24
# RQ
rq>=1.13.0
django-rq
+
+# Sieve
+sievelib>=1.1.1
diff --git a/test_project/test_project/settings.py b/test_project/test_project/settings.py
index 79889a953..aa9271543 100644
--- a/test_project/test_project/settings.py
+++ b/test_project/test_project/settings.py
@@ -66,6 +66,7 @@ INSTALLED_APPS = (
"reversion",
"ckeditor",
"ckeditor_uploader",
+ "oauth2_provider",
"rest_framework",
"rest_framework.authtoken",
"drf_spectacular",
@@ -95,6 +96,7 @@ MODOBOA_APPS = (
"modoboa.dmarc",
"modoboa.imap_migration",
"modoboa.postfix_autoreply",
+ "modoboa.sievefilters",
# Modoboa extensions here.
)
@@ -189,6 +191,17 @@ STATICFILES_DIRS = (os.path.join(BASE_DIR, "..", "modoboa", "bower_components"),
MEDIA_URL = "/media/"
MEDIA_ROOT = os.path.join(BASE_DIR, "media")
+# oAuth2 settings
+
+OAUTH2_PROVIDER = {
+ "SCOPES": {
+ "read": "Read scope",
+ "write": "Write scope",
+ "introspection": "Introspect token scope",
+ },
+ "DEFAULT_SCOPES": ["read", "write"],
+}
+
# Rest framework settings
REST_FRAMEWORK = {
@@ -202,7 +215,7 @@ REST_FRAMEWORK = {
"password_recovery_apply": "25/hour",
},
"DEFAULT_AUTHENTICATION_CLASSES": (
- "modoboa.core.drf_authentication.JWTAuthenticationWith2FA",
+ "oauth2_provider.contrib.rest_framework.OAuth2Authentication",
"rest_framework.authentication.TokenAuthentication",
"rest_framework.authentication.SessionAuthentication",
),