diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/mailman/app/registrar.py | 5 | ||||
| -rw-r--r-- | src/mailman/core/runner.py | 4 | ||||
| -rw-r--r-- | src/mailman/docs/NEWS.rst | 2 | ||||
| -rw-r--r-- | src/mailman/runners/command.py | 30 | ||||
| -rw-r--r-- | src/mailman/runners/tests/test_confirm.py | 96 |
5 files changed, 120 insertions, 17 deletions
diff --git a/src/mailman/app/registrar.py b/src/mailman/app/registrar.py index e1d804167..a7c9dbb1b 100644 --- a/src/mailman/app/registrar.py +++ b/src/mailman/app/registrar.py @@ -25,8 +25,6 @@ __all__ = [ ] -import datetime - from pkg_resources import resource_string from zope.component import getUtility from zope.interface import implements @@ -39,6 +37,7 @@ from mailman.interfaces.member import MemberRole from mailman.interfaces.pending import IPendable, IPendings from mailman.interfaces.registrar import IRegistrar from mailman.interfaces.usermanager import IUserManager +from mailman.utilities.datetime import now @@ -131,7 +130,7 @@ class Registrar: # The IAddress and linked IUser already exist, so all we need to # do is verify the address. pass - address.verified_on = datetime.datetime.now() + address.verified_on = now() # If this registration is tied to a mailing list, subscribe the person # to the list right now. list_name = pendable.get('list_name') diff --git a/src/mailman/core/runner.py b/src/mailman/core/runner.py index 30189600d..e86741c41 100644 --- a/src/mailman/core/runner.py +++ b/src/mailman/core/runner.py @@ -169,12 +169,12 @@ class Runner: # Other work we want to do each time through the loop. dlog.debug('[%s] doing periodic', me) self._do_periodic() + dlog.debug('[%s] committing transaction', me) + config.db.commit() dlog.debug('[%s] checking short circuit', me) if self._short_circuit(): dlog.debug('[%s] short circuiting', me) break - dlog.debug('[%s] commiting', me) - config.db.commit() dlog.debug('[%s] ending oneloop: %s', me, len(files)) return len(files) diff --git a/src/mailman/docs/NEWS.rst b/src/mailman/docs/NEWS.rst index cdd81d49e..528009ef6 100644 --- a/src/mailman/docs/NEWS.rst +++ b/src/mailman/docs/NEWS.rst @@ -46,6 +46,8 @@ Interfaces Commands -------- * `bin/mailman shell` is an alias for `withlist`. + * The `confirm` email command now properly handles `Re:`-like prefixes, even + if they contain non-ASCII characters. (LP: #685261) Bug fixes --------- diff --git a/src/mailman/runners/command.py b/src/mailman/runners/command.py index 33e320bff..c6c8900aa 100644 --- a/src/mailman/runners/command.py +++ b/src/mailman/runners/command.py @@ -78,9 +78,13 @@ class CommandFinder: # Mail commands must be ASCII. self.command_lines.append(subject.encode('us-ascii')) except (HeaderParseError, UnicodeError, LookupError): - # The Subject header was unparseable or not ASCII, so just ignore - # it. - pass + # The Subject header was unparseable or not ASCII. If the raw + # subject is a unicode object, convert it to ASCII ignoring all + # bogus characters. Otherwise, there's nothing in the subject + # that we can use. + if isinstance(raw_subject, unicode): + safe_subject = raw_subject.encode('us-ascii', errors='ignore') + self.command_lines.append(safe_subject) # Find the first text/plain part of the message. part = None for part in typed_subpart_iterator(msg, 'text', 'plain'): @@ -102,19 +106,14 @@ class CommandFinder: self.ignored_lines.extend(lines[max_lines:]) def __iter__(self): - """Return each command line, split into commands and arguments. - - :return: 2-tuples where the first element is the command and the - second element is a tuple of the arguments. - """ + """Return each command line, split into space separated arguments.""" while self.command_lines: line = self.command_lines.pop(0) self.processed_lines.append(line) parts = line.strip().split() if len(parts) == 0: continue - command = parts.pop(0) - yield command, tuple(parts) + yield parts @@ -174,13 +173,20 @@ class CommandRunner(Runner): print >> results, _(' Message-ID: $message_id') print >> results, _('\n- Results:') finder = CommandFinder(msg, msgdata, results) - for command_name, arguments in finder: + for parts in finder: + # 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: + command_name = parts.pop(0) + command = config.commands.get(command_name) + if command is None: print >> results, _('No such command: $command_name') else: status = command.process( - mlist, msg, msgdata, arguments, results) + mlist, msg, msgdata, parts, results) assert status in ContinueProcessing, ( 'Invalid status: %s' % status) if status == ContinueProcessing.no: diff --git a/src/mailman/runners/tests/test_confirm.py b/src/mailman/runners/tests/test_confirm.py new file mode 100644 index 000000000..3e26bf542 --- /dev/null +++ b/src/mailman/runners/tests/test_confirm.py @@ -0,0 +1,96 @@ +# Copyright (C) 2012 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 `confirm` command.""" + +from __future__ import absolute_import, print_function, unicode_literals + +__metaclass__ = type +__all__ = [ + ] + + +import unittest + +from datetime import datetime +from zope.component import getUtility + +from mailman.app.lifecycle import create_list +from mailman.config import config +from mailman.interfaces.registrar import IRegistrar +from mailman.interfaces.usermanager import IUserManager +from mailman.runners.command import CommandRunner +from mailman.testing.helpers import ( + make_testable_runner, + specialized_message_from_string as mfs) +from mailman.testing.layers import ConfigLayer + + + +class TestConfirm(unittest.TestCase): + """Test confirmations.""" + + layer = ConfigLayer + + def setUp(self): + # Register a subscription requiring confirmation. + registrar = getUtility(IRegistrar) + self._mlist = create_list('test@example.com') + self._token = registrar.register(self._mlist, 'anne@example.org') + self._commandq = config.switchboards['command'] + self._runner = make_testable_runner(CommandRunner, 'command') + config.db.commit() + + def test_confirm_with_re_prefix(self): + subject = 'Re: confirm {0}'.format(self._token) + msg = mfs("""\ +From: anne@example.org +To: test-confirm@example.com + +""") + msg['Subject'] = subject + 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') + + def test_confirm_with_random_ascii_prefix(self): + subject = '\x99AW: confirm {0}'.format(self._token) + msg = mfs("""\ +From: anne@example.org +To: test-confirm@example.com + +""") + msg['Subject'] = subject + 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') |
