aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Mailman/Gui/Privacy.py116
1 files changed, 114 insertions, 2 deletions
diff --git a/Mailman/Gui/Privacy.py b/Mailman/Gui/Privacy.py
index 8f3001de..c07315ae 100644
--- a/Mailman/Gui/Privacy.py
+++ b/Mailman/Gui/Privacy.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2001,2002 by the Free Software Foundation, Inc.
+# Copyright (C) 2001-2003 by the Free Software Foundation, Inc.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
@@ -17,10 +17,19 @@
"""MailList mixin class managing the privacy options.
"""
+import re
+
from Mailman import mm_cfg
+from Mailman import Utils
from Mailman.i18n import _
from Mailman.Gui.GUIBase import GUIBase
+try:
+ True, False
+except NameError:
+ True = 1
+ False = 0
+
class Privacy(GUIBase):
@@ -361,7 +370,23 @@ class Privacy(GUIBase):
your list members end up receiving.
"""),
- _("Anti-Spam filters"),
+ _('Header filters'),
+
+ ('header_filter_rules', mm_cfg.HeaderFilter, 0, 0,
+ _('Filter rules to match against the headers of a message.'),
+
+ _("""Each header filter rule has two parts, a list of regular
+ expressions, one per line, and an action to take. Mailman
+ matches the message's headers against every regular expression in
+ the rule and if any match, the message is rejected, held, or
+ discarded based on the action you specify. Use <em>Defer</em> to
+ temporarily disable a rule.
+
+ You can have more than one filter rule for your list. In that
+ case, each rule is matched in turn, with processing stopped after
+ the first match.""")),
+
+ _('Legacy anti-spam filters'),
('bounce_matching_headers', mm_cfg.Text, (6, WIDTH), 0,
_('Hold posts with header value matching a specified regexp.'),
@@ -390,9 +415,96 @@ class Privacy(GUIBase):
return subscribing_rtn
def _setValue(self, mlist, property, val, doc):
+ # Ignore any hdrfilter_* form variables
+ if property.startswith('hdrfilter_'):
+ return
# For subscribe_policy when ALLOW_OPEN_SUBSCRIBE is true, we need to
# add one to the value because the page didn't present an open list as
# an option.
if property == 'subscribe_policy' and not mm_cfg.ALLOW_OPEN_SUBSCRIBE:
val += 1
setattr(mlist, property, val)
+
+ # We need to handle the header_filter_rules widgets specially, but
+ # everything else can be done by the base class's handleForm() method.
+ # However, to do this we need an awful hack. _setValue() and
+ # _getValidValue() will essentially ignore any hdrfilter_* form variables.
+ def handleForm(self, mlist, category, subcat, cgidata, doc):
+ # First deal with
+ rules = []
+ # We start i at 1 and keep going until we no longer find items keyed
+ # with the marked tags.
+ i = 1
+ downi = None
+ while True:
+ deltag = 'hdrfilter_delete_%02d' % i
+ reboxtag = 'hdrfilter_rebox_%02d' % i
+ actiontag = 'hdrfilter_action_%02d' % i
+ wheretag = 'hdrfilter_where_%02d' % i
+ addtag = 'hdrfilter_add_%02d' % i
+ newtag = 'hdrfilter_new_%02d' % i
+ uptag = 'hdrfilter_up_%02d' % i
+ downtag = 'hdrfilter_down_%02d' % i
+ i += 1
+ # Was this a delete? If so, we can just ignore this entry
+ if cgidata.has_key(deltag):
+ continue
+ # Get the data for the current box
+ pattern = cgidata.getvalue(reboxtag)
+ try:
+ action = int(cgidata.getvalue(actiontag))
+ # We'll get a TypeError when the actiontag is missing and the
+ # .getvalue() call returns None.
+ except (ValueError, TypeError):
+ action = mm_cfg.DEFER
+ if pattern is None:
+ # We came to the end of the boxes
+ break
+ if cgidata.has_key(newtag) and not pattern:
+ # This new entry is incomplete.
+ doc.addError(_("""Header filter rules require a pattern.
+ Incomplete filter rules will be ignored."""))
+ continue
+ # Make sure the pattern was a legal regular expression
+ try:
+ re.compile(pattern)
+ except (re.error, TypeError):
+ safepattern = Utils.websafe(pattern)
+ doc.addError(_("""The header filter rule pattern
+ '%(safepattern)s' is not a legal regular expression. This
+ rule will be ignored."""))
+ continue
+ # Was this an add item?
+ if cgidata.has_key(addtag):
+ # Where should the new one be added?
+ where = cgidata.getvalue(wheretag)
+ if where == 'before':
+ # Add a new empty rule box before the current one
+ rules.append(('', mm_cfg.DEFER, True))
+ rules.append((pattern, action, False))
+ # Default is to add it after...
+ else:
+ rules.append((pattern, action, False))
+ rules.append(('', mm_cfg.DEFER, True))
+ # Was this an up movement?
+ elif cgidata.has_key(uptag):
+ # As long as this one isn't the first rule, move it up
+ if rules:
+ rules.insert(-1, (pattern, action, False))
+ else:
+ rules.append((pattern, action, False))
+ # Was this the down movement?
+ elif cgidata.has_key(downtag):
+ downi = i - 2
+ rules.append((pattern, action, False))
+ # Otherwise, just retain this one in the list
+ else:
+ rules.append((pattern, action, False))
+ # Move any down button filter rule
+ if downi is not None:
+ rule = rules[downi]
+ del rules[downi]
+ rules.insert(downi+1, rule)
+ mlist.header_filter_rules = rules
+ # Everything else is dealt with by the base handler
+ GUIBase.handleForm(self, mlist, category, subcat, cgidata, doc)