diff options
| author | Barry Warsaw | 2012-02-28 17:19:26 -0500 |
|---|---|---|
| committer | Barry Warsaw | 2012-02-28 17:19:26 -0500 |
| commit | a3337eb1c75e00cf07081cf98a4d1c6fc2478919 (patch) | |
| tree | 3b58e14c80a76d2b2a1326e6ed97ab219e4304c3 | |
| parent | f9e08a392daa5e7e5270a2cab4fce9723a6811b5 (diff) | |
| download | mailman-a3337eb1c75e00cf07081cf98a4d1c6fc2478919.tar.gz mailman-a3337eb1c75e00cf07081cf98a4d1c6fc2478919.tar.zst mailman-a3337eb1c75e00cf07081cf98a4d1c6fc2478919.zip | |
| -rw-r--r-- | src/mailman/runners/command.py | 34 | ||||
| -rw-r--r-- | src/mailman/runners/tests/test_confirm.py | 92 |
2 files changed, 118 insertions, 8 deletions
diff --git a/src/mailman/runners/command.py b/src/mailman/runners/command.py index c6c8900aa..d2731e61b 100644 --- a/src/mailman/runners/command.py +++ b/src/mailman/runners/command.py @@ -113,6 +113,12 @@ class CommandFinder: parts = line.strip().split() if len(parts) == 0: continue + # Ensure that all the parts are unicodes. Since we only accept + # ASCII commands and arguments, ignore anything else. + parts = [(part + if isinstance(part, unicode) + else part.decode('ascii', errors='ignore')) + for part in parts] yield parts @@ -122,13 +128,16 @@ class Results: implements(IEmailResults) - def __init__(self): + def __init__(self, charset='us-ascii'): self._output = StringIO() + self.charset = charset print >> self._output, _("""\ The results of your email command are provided below. """) def write(self, text): + if not isinstance(text, unicode): + text = text.decode(self.charset, errors='ignore') self._output.write(text) def __unicode__(self): @@ -160,7 +169,10 @@ class CommandRunner(Runner): log.info('%s -request message replied and discard', message_id) return False # Now craft the response and process the command lines. - results = Results() + charset = msg.get_param('charset') + if charset is None: + charset = 'us-ascii' + results = Results(charset) # Include just a few key pieces of information from the original: the # sender, date, and message id. print >> results, _('- Original message details:') @@ -174,12 +186,14 @@ class CommandRunner(Runner): print >> results, _('\n- Results:') finder = CommandFinder(msg, msgdata, results) for parts in finder: + command = None # Try to find a command on this line. There may be a Re: prefix # (possibly internationalized) so try with the first and second # words on the line. - command_name = parts.pop(0) - command = config.commands.get(command_name) - if command is None: + if len(parts) > 0: + command_name = parts.pop(0) + command = config.commands.get(command_name) + if command is None and len(parts) > 0: command_name = parts.pop(0) command = config.commands.get(command_name) if command is None: @@ -210,10 +224,14 @@ class CommandRunner(Runner): reply = UserNotification(msg.sender, mlist.bounces_address, _('The results of your email commands'), lang=language) - # Find a charset for the response body. Try ascii first, then - # latin-1 and finally falling back to utf-8. + cte = msg.get('content-transfer-encoding') + if cte is not None: + reply['Content-Transfer-Encoding'] = cte + # Find a charset for the response body. Try the original message's + # charset first, then ascii, then latin-1 and finally falling back to + # utf-8. reply_body = unicode(results) - for charset in ('us-ascii', 'latin-1'): + for charset in (results.charset, 'us-ascii', 'latin-1'): try: reply_body.encode(charset) break diff --git a/src/mailman/runners/tests/test_confirm.py b/src/mailman/runners/tests/test_confirm.py index 3e26bf542..94a630a42 100644 --- a/src/mailman/runners/tests/test_confirm.py +++ b/src/mailman/runners/tests/test_confirm.py @@ -35,6 +35,7 @@ from mailman.interfaces.registrar import IRegistrar from mailman.interfaces.usermanager import IUserManager from mailman.runners.command import CommandRunner from mailman.testing.helpers import ( + get_queue_messages, make_testable_runner, specialized_message_from_string as mfs) from mailman.testing.layers import ConfigLayer @@ -94,3 +95,94 @@ To: test-confirm@example.com self.assertEqual(address.verified_on, datetime(2005, 8, 1, 7, 49, 23)) address = manager.get_address('anne@example.org') self.assertEqual(address.email, 'anne@example.org') + + def test_confirm_with_utf8_body(self): + # Clear out the virgin queue so that the test below only sees the + # reply to the confirmation message. + get_queue_messages('virgin') + subject = 'Re: confirm {0}'.format(self._token) + to = 'test-confirm+{0}@example.com'.format(self._token) + msg = mfs("""\ +From: Anne Person <anne@example.org +MIME-Version: 1.0 +Content-Type: text/plain; charset=utf-8 +Content-Disposition: inline +Content-Transfer-Encoding: quoted-printable + +* test-confirm+90bf6ef335d92cfbbe540a5c9ebfecb107a48e48@example.com <= +test-confirm+90bf6ef335d92cfbbe540a5c9ebfecb107a48e48@example.com>: +> Email Address Registration Confirmation +>=20 +> Hello, this is the GNU Mailman server at example.com. +>=20 +> We have received a registration request for the email address +>=20 +> anne@example.org +>=20 +> Before you can start using GNU Mailman at this site, you must first con= +firm +> that this is your email address. You can do this by replying to this m= +essage, +> keeping the Subject header intact. Or you can visit this web page +>=20 +> http://example.com/confirm/90bf6ef335d92cfbbe540a5c9ebfecb107a48e48 +>=20 +> If you do not wish to register this email address simply disregard this +> message. If you think you are being maliciously subscribed to the list= +, or +> have any other questions, you may contact +>=20 +> postmaster@example.com + +--=20 + +Franziskanerstra=C3=9Fe +""") + msg['Subject'] = subject + msg['To'] = to + self._commandq.enqueue(msg, dict(listname='test@example.com')) + self._runner.run() + # Anne is now a confirmed member so her user record and email address + # should exist in the database. + manager = getUtility(IUserManager) + user = manager.get_user('anne@example.org') + address = list(user.addresses)[0] + self.assertEqual(address.email, 'anne@example.org') + self.assertEqual(address.verified_on, datetime(2005, 8, 1, 7, 49, 23)) + address = manager.get_address('anne@example.org') + self.assertEqual(address.email, 'anne@example.org') + messages = get_queue_messages('virgin') + self.assertEqual(len(messages), 1) + self.assertEqual(messages[0].msgdata['recipients'], + set(['anne@example.org'])) + + def test_confirm_with_no_command_in_utf8_body(self): + get_queue_messages('virgin') + subject = 'Re: confirm {0}'.format(self._token) + to = 'test-confirm+{0}@example.com'.format(self._token) + msg = mfs("""\ +From: Anne Person <anne@example.org +MIME-Version: 1.0 +Content-Type: text/plain; charset=utf-8 +Content-Disposition: inline +Content-Transfer-Encoding: quoted-printable + +Franziskanerstra=C3=9Fe +""") + msg['Subject'] = subject + msg['To'] = to + self._commandq.enqueue(msg, dict(listname='test@example.com')) + self._runner.run() + # Anne is now a confirmed member so her user record and email address + # should exist in the database. + manager = getUtility(IUserManager) + user = manager.get_user('anne@example.org') + address = list(user.addresses)[0] + self.assertEqual(address.email, 'anne@example.org') + self.assertEqual(address.verified_on, datetime(2005, 8, 1, 7, 49, 23)) + address = manager.get_address('anne@example.org') + self.assertEqual(address.email, 'anne@example.org') + messages = get_queue_messages('virgin') + self.assertEqual(len(messages), 1) + self.assertEqual(messages[0].msgdata['recipients'], + set(['anne@example.org'])) |
