summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Mailman/Handlers/Cleanse.py6
-rw-r--r--Mailman/docs/cleanse.txt110
-rw-r--r--Mailman/testing/test_cleanse.py32
-rw-r--r--Mailman/testing/test_handlers.py65
4 files changed, 145 insertions, 68 deletions
diff --git a/Mailman/Handlers/Cleanse.py b/Mailman/Handlers/Cleanse.py
index cb148c8c0..d84f988e3 100644
--- a/Mailman/Handlers/Cleanse.py
+++ b/Mailman/Handlers/Cleanse.py
@@ -39,15 +39,15 @@ def process(mlist, msg, msgdata):
# We remove other headers from anonymous lists
if mlist.anonymous_list:
log.info('post to %s from %s anonymized',
- mlist.internal_name(), msg.get('from'))
+ mlist.fqdn_listname, msg.get('from'))
del msg['from']
del msg['reply-to']
del msg['sender']
# Hotmail sets this one
del msg['x-originating-email']
i18ndesc = str(uheader(mlist, mlist.description, 'From'))
- msg['From'] = formataddr((i18ndesc, mlist.GetListEmail()))
- msg['Reply-To'] = mlist.GetListEmail()
+ msg['From'] = formataddr((i18ndesc, mlist.posting_address))
+ msg['Reply-To'] = mlist.posting_address
# Some headers can be used to fish for membership
del msg['return-receipt-to']
del msg['disposition-notification-to']
diff --git a/Mailman/docs/cleanse.txt b/Mailman/docs/cleanse.txt
new file mode 100644
index 000000000..85b636737
--- /dev/null
+++ b/Mailman/docs/cleanse.txt
@@ -0,0 +1,110 @@
+Cleansing headers
+=================
+
+All messages posted to a list get their headers cleansed. Some headers are
+related to additional permissions that can be granted to the message and other
+headers can be used to fish for membership.
+
+ >>> from email import message_from_string
+ >>> from Mailman.Message import Message
+ >>> from Mailman.Handlers.Cleanse import process
+ >>> from Mailman.configuration import config
+ >>> from Mailman.database import flush
+ >>> mlist = config.list_manager.create('_xtest@example.com')
+ >>> flush()
+
+Headers such as Approved, Approve, and Urgent are used to grant special
+pemissions to individual messages. All may contain a password; the first two
+headers are used by list administrators to pre-approve a message normal held
+for approval. The latter header is used to send a regular message to all
+members, regardless of whether they get digests or not. Because all three
+headers contain passwords, they must be removed from any posted message.
+
+ >>> msg = message_from_string("""\
+ ... From: aperson@example.com
+ ... Approved: foobar
+ ... Approve: barfoo
+ ... Urgent: notreally
+ ... Subject: A message of great import
+ ...
+ ... Blah blah blah
+ ... """, Message)
+ >>> process(mlist, msg, {})
+ >>> print msg.as_string()
+ From: aperson@example.com
+ Subject: A message of great import
+ <BLANKLINE>
+ Blah blah blah
+ <BLANKLINE>
+
+Other headers can be used by list members to fish the list for membership, so
+we don't let them go through. These are a mix of standard headers and custom
+headers supported by some mail readers. For example, X-PMRC is supported by
+Pegasus mail. I don't remember what program uses X-Confirm-Reading-To though
+(Some Microsoft product perhaps?).
+
+ >>> msg = message_from_string("""\
+ ... From: bperson@example.com
+ ... Reply-To: bperson@example.org
+ ... Sender: asystem@example.net
+ ... Return-Receipt-To: another@example.com
+ ... Disposition-Notification-To: athird@example.com
+ ... X-Confirm-Reading-To: afourth@example.com
+ ... X-PMRQC: afifth@example.com
+ ... Subject: a message to you
+ ...
+ ... How are you doing?
+ ... """, Message)
+ >>> process(mlist, msg, {})
+ >>> print msg.as_string()
+ From: bperson@example.com
+ Reply-To: bperson@example.org
+ Sender: asystem@example.net
+ Subject: a message to you
+ <BLANKLINE>
+ How are you doing?
+ <BLANKLINE>
+
+
+Anonymous lists
+---------------
+
+Anonymous mailing lists also try to cleanse certain identifying headers from
+the original posting, so that it is at least a bit more difficult to determine
+who sent the message. This isn't perfect though, for example, the body of the
+messages are never scrubbed (though that might not be a bad idea). The From
+and Reply-To headers in the posted message are taken from list attributes.
+
+Hotmail apparently sets X-Originating-Email.
+
+ >>> mlist.anonymous_list = True
+ >>> mlist.description = u'A Test Mailing List'
+ >>> mlist.preferred_language = u'en'
+ >>> flush()
+ >>> msg = message_from_string("""\
+ ... From: bperson@example.com
+ ... Reply-To: bperson@example.org
+ ... Sender: asystem@example.net
+ ... X-Originating-Email: cperson@example.com
+ ... Subject: a message to you
+ ...
+ ... How are you doing?
+ ... """, Message)
+ >>> process(mlist, msg, {})
+ >>> print msg.as_string()
+ Subject: a message to you
+ From: A Test Mailing List <_xtest@example.com>
+ Reply-To: _xtest@example.com
+ <BLANKLINE>
+ How are you doing?
+ <BLANKLINE>
+
+
+Clean up
+--------
+
+ >>> for mlist in config.list_manager.mailing_lists:
+ ... config.list_manager.delete(mlist)
+ >>> flush()
+ >>> list(config.list_manager.mailing_lists)
+ []
diff --git a/Mailman/testing/test_cleanse.py b/Mailman/testing/test_cleanse.py
new file mode 100644
index 000000000..97ad9c46c
--- /dev/null
+++ b/Mailman/testing/test_cleanse.py
@@ -0,0 +1,32 @@
+# 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.
+
+"""Doctest harness for the Cleanse handler."""
+
+import doctest
+import unittest
+
+options = (doctest.ELLIPSIS
+ | doctest.NORMALIZE_WHITESPACE
+ | doctest.REPORT_NDIFF)
+
+
+def test_suite():
+ suite = unittest.TestSuite()
+ suite.addTest(doctest.DocFileSuite('../docs/cleanse.txt',
+ optionflags=options))
+ return suite
diff --git a/Mailman/testing/test_handlers.py b/Mailman/testing/test_handlers.py
index bbc7f5ba8..e6a846412 100644
--- a/Mailman/testing/test_handlers.py
+++ b/Mailman/testing/test_handlers.py
@@ -39,7 +39,6 @@ from Mailman.testing.base import TestBase
from Mailman.Handlers import Acknowledge
from Mailman.Handlers import AfterDelivery
from Mailman.Handlers import Approve
-from Mailman.Handlers import Cleanse
from Mailman.Handlers import CookHeaders
from Mailman.Handlers import FileRecips
from Mailman.Handlers import Hold
@@ -137,69 +136,6 @@ X-BeenThere: %s
-class TestCleanse(TestBase):
- def setUp(self):
- TestBase.setUp(self)
-
- def test_simple_cleanse(self):
- eq = self.assertEqual
- msg = email.message_from_string("""\
-From: aperson@example.org
-Approved: yes
-Urgent: indeed
-Reply-To: bperson@example.com
-Sender: asystem@example.com
-Return-Receipt-To: another@example.com
-Disposition-Notification-To: athird@example.com
-X-Confirm-Reading-To: afourth@example.com
-X-PMRQC: afifth@example.com
-Subject: a message to you
-
-""", Message.Message)
- Cleanse.process(self._mlist, msg, {})
- eq(msg['approved'], None)
- eq(msg['urgent'], None)
- eq(msg['return-receipt-to'], None)
- eq(msg['disposition-notification-to'], None)
- eq(msg['x-confirm-reading-to'], None)
- eq(msg['x-pmrqc'], None)
- eq(msg['from'], 'aperson@example.org')
- eq(msg['reply-to'], 'bperson@example.com')
- eq(msg['sender'], 'asystem@example.com')
- eq(msg['subject'], 'a message to you')
-
- def test_anon_cleanse(self):
- eq = self.assertEqual
- msg = email.message_from_string("""\
-From: aperson@example.org
-Approved: yes
-Urgent: indeed
-Reply-To: bperson@example.com
-Sender: asystem@example.com
-Return-Receipt-To: another@example.com
-Disposition-Notification-To: athird@example.com
-X-Confirm-Reading-To: afourth@example.com
-X-PMRQC: afifth@example.com
-Subject: a message to you
-
-""", Message.Message)
- self._mlist.anonymous_list = 1
- Cleanse.process(self._mlist, msg, {})
- eq(msg['approved'], None)
- eq(msg['urgent'], None)
- eq(msg['return-receipt-to'], None)
- eq(msg['disposition-notification-to'], None)
- eq(msg['x-confirm-reading-to'], None)
- eq(msg['x-pmrqc'], None)
- eq(len(msg.get_all('from')), 1)
- eq(len(msg.get_all('reply-to')), 1)
- eq(msg['from'], '_xtest@example.com')
- eq(msg['reply-to'], '_xtest@example.com')
- eq(msg['sender'], None)
- eq(msg['subject'], 'a message to you')
-
-
-
class TestCookHeaders(TestBase):
def test_transform_noack_to_xack(self):
eq = self.assertEqual
@@ -1463,7 +1399,6 @@ Mailman rocks!
def test_suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestApprove))
- suite.addTest(unittest.makeSuite(TestCleanse))
suite.addTest(unittest.makeSuite(TestCookHeaders))
suite.addTest(unittest.makeSuite(TestFileRecips))
suite.addTest(unittest.makeSuite(TestHold))