summaryrefslogtreecommitdiff
path: root/mailman/web/Gui/ContentFilter.py
diff options
context:
space:
mode:
authorBarry Warsaw2008-10-06 22:07:04 -0400
committerBarry Warsaw2008-10-06 22:07:04 -0400
commitc7340d712c640fa5992518a7cf16272f634abccc (patch)
tree99057710fbc7b92eaa1720daea4c3a6cd5929cf3 /mailman/web/Gui/ContentFilter.py
parent6f4351721559e8b7b577d3a01216fec88121ed11 (diff)
parentf0c9fad6372a645981b5c72fe02a6ad62f35790f (diff)
downloadmailman-c7340d712c640fa5992518a7cf16272f634abccc.tar.gz
mailman-c7340d712c640fa5992518a7cf16272f634abccc.tar.zst
mailman-c7340d712c640fa5992518a7cf16272f634abccc.zip
Diffstat (limited to 'mailman/web/Gui/ContentFilter.py')
-rw-r--r--mailman/web/Gui/ContentFilter.py199
1 files changed, 199 insertions, 0 deletions
diff --git a/mailman/web/Gui/ContentFilter.py b/mailman/web/Gui/ContentFilter.py
new file mode 100644
index 000000000..d7f26321b
--- /dev/null
+++ b/mailman/web/Gui/ContentFilter.py
@@ -0,0 +1,199 @@
+# Copyright (C) 2002-2008 by the Free Software Foundation, Inc.
+#
+# This file is part of GNU Mailman.
+#
+# GNU Mailman is free software: you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free
+# Software Foundation, either version 3 of the License, or (at your option)
+# any later version.
+#
+# GNU Mailman is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# GNU Mailman. If not, see <http://www.gnu.org/licenses/>.
+
+"""GUI component managing the content filtering options."""
+
+from Mailman.Gui.GUIBase import GUIBase
+from Mailman.configuration import config
+from Mailman.i18n import _
+
+NL = '\n'
+
+
+
+class ContentFilter(GUIBase):
+ def GetConfigCategory(self):
+ return 'contentfilter', _('Content&nbsp;filtering')
+
+ def GetConfigInfo(self, mlist, category, subcat=None):
+ if category <> 'contentfilter':
+ return None
+ WIDTH = config.TEXTFIELDWIDTH
+
+ actions = [_('Discard'), _('Reject'), _('Forward to List Owner')]
+ if config.OWNERS_CAN_PRESERVE_FILTERED_MESSAGES:
+ actions.append(_('Preserve'))
+
+ return [
+ _("""Policies concerning the content of list traffic.
+
+ <p>Content filtering works like this: when a message is
+ received by the list and you have enabled content filtering, the
+ individual attachments are first compared to the
+ <a href="?VARHELP=contentfilter/filter_mime_types">filter
+ types</a>. If the attachment type matches an entry in the filter
+ types, it is discarded.
+
+ <p>Then, if there are <a
+ href="?VARHELP=contentfilter/pass_mime_types">pass types</a>
+ defined, any attachment type that does <em>not</em> match a
+ pass type is also discarded. If there are no pass types defined,
+ this check is skipped.
+
+ <p>After this initial filtering, any <tt>multipart</tt>
+ attachments that are empty are removed. If the outer message is
+ left empty after this filtering, then the whole message is
+ discarded.
+
+ <p> Then, each <tt>multipart/alternative</tt> section will
+ be replaced by just the first alternative that is non-empty after
+ filtering if
+ <a href="?VARHELP=contentfilter/collapse_alternatives"
+ >collapse_alternatives</a> is enabled.
+
+ <p>Finally, any <tt>text/html</tt> parts that are left in the
+ message may be converted to <tt>text/plain</tt> if
+ <a href="?VARHELP=contentfilter/convert_html_to_plaintext"
+ >convert_html_to_plaintext</a> is enabled and the site is
+ configured to allow these conversions."""),
+
+ ('filter_content', config.Radio, (_('No'), _('Yes')), 0,
+ _("""Should Mailman filter the content of list traffic according
+ to the settings below?""")),
+
+ ('filter_mime_types', config.Text, (10, WIDTH), 0,
+ _("""Remove message attachments that have a matching content
+ type."""),
+
+ _("""Use this option to remove each message attachment that
+ matches one of these content types. Each line should contain a
+ string naming a MIME <tt>type/subtype</tt>,
+ e.g. <tt>image/gif</tt>. Leave off the subtype to remove all
+ parts with a matching major content type, e.g. <tt>image</tt>.
+
+ <p>Blank lines are ignored.
+
+ <p>See also <a href="?VARHELP=contentfilter/pass_mime_types"
+ >pass_mime_types</a> for a content type whitelist.""")),
+
+ ('pass_mime_types', config.Text, (10, WIDTH), 0,
+ _("""Remove message attachments that don't have a matching
+ content type. Leave this field blank to skip this filter
+ test."""),
+
+ _("""Use this option to remove each message attachment that does
+ not have a matching content type. Requirements and formats are
+ exactly like <a href="?VARHELP=contentfilter/filter_mime_types"
+ >filter_mime_types</a>.
+
+ <p><b>Note:</b> if you add entries to this list but don't add
+ <tt>multipart</tt> to this list, any messages with attachments
+ will be rejected by the pass filter.""")),
+
+ ('filter_filename_extensions', config.Text, (10, WIDTH), 0,
+ _("""Remove message attachments that have a matching filename
+ extension."""),),
+
+ ('pass_filename_extensions', config.Text, (10, WIDTH), 0,
+ _("""Remove message attachments that don't have a matching
+ filename extension. Leave this field blank to skip this filter
+ test."""),),
+
+ ('collapse_alternatives', config.Radio, (_('No'), _('Yes')), 0,
+ _("""Should Mailman collapse multipart/alternative to its
+ first part content?""")),
+
+ ('convert_html_to_plaintext', config.Radio, (_('No'), _('Yes')), 0,
+ _("""Should Mailman convert <tt>text/html</tt> parts to plain
+ text? This conversion happens after MIME attachments have been
+ stripped.""")),
+
+ ('filter_action', config.Radio, tuple(actions), 0,
+
+ _("""Action to take when a message matches the content filtering
+ rules."""),
+
+ _("""One of these actions is take when the message matches one of
+ the content filtering rules, meaning, the top-level
+ content type matches one of the <a
+ href="?VARHELP=contentfilter/filter_mime_types"
+ >filter_mime_types</a>, or the top-level content type does
+ <strong>not</strong> match one of the
+ <a href="?VARHELP=contentfilter/pass_mime_types"
+ >pass_mime_types</a>, or if after filtering the subparts of the
+ message, the message ends up empty.
+
+ <p>Note this action is not taken if after filtering the message
+ still contains content. In that case the message is always
+ forwarded on to the list membership.
+
+ <p>When messages are discarded, a log entry is written
+ containing the Message-ID of the discarded message. When
+ messages are rejected or forwarded to the list owner, a reason
+ for the rejection is included in the bounce message to the
+ original author. When messages are preserved, they are saved in
+ a special queue directory on disk for the site administrator to
+ view (and possibly rescue) but otherwise discarded. This last
+ option is only available if enabled by the site
+ administrator.""")),
+ ]
+
+ def _setValue(self, mlist, property, val, doc):
+ if property in ('filter_mime_types', 'pass_mime_types'):
+ types = []
+ for spectype in [s.strip() for s in val.splitlines()]:
+ ok = 1
+ slashes = spectype.count('/')
+ if slashes == 0 and not spectype:
+ ok = 0
+ elif slashes == 1:
+ maintype, subtype = [s.strip().lower()
+ for s in spectype.split('/')]
+ if not maintype or not subtype:
+ ok = 0
+ elif slashes > 1:
+ ok = 0
+ if not ok:
+ doc.addError(_('Bad MIME type ignored: %(spectype)s'))
+ else:
+ types.append(spectype.strip().lower())
+ if property == 'filter_mime_types':
+ mlist.filter_mime_types = types
+ elif property == 'pass_mime_types':
+ mlist.pass_mime_types = types
+ elif property in ('filter_filename_extensions',
+ 'pass_filename_extensions'):
+ fexts = []
+ for ext in [s.strip() for s in val.splitlines()]:
+ fexts.append(ext.lower())
+ if property == 'filter_filename_extensions':
+ mlist.filter_filename_extensions = fexts
+ elif property == 'pass_filename_extensions':
+ mlist.pass_filename_extensions = fexts
+ else:
+ GUIBase._setValue(self, mlist, property, val, doc)
+
+ def getValue(self, mlist, kind, property, params):
+ if property == 'filter_mime_types':
+ return NL.join(mlist.filter_mime_types)
+ if property == 'pass_mime_types':
+ return NL.join(mlist.pass_mime_types)
+ if property == 'filter_filename_extensions':
+ return NL.join(mlist.filter_filename_extensions)
+ if property == 'pass_filename_extensions':
+ return NL.join(mlist.pass_filename_extensions)
+ return None