summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBarry Warsaw2007-12-29 01:31:12 -0500
committerBarry Warsaw2007-12-29 01:31:12 -0500
commitd5c2865c3b247a96f4cfd8523b725b8eaffbde80 (patch)
treeb925796d715daec6837190491d7a53ffc88b3143
parentb7fc1a2cd9cc63f9bfafb6d3e7a28f3b64f3ed97 (diff)
downloadmailman-d5c2865c3b247a96f4cfd8523b725b8eaffbde80.tar.gz
mailman-d5c2865c3b247a96f4cfd8523b725b8eaffbde80.tar.zst
mailman-d5c2865c3b247a96f4cfd8523b725b8eaffbde80.zip
-rw-r--r--Mailman/docs/loop.txt50
-rw-r--r--Mailman/rules/approved.py3
-rw-r--r--Mailman/rules/emergency.py1
-rw-r--r--Mailman/rules/loop.py47
4 files changed, 100 insertions, 1 deletions
diff --git a/Mailman/docs/loop.txt b/Mailman/docs/loop.txt
new file mode 100644
index 000000000..3174805b9
--- /dev/null
+++ b/Mailman/docs/loop.txt
@@ -0,0 +1,50 @@
+Posting loops
+=============
+
+To avoid a posting loop, Mailman has a rule to check for the existence of an
+X-BeenThere header with the value of the list's posting address.
+
+ >>> from Mailman.configuration import config
+ >>> mlist = config.db.list_manager.create(u'_xtest@example.com')
+ >>> from Mailman.app.rules import find_rule
+ >>> rule = find_rule('loop')
+ >>> rule.name
+ 'loop'
+
+The header could be missing, in which case the rule does not match.
+
+ >>> msg = message_from_string(u"""\
+ ... From: aperson@example.com
+ ...
+ ... An important message.
+ ... """)
+ >>> rule.check(mlist, msg, {})
+ False
+
+The header could be present, but not match the list's posting address.
+
+ >>> msg['X-BeenThere'] = u'not-this-list@example.com'
+ >>> rule.check(mlist, msg, {})
+ False
+
+If the header is present and does match the posting address, the rule
+matches.
+
+ >>> del msg['x-beenthere']
+ >>> msg['X-BeenThere'] = mlist.posting_address
+ >>> rule.check(mlist, msg, {})
+ True
+
+Even if there are multiple X-BeenThere headers, as long as one with the
+posting address exists, the rule matches.
+
+ >>> msg = message_from_string(u"""\
+ ... From: aperson@example.com
+ ... X-BeenThere: not-this-list@example.com
+ ... X-BeenThere: _xtest@example.com
+ ... X-BeenThere: foo@example.com
+ ...
+ ... An important message.
+ ... """)
+ >>> rule.check(mlist, msg, {})
+ True
diff --git a/Mailman/rules/approved.py b/Mailman/rules/approved.py
index e5c13f770..b9b041c2e 100644
--- a/Mailman/rules/approved.py
+++ b/Mailman/rules/approved.py
@@ -15,7 +15,7 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
# USA.
-"""Look for a matching Approve header."""
+"""Look for moderator pre-approval."""
__all__ = ['approve_rule']
__metaclass__ = type
@@ -34,6 +34,7 @@ EMPTYSTRING = u''
class Approved:
+ """Look for moderator pre-approval."""
implements(IRule)
name = 'approved'
diff --git a/Mailman/rules/emergency.py b/Mailman/rules/emergency.py
index 16cb0db8a..989e4fff7 100644
--- a/Mailman/rules/emergency.py
+++ b/Mailman/rules/emergency.py
@@ -29,6 +29,7 @@ from Mailman.interfaces import IRule
class Emergency:
+ """The emergency hold rule."""
implements(IRule)
name = 'emergency'
diff --git a/Mailman/rules/loop.py b/Mailman/rules/loop.py
new file mode 100644
index 000000000..77cedb0a6
--- /dev/null
+++ b/Mailman/rules/loop.py
@@ -0,0 +1,47 @@
+# Copyright (C) 2007 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
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program 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 this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+# USA.
+
+"""Look for a posting loop."""
+
+__all__ = ['loop_rule']
+__metaclass__ = type
+
+
+from zope.interface import implements
+
+from Mailman.i18n import _
+from Mailman.interfaces import IRule
+
+
+
+class Loop:
+ """Look for a posting loop."""
+ implements(IRule)
+
+ name = 'loop'
+ description = _("""Look for a posting loop, via the X-BeenThere header.""")
+
+ def check(self, mlist, msg, msgdata):
+ """See `IRule`."""
+ # Has this message already been posted to this list?
+ been_theres = [value.strip().lower()
+ for value in msg.get_all('x-beenthere', [])]
+ return mlist.posting_address in been_theres
+
+
+
+loop_rule = Loop()