diff options
| -rw-r--r-- | src/mailman/handlers/docs/acknowledge.rst | 8 | ||||
| -rw-r--r-- | src/mailman/handlers/docs/avoid-duplicates.rst | 12 | ||||
| -rw-r--r-- | src/mailman/handlers/docs/file-recips.rst | 27 | ||||
| -rw-r--r-- | src/mailman/handlers/docs/filtering.rst | 18 | ||||
| -rw-r--r-- | src/mailman/handlers/docs/nntp.rst | 2 | ||||
| -rw-r--r-- | src/mailman/handlers/docs/replybot.rst | 8 | ||||
| -rw-r--r-- | src/mailman/handlers/docs/rfc-2369.rst | 2 | ||||
| -rw-r--r-- | src/mailman/handlers/docs/subject-munging.rst | 2 | ||||
| -rw-r--r-- | src/mailman/handlers/docs/tagger.rst | 24 | ||||
| -rw-r--r-- | src/mailman/handlers/docs/to-outgoing.rst | 2 | ||||
| -rw-r--r-- | src/mailman/handlers/mime_delete.py | 2 | ||||
| -rw-r--r-- | src/mailman/handlers/tagger.py | 6 | ||||
| -rw-r--r-- | src/mailman/handlers/tests/test_file_recips.py | 76 | ||||
| -rw-r--r-- | src/mailman/handlers/tests/test_filter.py | 60 | ||||
| -rw-r--r-- | src/mailman/testing/helpers.py | 5 |
15 files changed, 182 insertions, 72 deletions
diff --git a/src/mailman/handlers/docs/acknowledge.rst b/src/mailman/handlers/docs/acknowledge.rst index e91f94f62..42cab04a0 100644 --- a/src/mailman/handlers/docs/acknowledge.rst +++ b/src/mailman/handlers/docs/acknowledge.rst @@ -113,9 +113,9 @@ The receipt will include the original message's subject in the response body, 1 >>> dump_msgdata(messages[0].msgdata) _parsemsg : False - listname : test@example.com + listid : test.example.com nodecorate : True - recipients : set([u'aperson@example.com']) + recipients : {'aperson@example.com'} reduced_list_headers: True ... >>> print(messages[0].msg.as_string()) @@ -150,9 +150,9 @@ If there is no subject, then the receipt will use a generic message. 1 >>> dump_msgdata(messages[0].msgdata) _parsemsg : False - listname : test@example.com + listid : test.example.com nodecorate : True - recipients : set([u'aperson@example.com']) + recipients : {'aperson@example.com'} reduced_list_headers: True ... >>> print(messages[0].msg.as_string()) diff --git a/src/mailman/handlers/docs/avoid-duplicates.rst b/src/mailman/handlers/docs/avoid-duplicates.rst index 612634941..19a41bf85 100644 --- a/src/mailman/handlers/docs/avoid-duplicates.rst +++ b/src/mailman/handlers/docs/avoid-duplicates.rst @@ -71,7 +71,7 @@ or ``Resent-CC``), then they will get a list copy. >>> msgdata = recips.copy() >>> handler.process(mlist, msg, msgdata) >>> sorted(msgdata['recipients']) - [u'aperson@example.com', u'bperson@example.com'] + ['aperson@example.com', 'bperson@example.com'] >>> print(msg.as_string()) From: Claire Person <cperson@example.com> <BLANKLINE> @@ -89,7 +89,7 @@ If they're mentioned on the ``CC`` line, they won't get a list copy. >>> msgdata = recips.copy() >>> handler.process(mlist, msg, msgdata) >>> sorted(msgdata['recipients']) - [u'bperson@example.com'] + ['bperson@example.com'] >>> print(msg.as_string()) From: Claire Person <cperson@example.com> CC: aperson@example.com @@ -109,7 +109,7 @@ to ``True`` (the default), then they still get a list copy. >>> msgdata = recips.copy() >>> handler.process(mlist, msg, msgdata) >>> sorted(msgdata['recipients']) - [u'aperson@example.com', u'bperson@example.com'] + ['aperson@example.com', 'bperson@example.com'] >>> print(msg.as_string()) From: Claire Person <cperson@example.com> CC: bperson@example.com @@ -128,7 +128,7 @@ Other headers checked for recipients include the ``To``... >>> msgdata = recips.copy() >>> handler.process(mlist, msg, msgdata) >>> sorted(msgdata['recipients']) - [u'bperson@example.com'] + ['bperson@example.com'] >>> print(msg.as_string()) From: Claire Person <cperson@example.com> To: aperson@example.com @@ -147,7 +147,7 @@ Other headers checked for recipients include the ``To``... >>> msgdata = recips.copy() >>> handler.process(mlist, msg, msgdata) >>> sorted(msgdata['recipients']) - [u'bperson@example.com'] + ['bperson@example.com'] >>> print(msg.as_string()) From: Claire Person <cperson@example.com> Resent-To: aperson@example.com @@ -166,7 +166,7 @@ Other headers checked for recipients include the ``To``... >>> msgdata = recips.copy() >>> handler.process(mlist, msg, msgdata) >>> sorted(msgdata['recipients']) - [u'bperson@example.com'] + ['bperson@example.com'] >>> print(msg.as_string()) From: Claire Person <cperson@example.com> Resent-Cc: aperson@example.com diff --git a/src/mailman/handlers/docs/file-recips.rst b/src/mailman/handlers/docs/file-recips.rst index 58af6f480..73b47adb1 100644 --- a/src/mailman/handlers/docs/file-recips.rst +++ b/src/mailman/handlers/docs/file-recips.rst @@ -34,26 +34,6 @@ returns. recipients: 7 -Missing file -============ - -The include file must live inside the list's data directory, under the name -``members.txt``. If the file doesn't exist, the list of recipients will be -empty. - - >>> import os - >>> file_path = os.path.join(mlist.data_path, 'members.txt') - >>> open(file_path) - Traceback (most recent call last): - ... - IOError: [Errno ...] - No such file or directory: u'.../_xtest@example.com/members.txt' - >>> msgdata = {} - >>> handler.process(mlist, msg, msgdata) - >>> dump_list(msgdata['recipients']) - *Empty* - - Existing file ============= @@ -61,16 +41,15 @@ If the file exists, it contains a list of addresses, one per line. These addresses are returned as the set of recipients. :: - >>> fp = open(file_path, 'w') - >>> try: + >>> import os + >>> file_path = os.path.join(mlist.data_path, 'members.txt') + >>> with open(file_path, 'w', encoding='utf-8') as fp: ... print('bperson@example.com', file=fp) ... print('cperson@example.com', file=fp) ... print('dperson@example.com', file=fp) ... print('eperson@example.com', file=fp) ... print('fperson@example.com', file=fp) ... print('gperson@example.com', file=fp) - ... finally: - ... fp.close() >>> msgdata = {} >>> handler.process(mlist, msg, msgdata) diff --git a/src/mailman/handlers/docs/filtering.rst b/src/mailman/handlers/docs/filtering.rst index 6c3735f1b..6673933ad 100644 --- a/src/mailman/handlers/docs/filtering.rst +++ b/src/mailman/handlers/docs/filtering.rst @@ -26,6 +26,8 @@ Filtering the outer content type A simple filtering setting will just search the content types of the messages parts, discarding all parts with a matching MIME type. If the message's outer content type matches the filter, the entire message will be discarded. +However, if we turn off content filtering altogether, then the handler +short-circuits. :: >>> from mailman.interfaces.mime import FilterAction @@ -42,14 +44,6 @@ content type matches the filter, the entire message will be discarded. ... """) >>> process = config.handlers['mime-delete'].process - >>> process(mlist, msg, {}) - Traceback (most recent call last): - ... - DiscardMessage: The message's content type was explicitly disallowed - -However, if we turn off content filtering altogether, then the handler -short-circuits. - >>> mlist.filter_content = False >>> msgdata = {} >>> process(mlist, msg, msgdata) @@ -74,15 +68,15 @@ crafted internally by Mailman. MIME-Version: 1.0 <BLANKLINE> xxxxx - >>> msgdata - {u'isdigest': True} + >>> dump_msgdata(msgdata) + isdigest: True Simple multipart filtering ========================== -If one of the subparts in a multipart message matches the filter type, then -just that subpart will be stripped. +If one of the subparts in a ``multipart`` message matches the filter type, +then just that subpart will be stripped. :: >>> msg = message_from_string("""\ diff --git a/src/mailman/handlers/docs/nntp.rst b/src/mailman/handlers/docs/nntp.rst index 2dfc95ce1..72bcb35f0 100644 --- a/src/mailman/handlers/docs/nntp.rst +++ b/src/mailman/handlers/docs/nntp.rst @@ -63,5 +63,5 @@ messages are gated to. >>> dump_msgdata(messages[0].msgdata) _parsemsg: False - listname : test@example.com + listid : test.example.com version : 3 diff --git a/src/mailman/handlers/docs/replybot.rst b/src/mailman/handlers/docs/replybot.rst index 638c2fdc8..9e18ce911 100644 --- a/src/mailman/handlers/docs/replybot.rst +++ b/src/mailman/handlers/docs/replybot.rst @@ -49,9 +49,9 @@ response. >>> dump_msgdata(messages[0].msgdata) _parsemsg : False - listname : _xtest@example.com + listid : _xtest.example.com nodecorate : True - recipients : set([u'aperson@example.com']) + recipients : {'aperson@example.com'} reduced_list_headers: True version : 3 @@ -141,9 +141,9 @@ Unless the ``X-Ack:`` header has a value of ``yes``, in which case, the >>> dump_msgdata(messages[0].msgdata) _parsemsg : False - listname : _xtest@example.com + listid : _xtest.example.com nodecorate : True - recipients : set([u'asystem@example.com']) + recipients : {'asystem@example.com'} reduced_list_headers: True version : 3 diff --git a/src/mailman/handlers/docs/rfc-2369.rst b/src/mailman/handlers/docs/rfc-2369.rst index 8180b0635..b5a783edc 100644 --- a/src/mailman/handlers/docs/rfc-2369.rst +++ b/src/mailman/handlers/docs/rfc-2369.rst @@ -13,7 +13,7 @@ headers generally start with the `List-` prefix. .. This is a helper function for the following section. >>> def list_headers(msg, only=None): - ... if isinstance(only, basestring): + ... if isinstance(only, str): ... only = (only.lower(),) ... elif only is None: ... only = set(header.lower() for header in msg.keys() diff --git a/src/mailman/handlers/docs/subject-munging.rst b/src/mailman/handlers/docs/subject-munging.rst index 072e80d17..6f70a9d5e 100644 --- a/src/mailman/handlers/docs/subject-munging.rst +++ b/src/mailman/handlers/docs/subject-munging.rst @@ -35,7 +35,7 @@ subject munging, a mailing list must have a preferred language. The original subject header is stored in the message metadata. >>> msgdata['original_subject'] - u'' + '' >>> print(msg['subject']) [XTest] (no subject) diff --git a/src/mailman/handlers/docs/tagger.rst b/src/mailman/handlers/docs/tagger.rst index f3303b7ef..fcefdb01c 100644 --- a/src/mailman/handlers/docs/tagger.rst +++ b/src/mailman/handlers/docs/tagger.rst @@ -55,7 +55,7 @@ and the message metadata gets a key with a list of matching topic names. <BLANKLINE> <BLANKLINE> >>> msgdata['topichits'] - [u'bar fight'] + ['bar fight'] Scanning body lines @@ -114,7 +114,7 @@ found. Keywords: barbaz <BLANKLINE> >>> msgdata['topichits'] - [u'bar fight'] + ['bar fight'] However, scanning stops at the first body line that doesn't look like a header. @@ -161,7 +161,7 @@ When set to a negative number, all body lines will be scanned. >>> print(msg['x-topics']) bar fight >>> msgdata['topichits'] - [u'bar fight'] + ['bar fight'] Scanning sub-parts @@ -175,14 +175,14 @@ text payload. ... Subject: Was ... Keywords: Raw ... Content-Type: multipart/alternative; boundary="BOUNDARY" - ... + ... ... --BOUNDARY ... From: sabo ... To: obas - ... + ... ... Subject: farbaw ... Keywords: barbaz - ... + ... ... --BOUNDARY-- ... """) >>> msgdata = {} @@ -203,7 +203,7 @@ text payload. --BOUNDARY-- <BLANKLINE> >>> msgdata['topichits'] - [u'bar fight'] + ['bar fight'] But the tagger will not descend into non-text parts. @@ -211,23 +211,23 @@ But the tagger will not descend into non-text parts. ... Subject: Was ... Keywords: Raw ... Content-Type: multipart/alternative; boundary=BOUNDARY - ... + ... ... --BOUNDARY ... From: sabo ... To: obas ... Content-Type: message/rfc822 - ... + ... ... Subject: farbaw ... Keywords: barbaz - ... + ... ... --BOUNDARY ... From: sabo ... To: obas ... Content-Type: message/rfc822 - ... + ... ... Subject: farbaw ... Keywords: barbaz - ... + ... ... --BOUNDARY-- ... """) >>> msgdata = {} diff --git a/src/mailman/handlers/docs/to-outgoing.rst b/src/mailman/handlers/docs/to-outgoing.rst index e87fd4f26..90ea137a5 100644 --- a/src/mailman/handlers/docs/to-outgoing.rst +++ b/src/mailman/handlers/docs/to-outgoing.rst @@ -37,6 +37,6 @@ additional key set: the mailing list name. _parsemsg: False bar : 2 foo : 1 - listname : test@example.com + listid : test.example.com verp : True version : 3 diff --git a/src/mailman/handlers/mime_delete.py b/src/mailman/handlers/mime_delete.py index 98c1de3f9..b5c937fdb 100644 --- a/src/mailman/handlers/mime_delete.py +++ b/src/mailman/handlers/mime_delete.py @@ -245,7 +245,7 @@ def to_plaintext(msg): filename = tempfile.mktemp('.html') fp = open(filename, 'w') try: - fp.write(subpart.get_payload(decode=True)) + fp.write(subpart.get_payload()) fp.close() cmd = os.popen(config.HTML_TO_PLAIN_TEXT_COMMAND % {'filename': filename}) diff --git a/src/mailman/handlers/tagger.py b/src/mailman/handlers/tagger.py index 803cc6d11..51ff6b39e 100644 --- a/src/mailman/handlers/tagger.py +++ b/src/mailman/handlers/tagger.py @@ -37,7 +37,7 @@ from mailman.interfaces.handler import IHandler OR = '|' CRNL = '\r\n' -EMPTYBYTES = b'' +EMPTYSTRING = '' NLTAB = '\n\t' @@ -104,7 +104,7 @@ def scanbody(msg, numlines=None): reader = list(email.iterators.body_line_iterator(msg)) while numlines is None or lineno < numlines: try: - line = bytes(reader.pop(0)) + line = reader.pop(0) except IndexError: break # Blank lines don't count @@ -115,7 +115,7 @@ def scanbody(msg, numlines=None): # Concatenate those body text lines with newlines, and then create a new # message object from those lines. p = _ForgivingParser() - msg = p.parsestr(EMPTYBYTES.join(lines)) + msg = p.parsestr(EMPTYSTRING.join(lines)) return msg.get_all('subject', []) + msg.get_all('keywords', []) diff --git a/src/mailman/handlers/tests/test_file_recips.py b/src/mailman/handlers/tests/test_file_recips.py new file mode 100644 index 000000000..9f3e0ec6e --- /dev/null +++ b/src/mailman/handlers/tests/test_file_recips.py @@ -0,0 +1,76 @@ +# Copyright (C) 2014 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/>. + +"""Test file-recips handler.""" + +from __future__ import absolute_import, print_function, unicode_literals + +__metaclass__ = type +__all__ = [ + 'TestFileRecips', + ] + + +import os +import unittest + +from mailman.app.lifecycle import create_list +from mailman.config import config +from mailman.testing.helpers import specialized_message_from_string as mfs +from mailman.testing.layers import ConfigLayer + + + +class TestFileRecips(unittest.TestCase): + layer = ConfigLayer + + def setUp(self): + self._mlist = create_list('test@example.com') + self._handler = config.handlers['file-recipients'].process + self._msg = mfs("""\ +From: aperson@example.com + +A message. +""") + + def test_file_is_missing(self): + # It is not an error for the list's the members.txt file to be + # missing. The missing file is just ignored. + msgdata = {} + self._handler(self._mlist, self._msg, msgdata) + self.assertEqual(msgdata['recipients'], set()) + + def test_file_exists(self): + # Like above, but the file exists and contains recipients. + path = os.path.join(self._mlist.data_path, 'members.txt') + with open(path, 'w', encoding='utf-8') as fp: + print('bperson@example.com', file=fp) + print('cperson@example.com', file=fp) + print('dperson@example.com', file=fp) + print('eperson@example.com', file=fp) + print('fperson@example.com', file=fp) + print('gperson@example.com', file=fp) + msgdata = {} + self._handler(self._mlist, self._msg, msgdata) + self.assertEqual(msgdata['recipients'], set(( + 'bperson@example.com', + 'cperson@example.com', + 'dperson@example.com', + 'eperson@example.com', + 'fperson@example.com', + 'gperson@example.com', + ))) diff --git a/src/mailman/handlers/tests/test_filter.py b/src/mailman/handlers/tests/test_filter.py new file mode 100644 index 000000000..292e646cd --- /dev/null +++ b/src/mailman/handlers/tests/test_filter.py @@ -0,0 +1,60 @@ +# Copyright (C) 2014 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/>. + +"""Test the filter handler.""" + +from __future__ import absolute_import, print_function, unicode_literals + +__metaclass__ = type +__all__ = [ + 'TestFilters', + ] + + +import unittest + +from mailman.app.lifecycle import create_list +from mailman.config import config +from mailman.core.errors import DiscardMessage +from mailman.interfaces.mime import FilterAction +from mailman.testing.helpers import specialized_message_from_string as mfs +from mailman.testing.layers import ConfigLayer + + + +class TestFilters(unittest.TestCase): + layer = ConfigLayer + + def setUp(self): + self._mlist = create_list('test@example.com') + + def test_discard_when_outer_type_matches(self): + # When the outer MIME type of the message matches a filter type, the + # entire message is discarded. + self._mlist.filter_content = True + self._mlist.filter_types = ['image/jpeg'] + self._mlist.filter_action = FilterAction.discard + msg = mfs("""\ +From: aperson@example.com +Content-Type: image/jpeg +MIME-Version: 1.0 + +xxxxx +""") + self.assertRaises(DiscardMessage, + config.handlers['mime-delete'].process, + self._mlist, msg, {}) diff --git a/src/mailman/testing/helpers.py b/src/mailman/testing/helpers.py index 882e69cd9..5bfac20ee 100644 --- a/src/mailman/testing/helpers.py +++ b/src/mailman/testing/helpers.py @@ -471,10 +471,11 @@ def reset_the_world(): """ # Reset the database between tests. config.db._reset() - # Remove any digest files. + # Remove any digest files and members.txt file (for the file-recips + # handler) in the lists' data directories. for dirpath, dirnames, filenames in os.walk(config.LIST_DATA_DIR): for filename in filenames: - if filename.endswith('.mmdf'): + if filename.endswith('.mmdf') or filename == 'members.txt': os.remove(os.path.join(dirpath, filename)) # Remove all residual queue files. for dirpath, dirnames, filenames in os.walk(config.QUEUE_DIR): |
