summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBarry Warsaw2012-02-28 17:19:26 -0500
committerBarry Warsaw2012-02-28 17:19:26 -0500
commita3337eb1c75e00cf07081cf98a4d1c6fc2478919 (patch)
tree3b58e14c80a76d2b2a1326e6ed97ab219e4304c3
parentf9e08a392daa5e7e5270a2cab4fce9723a6811b5 (diff)
downloadmailman-a3337eb1c75e00cf07081cf98a4d1c6fc2478919.tar.gz
mailman-a3337eb1c75e00cf07081cf98a4d1c6fc2478919.tar.zst
mailman-a3337eb1c75e00cf07081cf98a4d1c6fc2478919.zip
-rw-r--r--src/mailman/runners/command.py34
-rw-r--r--src/mailman/runners/tests/test_confirm.py92
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']))