diff --git a/0001-fix-tests-assertion-error.patch b/0001-fix-tests-assertion-error.patch deleted file mode 100644 index c909ed7f2c94ffccc6eed4080d515bb7d627cac1..0000000000000000000000000000000000000000 --- a/0001-fix-tests-assertion-error.patch +++ /dev/null @@ -1,112 +0,0 @@ -From 3b8f0a3c4981f61d2f9b759b27a1e4b3c1d504aa Mon Sep 17 00:00:00 2001 -From: baizg1107 -Date: Mon, 20 Jun 2022 11:33:30 +0800 -Subject: [PATCH] fix tests assertion error - ---- - src/mailman/commands/tests/test_cli_addmembers.py | 1 + - src/mailman/commands/tests/test_cli_delmembers.py | 1 + - src/mailman/commands/tests/test_cli_notify.py | 7 +++---- - src/mailman/commands/tests/test_cli_syncmembers.py | 12 ++++++------ - src/mailman/model/tests/test_listmanager.py | 12 ++++++------ - 5 files changed, 17 insertions(+), 16 deletions(-) - -diff --git a/src/mailman/commands/tests/test_cli_addmembers.py b/src/mailman/commands/tests/test_cli_addmembers.py -index 13f6ff7..6c87b9d 100644 ---- a/src/mailman/commands/tests/test_cli_addmembers.py -+++ b/src/mailman/commands/tests/test_cli_addmembers.py -@@ -253,6 +253,7 @@ class TestCLIAddMembers(unittest.TestCase): - print('Anne Person ', file=infp) - result = self._command.invoke(addmembers, ( - '-i', infp.name, 'ant.example.com')) -+ self.maxDiff = None - self.assertEqual(result.output, '') - self.assertEqual(result.exit_code, 0) - members = list(self._mlist.members.members) -diff --git a/src/mailman/commands/tests/test_cli_delmembers.py b/src/mailman/commands/tests/test_cli_delmembers.py -index 297e0bf..091c134 100644 ---- a/src/mailman/commands/tests/test_cli_delmembers.py -+++ b/src/mailman/commands/tests/test_cli_delmembers.py -@@ -143,6 +143,7 @@ class TestCLIDelMembers(unittest.TestCase): - print('Bart Person ', file=infp) - result = self._command.invoke(delmembers, ( - '--fromall', '-f', infp.name)) -+ self.maxDiff = None - self.assertEqual(result.output, '') - members = list(self._mlist.members.members) - self.assertEqual(len(members), 1) -diff --git a/src/mailman/commands/tests/test_cli_notify.py b/src/mailman/commands/tests/test_cli_notify.py -index 8b37922..30b4518 100644 ---- a/src/mailman/commands/tests/test_cli_notify.py -+++ b/src/mailman/commands/tests/test_cli_notify.py -@@ -134,10 +134,9 @@ No such list found: bogus@example.com - # Clear messages from setup. - get_queue_messages('virgin') - result = self._command.invoke(notify, ('-v',)) -- self.assertMultiLineEqual(result.output, """\ --The ant@example.com list has 4 moderation requests waiting. --The bee@example.com list has 0 moderation requests waiting. --""") -+ self.maxDiff = None -+ equaldiff = result.output -+ self.assertMultiLineEqual(result.output, equaldiff) - msg = get_queue_messages('virgin', expected_count=1)[0].msg - self.assertMultiLineEqual(msg.get_payload(), """\ - The ant@example.com list has 4 moderation requests waiting. -diff --git a/src/mailman/commands/tests/test_cli_syncmembers.py b/src/mailman/commands/tests/test_cli_syncmembers.py -index 3a30bbf..6dc46b0 100644 ---- a/src/mailman/commands/tests/test_cli_syncmembers.py -+++ b/src/mailman/commands/tests/test_cli_syncmembers.py -@@ -106,11 +106,10 @@ class TestCLISyncMembers(unittest.TestCase): - print('Anne Person ', file=infp) - result = self._command.invoke(syncmembers, ( - infp.name, 'ant.example.com')) -+ self.maxDiff = None -+ equaldiff = result.output - self.assertEqual( -- result.output, -- '[ADD] Anne Person \n' -- 'Membership is banned (skipping): ' -- 'Anne Person \n' -+ result.output, equaldiff - ) - self.assertEqual(len(list(self._mlist.members.members)), 0) - -@@ -413,8 +412,9 @@ class TestCLISyncMembers(unittest.TestCase): - print('Anne Person ', file=infp) - result = self._command.invoke(syncmembers, ( - infp.name, 'ant.example.com')) -- self.assertEqual(result.output, -- '[ADD] Anne Person \n') -+ self.assertEqual(result.exit_code, 0) -+ equaldiff = result.output -+ self.assertEqual(result.output, equaldiff) - self.assertEqual(result.exit_code, 0) - members = list(self._mlist.members.members) - self.assertEqual(len(members), 1) -diff --git a/src/mailman/model/tests/test_listmanager.py b/src/mailman/model/tests/test_listmanager.py -index 8e0ba03..82f8427 100644 ---- a/src/mailman/model/tests/test_listmanager.py -+++ b/src/mailman/model/tests/test_listmanager.py -@@ -81,12 +81,12 @@ class TestListManager(unittest.TestCase): - - def test_list_manager_list_ids(self): - # You can get all the list ids for all the existing mailing lists. -- create_list('ant@example.com') -- create_list('bee@example.com') -- create_list('cat@example.com') -- self.assertEqual( -- sorted(getUtility(IListManager).list_ids), -- ['ant.example.com', 'bee.example.com', 'cat.example.com']) -+ ant = create_list('ant@example.com') -+ bee = create_list('bee@example.com') -+ cat = create_list('cat@example.com') -+ self.assertEqual(ant.list_id, 'ant.example.com') -+ self.assertEqual(bee.list_id, 'bee.example.com') -+ self.assertEqual(cat.list_id, 'cat.example.com') - - def test_delete_list_with_list_archiver_set(self): - # Ensure that mailing lists with archiver sets can be deleted. In --- -2.27.0 - diff --git a/Remove-old-style-coroutines-and-use-async-def-instead.patch b/Remove-old-style-coroutines-and-use-async-def-instead.patch deleted file mode 100644 index 3fe9402626c5bc2f2825c6af27ac31343939b47f..0000000000000000000000000000000000000000 --- a/Remove-old-style-coroutines-and-use-async-def-instead.patch +++ /dev/null @@ -1,120 +0,0 @@ -From 38c794d9ed71f25ee138760461f66abc29dfa81c Mon Sep 17 00:00:00 2001 -From: Abhilash Raj -Date: Sun, 20 Dec 2020 05:26:18 +0000 -Subject: [PATCH] Remove old style coroutines and use async def instead. - ---- - src/mailman/testing/mta.py | 39 ++++++++++++++++---------------------- - 1 file changed, 16 insertions(+), 23 deletions(-) - -diff --git a/src/mailman/testing/mta.py b/src/mailman/testing/mta.py -index aede4a24da..aa6543056d 100644 ---- a/src/mailman/testing/mta.py -+++ b/src/mailman/testing/mta.py -@@ -18,7 +18,6 @@ - """Fake MTA for testing purposes.""" - from __future__ import generator_stop - --import asyncio - import smtplib - - from aiosmtpd.controller import Controller -@@ -54,14 +53,12 @@ class ConnectionCountingHandler(MessageHandler): - def handle_message(self, message): - self._msg_queue.put(message) - -- @asyncio.coroutine -- def handle_EHLO(self, server, session, envelope, hostname): -+ async def handle_EHLO(self, server, session, envelope, hostname): - session.host_name = hostname -- yield from server.push('250-AUTH PLAIN') -+ await server.push('250-AUTH PLAIN') - return '250 HELP' - -- @asyncio.coroutine -- def handle_RSET(self, server, session, envelope): -+ async def handle_RSET(self, server, session, envelope): - self.connection_count = 0 - return '250 OK' - -@@ -83,8 +80,7 @@ class ConnectionCountingSMTP(SMTP): - # same though, so it's fine to stash this value away there. - self.event_handler.connection_count += 1 - -- @asyncio.coroutine -- def smtp_AUTH(self, arg): -+ async def smtp_AUTH(self, arg): - """Record that the AUTH occurred.""" - args = arg.split() - if args[0].lower() == 'plain': -@@ -94,25 +90,24 @@ class ConnectionCountingSMTP(SMTP): - # which must be equal to the base 64 equivalent of the - # expected login string "testuser:testpass". - if response == 'AHRlc3R1c2VyAHRlc3RwYXNz': -- yield from self.push('235 Ok') -+ await self.push('235 Ok') - self._oob_queue.put(response) - else: -- yield from self.push('571 Bad authentication') -+ await self.push('571 Bad authentication') - else: - assert len(args) == 1, args - # Send a challenge and set us up to wait for the response. -- yield from self.push('334 ') -+ await self.push('334 ') - self._waiting_for_auth_response = True - else: -- yield from self.push('571 Bad authentication') -+ await self.push('571 Bad authentication') - -- @asyncio.coroutine -- def smtp_STAT(self, arg): -+ async def smtp_STAT(self, arg): - """Cause the server to send statistics to its controller.""" - # Do not count the connection caused by the STAT connect. - self.event_handler.connection_count -= 1 - self._oob_queue.put(self.event_handler.connection_count) -- yield from self.push('250 Ok') -+ await self.push('250 Ok') - - def _next_error(self, command): - """Return the next error for the SMTP command, if there is one. -@@ -139,29 +134,27 @@ class ConnectionCountingSMTP(SMTP): - return code - return None - -- @asyncio.coroutine -- def smtp_RCPT(self, arg): -+ async def smtp_RCPT(self, arg): - """For testing, sometimes cause a non-25x response.""" - code = self._next_error('rcpt') - if code is None: - # Everything's cool. -- yield from super().smtp_RCPT(arg) -+ await super().smtp_RCPT(arg) - else: - # The test suite wants this to fail. The message corresponds to - # the exception we expect smtplib.SMTP to raise. -- yield from self.push('%d Error: SMTPRecipientsRefused' % code) -+ await self.push('%d Error: SMTPRecipientsRefused' % code) - -- @asyncio.coroutine -- def smtp_MAIL(self, arg): -+ async def smtp_MAIL(self, arg): - """For testing, sometimes cause a non-25x response.""" - code = self._next_error('mail') - if code is None: - # Everything's cool. -- yield from super().smtp_MAIL(arg) -+ await super().smtp_MAIL(arg) - else: - # The test suite wants this to fail. The message corresponds to - # the exception we expect smtplib.SMTP to raise. -- yield from self.push('%d Error: SMTPResponseException' % code) -+ await self.push('%d Error: SMTPResponseException' % code) - - - class ConnectionCountingController(Controller): --- -GitLab - diff --git a/Require-authheaders-0.14.0-and-adjust-tests-accordingly.patch b/Require-authheaders-0.14.0-and-adjust-tests-accordingly.patch deleted file mode 100644 index 3a11903d25a0d1f3953241c34ef169c4f54df004..0000000000000000000000000000000000000000 --- a/Require-authheaders-0.14.0-and-adjust-tests-accordingly.patch +++ /dev/null @@ -1,64 +0,0 @@ -From 6eada072194037049e5875edc4fda914d9c67f83 Mon Sep 17 00:00:00 2001 -From: starlet-dx <15929766099@163.com> -Date: Thu, 19 Jan 2023 15:08:54 +0800 -Subject: [PATCH 1/1] Require authheaders >=0.14.0 and adjust tests accordingly. - ---- - setup.py | 2 +- - src/mailman/handlers/tests/test_arc_validate.py | 13 ++++++++----- - 2 files changed, 9 insertions(+), 6 deletions(-) - -diff --git a/setup.py b/setup.py -index 5eceac2..5171d0e 100644 ---- a/setup.py -+++ b/setup.py -@@ -113,7 +113,7 @@ case second 'm'. Any other spelling is incorrect.""", - 'aiosmtpd>=1.1', - 'alembic', - 'atpublic', -- 'authheaders>=0.9.2', -+ 'authheaders>=0.14.0', - 'authres>=1.0.1', - 'click>=8.0.0', - 'dnspython>=1.14.0', -diff --git a/src/mailman/handlers/tests/test_arc_validate.py b/src/mailman/handlers/tests/test_arc_validate.py -index 6eb2f57..2103b08 100644 ---- a/src/mailman/handlers/tests/test_arc_validate.py -+++ b/src/mailman/handlers/tests/test_arc_validate.py -@@ -190,8 +190,9 @@ This is a test message. - """) - - ValidateAuthenticity().process(lst, msg, msgdata) -- res = ["lists.example.org; spf=pass smtp.mfrom=jqd@d1.example" -- "; dkim=pass header.i=@d1.example; dmarc=pass; arc=fail"] -+ res = ['lists.example.org; spf=pass smtp.mfrom=jqd@d1.example', -+ '; dkim=pass header.i=@d1.example; dmarc=pass; arc=fail ', -+ '(Most recent ARC-Message-Signature did not validate)'] - self.assertEqual(msg["Authentication-Results"], ''.join(res)) - - def test_authentication_whitelist_hit(self): -@@ -233,8 +234,9 @@ This is a test! - - ValidateAuthenticity().process(lst, msg, msgdata) - -- res = ["example.com; spf=pass smtp.mailfrom=gmail.com" -- "; dkim=pass header.d=valimail.com; arc=none"] -+ res = ['example.com; spf=pass smtp.mailfrom=gmail.com', -+ '; dkim=pass header.d=valimail.com; arc=none ', -+ '(Message is not ARC signed)'] - self.assertEqual(msg["Authentication-Results"], ''.join(res)) - - def test_authentication_whitelist_miss(self): -@@ -277,7 +279,8 @@ This is a test! - - ValidateAuthenticity().process(lst, msg, msgdata) - self.assertEqual(msg["Authentication-Results"], -- "test.com; dkim=pass header.d=valimail.com; arc=none") -+ 'test.com; dkim=pass header.d=valimail.com; arc=none ' -+ '(Message is not ARC signed)') - - - class TestTimeout(unittest.TestCase): --- -2.30.0 - diff --git a/Support-Python-3.11.patch b/Support-Python-3.11.patch deleted file mode 100644 index 3d15a3df928712337b0a3f0714941bf800c11065..0000000000000000000000000000000000000000 --- a/Support-Python-3.11.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 1f2b19c8ad7235f5632a170c91e766462884813e Mon Sep 17 00:00:00 2001 -From: starlet-dx <15929766099@163.com> -Date: Sun, 23 Jul 2023 15:19:02 +0800 -Subject: [PATCH 1/1] Support Python 3.11 - -Refer: -https://gitlab.com/mailman/mailman/-/commit/1954815f32fea4d9d920cdc74f63bcc24d3b6c49 ---- - src/mailman/runners/lmtp.py | 17 ++++++++++++----- - 1 file changed, 12 insertions(+), 5 deletions(-) - -diff --git a/src/mailman/runners/lmtp.py b/src/mailman/runners/lmtp.py -index a653275..0fc45bf 100644 ---- a/src/mailman/runners/lmtp.py -+++ b/src/mailman/runners/lmtp.py -@@ -35,7 +35,6 @@ so that the peer mail server can provide better diagnostics. - """ - - import email --import asyncio - import logging - - from aiosmtpd.controller import Controller -@@ -126,9 +125,13 @@ def split_recipient(address): - - - class LMTPHandler: -- @asyncio.coroutine -+ async def handle_RCPT(self, server, session, envelope, to, rcpt_options): -+ # Use a helper function to use the transactional wrapper on since it -+ # doesn't yet work on awaitables (async def funcs.) -+ return self._handle_RCPT(server, session, envelope, to, rcpt_options) -+ - @transactional -- def handle_RCPT(self, server, session, envelope, to, rcpt_options): -+ def _handle_RCPT(self, server, session, envelope, to, rcpt_options): - listnames = set(getUtility(IListManager).names) - try: - to = parseaddr(to)[1].lower() -@@ -164,9 +167,13 @@ class LMTPHandler: - config.db.abort() - return ERR_550 - -- @asyncio.coroutine -+ async def handle_DATA(self, server, session, envelope): -+ # Use a helper function to use the transactional wrapper on since it -+ # doesn't yet work on awaitables (async def funcs.) -+ return self._handle_DATA(server, session, envelope) -+ - @transactional -- def handle_DATA(self, server, session, envelope): -+ def _handle_DATA(self, server, session, envelope): - try: - # Refresh the list of list names every time we process a message - # since the set of mailing lists could have changed. --- -2.30.0 - diff --git a/Verify-recipient-validity-at-RCPT-command-in-LMTP-runner.patch b/Verify-recipient-validity-at-RCPT-command-in-LMTP-runner.patch deleted file mode 100644 index 54380526265712c8c075c90150c48e59e3eb6b63..0000000000000000000000000000000000000000 --- a/Verify-recipient-validity-at-RCPT-command-in-LMTP-runner.patch +++ /dev/null @@ -1,217 +0,0 @@ -From b9387743835821e8327e73aa502cb01f2f83dc97 Mon Sep 17 00:00:00 2001 -From: Patrick Cernko -Date: Wed, 19 Oct 2022 23:27:10 +0000 -Subject: [PATCH] Verify recipient validity at RCPT command in LMTP runner (2nd - try) - -Verify recipient validity at RCPT command in LMTP runner (reviewed merge request c2ddff05a4f405fa46fb792cc69912829c1cbf83, rejected 2 years ago) -* returning '250 ok' to correctly accept valid recipients -* reorganized code a bit to better match existing recipient verification code in handle_DATA() -* fixed unit tests (verified with `tox -e py39-nocov` on Debian/bullseye) - -See !671 for the original merge request by @foxcpp. Also see !126. - -Fixes #14 ---- - src/mailman/docs/NEWS.rst | 5 +++ - src/mailman/docs/mta.rst | 38 ++++++++++++++++++++++ - src/mailman/runners/lmtp.py | 38 ++++++++++++++++++++++ - src/mailman/runners/tests/test_lmtp.py | 45 ++++++++++++++++++++------ - 4 files changed, 117 insertions(+), 9 deletions(-) - -diff --git a/src/mailman/docs/mta.rst b/src/mailman/docs/mta.rst -index bd2df65948..cc85910b2c 100644 ---- a/src/mailman/docs/mta.rst -+++ b/src/mailman/docs/mta.rst -@@ -253,6 +253,8 @@ which are local, you may need ``local_recipient_maps`` as above. Note that - these can be ``regexp`` tables rather than ``hash`` tables. See the - ``Transport maps`` section above. - -+Starting with version 3.3.6, it is possible to use Mailman's LMTP -+service with Postfix' ``reject_unverified_recipient``. - - Postfix documentation - --------------------- -@@ -381,6 +383,42 @@ two lines to the ``mailman3_transport:`` section. - headers_remove = message-id - headers_add = "Message-ID: ${if def:header_message-id:{$h_message-id:}{}}" - -+Alternative setup using callout verification -+-------------------------------------------- -+ -+Starting with version 3.3.6, you can rely on Mailman's responce on -+``RCPT TO:`` LMTP command if mailman would accept the recipient -+address as valid. This can be used in Exim to validate recipients -+using callout verification. -+:: -+ -+ # /etc/exim4/conf.d/main/25_mm3_macros -+ # The colon-separated list of domains served by Mailman. -+ domainlist mm_domains = list.example.net -+ # The port of your Mailman's LMTP service -+ MM3_LMTP_PORT = 8024 -+ -+ # /etc/exim4/local_rcpt_callout (create file or append if already exists) -+ # Make callout verification for all domains served by Mailman. -+ *@+mm_domains -+ -+ # /etc/exim4/conf.d/router/455_mm3_router -+ mailman3_router: -+ driver = accept -+ domains = +mm_domains -+ # no further conditions, valid recipients are verified in -+ # acl_check_rcpt using callout verification -+ transport = mailman3_transport -+ -+ # /etc/exim4/conf.d/transport/55_mm3_transport -+ mailman3_transport: -+ driver = smtp -+ protocol = lmtp -+ allow_localhost -+ hosts = localhost -+ port = MM3_LMTP_PORT -+ rcpt_include_affixes = true -+ - Exim 4 documentation - -------------------- - -diff --git a/src/mailman/runners/lmtp.py b/src/mailman/runners/lmtp.py -index 53318f7120..b5b5b181ef 100644 ---- a/src/mailman/runners/lmtp.py -+++ b/src/mailman/runners/lmtp.py -@@ -126,6 +126,44 @@ def split_recipient(address): - - - class LMTPHandler: -+ @asyncio.coroutine -+ @transactional -+ def handle_RCPT(self, server, session, envelope, to, rcpt_options): -+ listnames = set(getUtility(IListManager).names) -+ try: -+ to = parseaddr(to)[1].lower() -+ local, subaddress, domain = split_recipient(to) -+ if subaddress is not None: -+ # Check that local-subaddress is not an actual list name. -+ listname = '{}-{}@{}'.format(local, subaddress, domain) -+ if listname in listnames: -+ local = '{}-{}'.format(local, subaddress) -+ subaddress = None -+ listname = '{}@{}'.format(local, domain) -+ if listname not in listnames: -+ return ERR_550 -+ canonical_subaddress = SUBADDRESS_NAMES.get(subaddress) -+ if subaddress is None: -+ # The message is destined for the mailing list. -+ # nothing to do here, just keep code similar to handle_DATA -+ pass -+ elif canonical_subaddress is None: -+ # The subaddress was bogus. -+ slog.error('unknown sub-address: %s', subaddress) -+ return ERR_550 -+ else: -+ # A valid subaddress. -+ # nothing to do here, just keep code similar to handle_DATA -+ pass -+ # recipient validated, just do the same as aiosmtpd.LMTP would do -+ envelope.rcpt_tos.append(to) -+ envelope.rcpt_options.extend(rcpt_options) -+ return '250 Ok' -+ except Exception: -+ slog.exception('Address verification: %s', to) -+ config.db.abort() -+ return ERR_550 -+ - @asyncio.coroutine - @transactional - def handle_DATA(self, server, session, envelope): -diff --git a/src/mailman/runners/tests/test_lmtp.py b/src/mailman/runners/tests/test_lmtp.py -index 3d0f8e0e5d..5200228028 100644 ---- a/src/mailman/runners/tests/test_lmtp.py -+++ b/src/mailman/runners/tests/test_lmtp.py -@@ -114,7 +114,7 @@ Message-ID: - - def test_nonexistent_mailing_list(self): - # Trying to post to a nonexistent mailing list is an error. -- with self.assertRaises(smtplib.SMTPDataError) as cm: -+ with self.assertRaises(smtplib.SMTPRecipientsRefused) as cm: - self._lmtp.sendmail('anne@example.com', - ['notalist@example.com'], """\ - From: anne.person@example.com -@@ -123,13 +123,22 @@ Subject: An interesting message - Message-ID: - - """) -- self.assertEqual(cm.exception.smtp_code, 550) -- self.assertEqual(cm.exception.smtp_error, -+ # smtplib.SMTPRecipientsRefused.args contains a list of errors (for -+ # each RCPT TO), thus we should have only one error -+ self.assertEqual(len(cm.exception.args), 1) -+ args0 = cm.exception.args[0] -+ # each error should be a dict with the corresponding email address -+ # as key -+ self.assertTrue('notalist@example.com' in args0) -+ errorval = args0['notalist@example.com'] -+ # errorval must be a tuple of (code, errorstr) -+ self.assertEqual(errorval[0], 550) -+ self.assertEqual(errorval[1], - b'Requested action not taken: mailbox unavailable') - - def test_nonexistent_domain(self): - # Trying to post to a nonexistent domain is an error. -- with self.assertRaises(smtplib.SMTPDataError) as cm: -+ with self.assertRaises(smtplib.SMTPRecipientsRefused) as cm: - self._lmtp.sendmail('anne@example.com', - ['test@x.example.com'], """\ - From: anne.person@example.com -@@ -138,8 +147,17 @@ Subject: An interesting message - Message-ID: - - """) -- self.assertEqual(cm.exception.smtp_code, 550) -- self.assertEqual(cm.exception.smtp_error, -+ # smtplib.SMTPRecipientsRefused.args contains a list of errors (for -+ # each RCPT TO), thus we should have only one error -+ self.assertEqual(len(cm.exception.args), 1) -+ args0 = cm.exception.args[0] -+ # each error should be a dict with the corresponding email address -+ # as key -+ self.assertTrue('test@x.example.com' in args0) -+ errorval = args0['test@x.example.com'] -+ # errorval must be a tuple of (code, errorstr) -+ self.assertEqual(errorval[0], 550) -+ self.assertEqual(errorval[1], - b'Requested action not taken: mailbox unavailable') - - def test_alias_domain(self): -@@ -168,7 +186,7 @@ X-MailFrom: anne@example.com - - def test_missing_subaddress(self): - # Trying to send a message to a bogus subaddress is an error. -- with self.assertRaises(smtplib.SMTPDataError) as cm: -+ with self.assertRaises(smtplib.SMTPRecipientsRefused) as cm: - self._lmtp.sendmail('anne@example.com', - ['test-bogus@example.com'], """\ - From: anne.person@example.com -@@ -177,8 +195,17 @@ Subject: An interesting message - Message-ID: - - """) -- self.assertEqual(cm.exception.smtp_code, 550) -- self.assertEqual(cm.exception.smtp_error, -+ # smtplib.SMTPRecipientsRefused.args contains a list of errors (for -+ # each RCPT TO), thus we should have only one error -+ self.assertEqual(len(cm.exception.args), 1) -+ args0 = cm.exception.args[0] -+ # each error should be a dict with the corresponding email address -+ # as key -+ self.assertTrue('test-bogus@example.com' in args0) -+ errorval = args0['test-bogus@example.com'] -+ # errorval must be a tuple of (code, errorstr) -+ self.assertEqual(errorval[0], 550) -+ self.assertEqual(errorval[1], - b'Requested action not taken: mailbox unavailable') - - def test_mailing_list_with_subaddress(self): --- -GitLab - diff --git a/mailman-3.3.2.tar.gz b/mailman-3.3.2.tar.gz deleted file mode 100644 index 076657b0b068edd29ee5be5a2d89ea635380b7cd..0000000000000000000000000000000000000000 Binary files a/mailman-3.3.2.tar.gz and /dev/null differ diff --git a/mailman-3.3.8.tar.gz b/mailman-3.3.8.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..f0165b590d0b5edee3804873b8332e0356872053 Binary files /dev/null and b/mailman-3.3.8.tar.gz differ diff --git a/mailman-subject-prefix.patch b/mailman-subject-prefix.patch index 39638b8f0396c53122dfecfa140e4b529aac15c4..c57a6e22c18e27f6e2cde0cc8114e285650a349a 100644 --- a/mailman-subject-prefix.patch +++ b/mailman-subject-prefix.patch @@ -1,32 +1,32 @@ -From 700a1e2e3572ec2c8766da9acdaf8babce5d8d20 Mon Sep 17 00:00:00 2001 -From: Neal Gompa -Date: Thu, 15 Oct 2020 10:30:07 -0400 -Subject: [PATCH] Cover some subject prefix use cases +From d54000d8223e6f1567f669f72cb09970491fdbb2 Mon Sep 17 00:00:00 2001 +From: Neal Gompa +Date: Sat, 13 May 2023 07:27:41 -0400 +Subject: [PATCH] Cover subject prefix cases for empty subjects and non-ascii + charsets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit -The subject_prefix handler has many bugs and was mostly not covered -for lists with a non-ascii charset. +The subject_prefix handler has several bugs around empty subjects +and lacked coverage for lists with a non-ascii charset. Co-authored-by: Aurélien Bompard -Signed-off-by: Neal Gompa +Signed-off-by: Neal Gompa --- - src/mailman/handlers/subject_prefix.py | 19 +++-- - .../handlers/tests/test_subject_prefix.py | 81 +++++++++++++++++-- - 2 files changed, 87 insertions(+), 13 deletions(-) + src/mailman/handlers/subject_prefix.py | 6 +- + .../handlers/tests/test_subject_prefix.py | 82 +++++++++++++++++-- + 2 files changed, 78 insertions(+), 10 deletions(-) diff --git a/src/mailman/handlers/subject_prefix.py b/src/mailman/handlers/subject_prefix.py -index 95ec0ec2d..10ad07875 100644 +index 577149cee..a20b45115 100644 --- a/src/mailman/handlers/subject_prefix.py +++ b/src/mailman/handlers/subject_prefix.py -@@ -39,13 +39,12 @@ def ascii_header(mlist, msgdata, subject, prefix, prefix_pattern, ws): +@@ -39,12 +39,11 @@ def ascii_header(mlist, msgdata, subject, prefix, prefix_pattern, ws): if charset not in ASCII_CHARSETS: return None subject_text = EMPTYSTRING.join(str(subject).splitlines()) + subject_text = re.sub(prefix_pattern, '', subject_text) - # At this point, the subject may become null if someone posted mail - # with "Subject: [subject prefix]". + # Replace empty subject. if subject_text.strip() == '': with _.using(mlist.preferred_language.code): subject_text = _('(no subject)') @@ -35,58 +35,25 @@ index 95ec0ec2d..10ad07875 100644 msgdata['stripped_subject'] = subject_text rematch = re.match(RE_PATTERN, subject_text, re.I) if rematch: -@@ -83,13 +82,12 @@ def all_same_charset(mlist, msgdata, subject, prefix, prefix_pattern, ws): - if charset != list_charset: - return None +@@ -85,12 +84,11 @@ def all_same_charset(mlist, msgdata, subject, prefix, prefix_pattern, ws): + except UnicodeEncodeError: + return None subject_text = EMPTYSTRING.join(chunks) + subject_text = re.sub(prefix_pattern, '', subject_text) - # At this point, the subject may become null if someone posted mail - # with "Subject: [subject prefix]". + # Replace empty subject. if subject_text.strip() == '': -- with _.push(mlist.preferred_language.code): -+ with _.using(mlist.preferred_language.code): + with _.using(mlist.preferred_language.code): subject_text = _('(no subject)') - else: - subject_text = re.sub(prefix_pattern, '', subject_text) msgdata['stripped_subject'] = subject_text rematch = re.match(RE_PATTERN, subject_text, re.I) if rematch: -@@ -114,7 +112,7 @@ def mixed_charsets(mlist, msgdata, subject, prefix, prefix_pattern, ws): - list_charset = mlist.preferred_language.charset - chunks = decode_header(subject.encode()) - if len(chunks) == 0: -- with _.push(mlist.preferred_language.code): -+ with _.using(mlist.preferred_language.code): - subject_text = _('(no subject)') - chunks = [(prefix, list_charset), - (subject_text, list_charset), -@@ -134,13 +132,20 @@ def mixed_charsets(mlist, msgdata, subject, prefix, prefix_pattern, ws): - chunks.insert(0, ('', 'us-ascii')) - first_text = '' - first_text = re.sub(prefix_pattern, '', first_text).lstrip() -+ if not first_text.strip() and len(chunks) <= 1: -+ with _.using(mlist.preferred_language.code): -+ subject_text = _('(no subject)') -+ chunks = [(prefix.strip(), list_charset), -+ (subject_text, list_charset), -+ ] -+ return make_header(chunks, continuation_ws=ws) - rematch = re.match(RE_PATTERN, first_text, re.I) - if rematch: - first_text = 'Re: ' + first_text[rematch.end():] - chunks[0] = (first_text, chunk_charset) - # The subject text stripped of the prefix, for use in the NNTP gateway. - msgdata['stripped_subject'] = str(make_header(chunks, continuation_ws=ws)) -- chunks.insert(0, (prefix, list_charset)) -+ chunks.insert(0, (prefix.strip(), list_charset)) - return make_header(chunks, continuation_ws=ws) - - diff --git a/src/mailman/handlers/tests/test_subject_prefix.py b/src/mailman/handlers/tests/test_subject_prefix.py -index c2a257035..1d8bc175d 100644 +index 0b13f5068..960afa49a 100644 --- a/src/mailman/handlers/tests/test_subject_prefix.py +++ b/src/mailman/handlers/tests/test_subject_prefix.py -@@ -33,6 +33,13 @@ class TestSubjectPrefix(unittest.TestCase): +@@ -34,6 +34,13 @@ class TestSubjectPrefix(unittest.TestCase): def setUp(self): self._mlist = create_list('test@example.com') self._process = config.handlers['subject-prefix'].process @@ -100,22 +67,23 @@ index c2a257035..1d8bc175d 100644 def test_isdigest(self): # If the message is destined for the digest, the Subject header does -@@ -114,6 +121,14 @@ class TestSubjectPrefix(unittest.TestCase): +@@ -115,6 +122,15 @@ class TestSubjectPrefix(unittest.TestCase): self._process(self._mlist, msg, {}) self.assertEqual(str(msg['subject']), '[Test] A test message') + def test_multiline_subject_non_ascii_list(self): + # The subject appears on multiple lines on a non-ascii list. + self._mlist.preferred_language = 'xx' ++ self._mlist.preferred_language.charset = 'utf-8' + msg = Message() + msg['Subject'] = '\n A test message' + self._process(self._mlist, msg, {}) -+ self.assertEqual(str(msg['subject']), '[Test] A test message') ++ self.assertEqual(str(msg['subject']), '[Test] A test message') + def test_i18n_prefix(self): # The Subject header is encoded, but the prefix is still added. msg = Message() -@@ -130,7 +145,7 @@ class TestSubjectPrefix(unittest.TestCase): +@@ -131,7 +147,7 @@ class TestSubjectPrefix(unittest.TestCase): msg['Subject'] = '[Test] ' self._process(self._mlist, msg, {}) subject = msg['subject'] @@ -124,7 +92,7 @@ index c2a257035..1d8bc175d 100644 def test_prefix_only_all_same(self): # Incoming subject is only the prefix. -@@ -141,7 +156,7 @@ class TestSubjectPrefix(unittest.TestCase): +@@ -142,7 +158,7 @@ class TestSubjectPrefix(unittest.TestCase): self._process(self._mlist, msg, {}) self._mlist.preferred_language.charset = old_charset subject = msg['subject'] @@ -133,7 +101,7 @@ index c2a257035..1d8bc175d 100644 def test_prefix_only_mixed(self): # Incoming subject is only the prefix. -@@ -149,7 +164,7 @@ class TestSubjectPrefix(unittest.TestCase): +@@ -150,7 +166,7 @@ class TestSubjectPrefix(unittest.TestCase): msg['Subject'] = '=?utf-8?Q?[Test]_?=' self._process(self._mlist, msg, {}) subject = msg['subject'] @@ -142,7 +110,7 @@ index c2a257035..1d8bc175d 100644 def test_re_only(self): # Incoming subject is only Re:. -@@ -198,15 +213,13 @@ class TestSubjectPrefix(unittest.TestCase): +@@ -226,15 +242,13 @@ class TestSubjectPrefix(unittest.TestCase): def test_decode_header_returns_string(self): # Under some circumstances, email.header.decode_header() returns a # string value. Ensure we can handle that. @@ -154,15 +122,15 @@ index c2a257035..1d8bc175d 100644 self._process(self._mlist, msg, {}) subject = msg['subject'] self.assertEqual(subject.encode(), -- '=?iso-8859-1?q?=5BTest=5D_?= Plain text') -+ '=?utf-8?b?W1Rlc3Rd?= Plain text') +- '=?iso-8859-1?q?=5BTest=5D_Plain_text?=') ++ '=?utf-8?q?=5BTest=5D_Plain_text?=') def test_unknown_encoded_subject(self): msg = Message() -@@ -215,3 +228,59 @@ class TestSubjectPrefix(unittest.TestCase): - subject = msg['subject'] - self.assertEqual(str(subject), - '[Test] Non-ascii subject - fran�ais') +@@ -280,3 +294,59 @@ class TestSubjectPrefix(unittest.TestCase): + self._process(self._mlist, msg, {}) + self.assertEqual(str(msg['subject']), + '[Test] This is a folded subject header.') + + def test_non_ascii_list(self): + # The mailing list has a non-ascii language @@ -220,5 +188,5 @@ index c2a257035..1d8bc175d 100644 + self._process(self._mlist, msg, {}) + self.assertEqual(str(msg['subject']), '[Test] (no subject)') -- -2.28.0 +2.40.0 diff --git a/mailman-use-either-importlib_resources-or-directly-importlib.patch b/mailman-use-either-importlib_resources-or-directly-importlib.patch index 7996c15a6463313a8c498081c364cb4c6ff6ebe0..c133d607e09fbd554757a9b62a68b3e64ea4858a 100644 --- a/mailman-use-either-importlib_resources-or-directly-importlib.patch +++ b/mailman-use-either-importlib_resources-or-directly-importlib.patch @@ -1,13 +1,13 @@ -From a4bcacc25398fcea819bd9e6b9a531c3007aa386 Mon Sep 17 00:00:00 2001 -From: Neal Gompa -Date: Fri, 16 Oct 2020 03:47:38 -0400 +From dd56f4a645d65b8022a07dd37bb803250a157ea8 Mon Sep 17 00:00:00 2001 +From: Neal Gompa +Date: Sat, 13 May 2023 08:04:39 -0400 Subject: [PATCH] Use importlib.resources for Python 3.9+ and importlib_resources otherwise This makes it possible to use Mailman 3 in environments where importlib_resources is not available. -Signed-off-by: Neal Gompa +Signed-off-by: Neal Gompa --- setup.py | 2 +- src/mailman/__init__.py | 5 +++++ @@ -15,20 +15,20 @@ Signed-off-by: Neal Gompa 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py -index e1b2e07c5..b768ef3d2 100644 +index 5448b7cf9..c3d0f83fe 100644 --- a/setup.py +++ b/setup.py @@ -121,7 +121,7 @@ case second 'm'. Any other spelling is incorrect.""", - 'flufl.bounce', - 'flufl.i18n>=2.0', - 'flufl.lock>=3.1', + 'flufl.bounce>=4.0', + 'flufl.i18n>=3.2', + 'flufl.lock>=5.1', - 'importlib_resources>=1.1.0', + 'importlib_resources>=1.1.0 ; python_version<"3.9"', 'gunicorn', 'lazr.config', 'python-dateutil>=2.0', diff --git a/src/mailman/__init__.py b/src/mailman/__init__.py -index fa5233fab..00990be45 100644 +index ad94ffdbd..0d78b38ea 100644 --- a/src/mailman/__init__.py +++ b/src/mailman/__init__.py @@ -37,3 +37,8 @@ if 'build_sphinx' not in sys.argv: # pragma: nocover @@ -69,5 +69,5 @@ index e69de29bb..2b2ed536a 100644 + import importlib.resources + sys.modules['importlib_resources'] = importlib.resources -- -2.28.0 +2.40.0 diff --git a/mailman.spec b/mailman.spec index 8bd002e764ec7390d72272971a6785aaf794dd61..e864c4aeed9148d82913beba84b3d3f0cd91e110 100644 --- a/mailman.spec +++ b/mailman.spec @@ -6,8 +6,8 @@ %{?python_enable_dependency_generator} Name: mailman -Version: 3.3.2 -Release: 10 +Version: 3.3.8 +Release: 1 Epoch: 3 Summary: The GNU mailing list manager License: GPLv3 @@ -19,25 +19,8 @@ Source3: mailman3.service Source4: mailman3.logrotate Source5: mailman3-digests.service Source6: mailman3-digests.timer -#Refer: https://gitlab.com/mailman/mailman/-/merge_requests/860 -Patch01: mailman3-click8.patch -Patch11: mailman-subject-prefix.patch -Patch14: mailman-use-either-importlib_resources-or-directly-importlib.patch -#Refer: https://bugzilla.redhat.com/show_bug.cgi?id=1900668#c9 -Patch15: mailman3-do-not-assume-sapce-in-banner.patch -#Refer: https://gitlab.com/mailman/mailman/-/merge_requests/772 -Patch16: mailman3-test_as_string_python_bug_27321.patch -Patch17: 0001-fix-tests-assertion-error.patch -#Refer: https://gitlab.com/mailman/mailman/-/issues/964#note_1001855903 -Patch18: support-sqlalchemy-1-4.patch -#Refer: https://gitlab.com/mailman/mailman/-/merge_requests/929 -Patch19: Require-authheaders-0.14.0-and-adjust-tests-accordingly.patch -#Refer: https://gitlab.com/mailman/mailman/-/commit/38c794d9ed71f25ee138760461f66abc29dfa81c -Patch20: Remove-old-style-coroutines-and-use-async-def-instead.patch -#Refer: https://gitlab.com/mailman/mailman/-/commit/b9387743835821e8327e73aa502cb01f2f83dc97 -Patch21: Verify-recipient-validity-at-RCPT-command-in-LMTP-runner.patch -#Refer: https://gitlab.com/mailman/mailman/-/commit/1954815f32fea4d9d920cdc74f63bcc24d3b6c49 -Patch22: Support-Python-3.11.patch +Patch0001: mailman-subject-prefix.patch +Patch0002: mailman-use-either-importlib_resources-or-directly-importlib.patch BuildArch: noarch BuildRequires: glibc-langpack-en BuildRequires: python%{python3_pkgversion}-devel >= 3.5 python%{python3_pkgversion}-setuptools @@ -219,6 +202,9 @@ done %{_datadir}/selinux/*/mailman3.pp %changelog +* Wed Sep 13 2023 liyanan - 3:3.3.8-1 +- update to 3.3.8 + * Sun Jul 23 2023 yaoxin - 3:3.3.2-10 - Fix test fails caused by python update to 3.11.4 diff --git a/mailman3-click8.patch b/mailman3-click8.patch deleted file mode 100644 index 91fcf763d8dc66ebd929cc81b4e6bef687981f33..0000000000000000000000000000000000000000 --- a/mailman3-click8.patch +++ /dev/null @@ -1,107 +0,0 @@ -From 465c2ff847d462c1a9cf8f548093ba4b5be84c3b Mon Sep 17 00:00:00 2001 -From: Mark Sapiro -Date: Tue, 11 May 2021 18:14:59 -0700 -Subject: [PATCH] Require click >=8.0.0 and fix the tests it breaks. - ---- - setup.py | 2 +- - src/mailman/commands/docs/import.rst | 1 + - src/mailman/commands/tests/test_cli_addmembers.py | 8 ++++---- - src/mailman/commands/tests/test_cli_delmembers.py | 4 ++-- - src/mailman/commands/tests/test_cli_syncmembers.py | 8 ++++---- - 5 files changed, 12 insertions(+), 11 deletions(-) - -diff --git a/setup.py b/setup.py -index cd36456..ad04e77 100644 ---- a/setup.py -+++ b/setup.py -@@ -115,7 +115,7 @@ case second 'm'. Any other spelling is incorrect.""", - 'atpublic', - 'authheaders>=0.9.2', - 'authres>=1.0.1', -- 'click>=7.0.0', -+ 'click>=8.0.0', - 'dnspython>=1.14.0', - 'falcon>1.0.0', - 'flufl.bounce', -diff --git a/src/mailman/commands/docs/import.rst b/src/mailman/commands/docs/import.rst -index 947d932..66f72be 100644 ---- a/src/mailman/commands/docs/import.rst -+++ b/src/mailman/commands/docs/import.rst -@@ -58,5 +58,6 @@ import, the mailing list's "real name" will change. - Import - - >>> command('mailman import21 import@example.com ' + pickle_file) -+ Importing ... - >>> print(mlist.display_name) - Test -diff --git a/src/mailman/commands/tests/test_cli_addmembers.py b/src/mailman/commands/tests/test_cli_addmembers.py -index e257da5..95f8542 100644 ---- a/src/mailman/commands/tests/test_cli_addmembers.py -+++ b/src/mailman/commands/tests/test_cli_addmembers.py -@@ -57,8 +57,8 @@ class TestCLIAddMembers(unittest.TestCase): - result.output, - 'Usage: addmembers [OPTIONS] FILENAME LISTSPEC\n' - 'Try \'addmembers --help\' for help.\n\n' -- 'Error: Invalid value for \'FILENAME\': Could not open ' -- 'file: bad: No such file or directory\n') -+ 'Error: Invalid value for \'FILENAME\': ' -+ '\'bad\': No such file or directory\n') - - def test_already_subscribed_with_display_name(self): - subscribe(self._mlist, 'Anne') -@@ -265,8 +265,8 @@ class TestCLIAddMembers(unittest.TestCase): - 'Usage: addmembers [OPTIONS] FILENAME LISTSPEC\n' - 'Try \'addmembers --help\' for help.\n\n' - 'Error: Invalid value for \'--delivery\' / \'-d\': ' -- 'invalid choice: bogus. (choose from regular, mime, ' -- 'plain, summary, disabled)\n') -+ '\'bogus\' is not one of \'regular\', \'mime\', ' -+ '\'plain\', \'summary\', \'disabled\'.\n') - - def test_invite_member(self): - with NamedTemporaryFile('w', buffering=1, encoding='utf-8') as infp: -diff --git a/src/mailman/commands/tests/test_cli_delmembers.py b/src/mailman/commands/tests/test_cli_delmembers.py -index cf24b54..e34c22a 100644 ---- a/src/mailman/commands/tests/test_cli_delmembers.py -+++ b/src/mailman/commands/tests/test_cli_delmembers.py -@@ -56,8 +56,8 @@ class TestCLIDelMembers(unittest.TestCase): - result.output, - 'Usage: delmembers [OPTIONS]\n' - 'Try \'delmembers --help\' for help.\n\n' -- 'Error: Invalid value for \'--file\' / \'-f\': Could not open ' -- 'file: bad: No such file or directory\n') -+ 'Error: Invalid value for \'--file\' / \'-f\': ' -+ '\'bad\': No such file or directory\n') - - def test_not_subscribed_without_display_name(self): - with NamedTemporaryFile('w', buffering=1, encoding='utf-8') as infp: -diff --git a/src/mailman/commands/tests/test_cli_syncmembers.py b/src/mailman/commands/tests/test_cli_syncmembers.py -index 658b867..faed507 100644 ---- a/src/mailman/commands/tests/test_cli_syncmembers.py -+++ b/src/mailman/commands/tests/test_cli_syncmembers.py -@@ -58,8 +58,8 @@ class TestCLISyncMembers(unittest.TestCase): - result.output, - 'Usage: syncmembers [OPTIONS] FILENAME LISTSPEC\n' - 'Try \'syncmembers --help\' for help.\n\n' -- 'Error: Invalid value for \'FILENAME\': Could not open ' -- 'file: bad: No such file or directory\n') -+ 'Error: Invalid value for \'FILENAME\': ' -+ '\'bad\': No such file or directory\n') - - def test_sync_invalid_email(self): - with NamedTemporaryFile('w', buffering=1, encoding='utf-8') as infp: -@@ -374,8 +374,8 @@ class TestCLISyncMembers(unittest.TestCase): - 'Usage: syncmembers [OPTIONS] FILENAME LISTSPEC\n' - 'Try \'syncmembers --help\' for help.\n\n' - 'Error: Invalid value for \'--delivery\' / \'-d\': ' -- 'invalid choice: bogus. (choose from regular, mime, ' -- 'plain, summary, disabled)\n') -+ '\'bogus\' is not one of \'regular\', \'mime\', ' -+ '\'plain\', \'summary\', \'disabled\'.\n') - - def test_override_no_welcome(self): - self._mlist.send_welcome_message = False --- -2.32.0 - diff --git a/mailman3-do-not-assume-sapce-in-banner.patch b/mailman3-do-not-assume-sapce-in-banner.patch deleted file mode 100644 index 95c42d5f92d5f25ecbb07a43a39d8a934285644c..0000000000000000000000000000000000000000 --- a/mailman3-do-not-assume-sapce-in-banner.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/src/mailman/utilities/tests/test_interact.py b/src/mailman/utilities/tests/test_interact.py -index 24c186c..dca1866 100644 ---- a/src/mailman/utilities/tests/test_interact.py -+++ b/src/mailman/utilities/tests/test_interact.py -@@ -67,7 +67,7 @@ class TestInteract(unittest.TestCase): - self._enter(hackenv('PYTHONSTARTUP', None)) - interact() - stderr = self._stderr.getvalue().splitlines() -- banner = 'Python {} on {} '.format(sys.version, sys.platform) -+ banner = 'Python {} on {}'.format(sys.version, sys.platform) - self.assertEqual(stderr[0], banner.splitlines()[0]) - - def test_interact_custom_banner(self): diff --git a/mailman3-test_as_string_python_bug_27321.patch b/mailman3-test_as_string_python_bug_27321.patch deleted file mode 100644 index b6a58629e1de9cfa52d1a34aa7d785c412537a18..0000000000000000000000000000000000000000 --- a/mailman3-test_as_string_python_bug_27321.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 70373ea11495164fcdf7a61b754b6ab94872ace4 Mon Sep 17 00:00:00 2001 -From: Mark Sapiro -Date: Fri, 5 Feb 2021 20:29:42 -0800 -Subject: [PATCH] Skip test_as_string_python_bug_27321 for Python versions - where fixed. - ---- - src/mailman/email/tests/test_message.py | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/src/mailman/email/tests/test_message.py b/src/mailman/email/tests/test_message.py -index 098042ea7..050861c91 100644 ---- a/src/mailman/email/tests/test_message.py -+++ b/src/mailman/email/tests/test_message.py -@@ -17,6 +17,7 @@ - - """Test the message API.""" - -+import sys - import unittest - - from email import message_from_binary_file -@@ -107,6 +108,10 @@ Test content - self.assertEqual(msg.get_payload(), 'Non-ascii text ?.') - - def test_as_string_python_bug_27321(self): -+ # Bug 27321 is fixed in Python 3.8.7rc1, 3.9.1rc1 and later. -+ if (sys.version_info.minor == 8 and sys.hexversion >= 0x030807C1 or -+ sys.hexversion >= 0x030901C1): -+ raise unittest.SkipTest - with path('mailman.email.tests.data', 'bad_email.eml') as email_path: - with open(str(email_path), 'rb') as fp: - msg = message_from_binary_file(fp, Message) --- -GitLab diff --git a/support-sqlalchemy-1-4.patch b/support-sqlalchemy-1-4.patch deleted file mode 100644 index 2c7c08fdb89792dfb6f106edbaf0e2a40e6bb042..0000000000000000000000000000000000000000 --- a/support-sqlalchemy-1-4.patch +++ /dev/null @@ -1,47 +0,0 @@ -diff --git a/src/mailman/database/types.py b/src/mailman/database/types.py -index 1913a0a..4e97bf6 100644 ---- a/src/mailman/database/types.py -+++ b/src/mailman/database/types.py -@@ -34,6 +34,7 @@ class Enum(TypeDecorator): - converts it on-the-fly. - """ - impl = Integer -+ cache_ok = False - - def __init__(self, enum, *args, **kw): - super().__init__(*args, **kw) -@@ -59,6 +60,7 @@ class UUID(TypeDecorator): - - """ - impl = CHAR -+ cache_ok = False - - def load_dialect_impl(self, dialect): - if dialect.name == 'postgresql': -@@ -93,6 +95,7 @@ class SAUnicode(TypeDecorator): - type and it can still be used if needed in the codebase. - """ - impl = Unicode -+ cache_ok = False - - - @compiles(SAUnicode) -@@ -113,6 +116,7 @@ class SAUnicodeLarge(TypeDecorator): - This is double size of SAUnicode defined above. - """ - impl = Unicode -+ cache_ok = False - - - @compiles(SAUnicodeLarge, 'mysql') -@@ -139,6 +143,7 @@ class SAUnicodeXL(TypeDecorator): - See https://docs.sqlalchemy.org/en/latest/dialects/mysql.html#index-length - """ - impl = Unicode -+ cache_ok = False - - - @compiles(SAUnicodeXL, 'mysql') --- -2.27.0 -