diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/mailman/bin/inject.py | 91 | ||||
| -rw-r--r-- | src/mailman/commands/cli_inject.py | 104 | ||||
| -rw-r--r-- | src/mailman/commands/docs/echo.txt | 1 | ||||
| -rw-r--r-- | src/mailman/commands/docs/end.txt | 1 | ||||
| -rw-r--r-- | src/mailman/commands/docs/inject.txt | 193 | ||||
| -rw-r--r-- | src/mailman/commands/docs/join.txt | 1 | ||||
| -rw-r--r-- | src/mailman/commands/docs/lists.txt | 1 | ||||
| -rw-r--r-- | src/mailman/commands/docs/members.txt | 1 | ||||
| -rw-r--r-- | src/mailman/commands/docs/remove.txt | 3 | ||||
| -rw-r--r-- | src/mailman/database/__init__.py | 2 | ||||
| -rw-r--r-- | src/mailman/database/listmanager.py | 7 | ||||
| -rw-r--r-- | src/mailman/database/mailinglist.py | 3 | ||||
| -rw-r--r-- | src/mailman/docs/listmanager.txt | 15 | ||||
| -rw-r--r-- | src/mailman/queue/docs/incoming.txt | 1 |
14 files changed, 319 insertions, 105 deletions
diff --git a/src/mailman/bin/inject.py b/src/mailman/bin/inject.py deleted file mode 100644 index ebe7584e5..000000000 --- a/src/mailman/bin/inject.py +++ /dev/null @@ -1,91 +0,0 @@ -# Copyright (C) 2002-2009 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/>. - -import os -import sys - -from email import message_from_string -from zope.component import getUtility - -from mailman import Utils -from mailman.configuration import config -from mailman.i18n import _ -from mailman.inject import inject_text -from mailman.interfaces.listmanager import IListManager -from mailman.message import Message -from mailman.options import SingleMailingListOptions - - - -class ScriptOptions(SingleMailingListOptions): - usage=_("""\ -%prog [options] [filename] - -Inject a message from a file into Mailman's incoming queue. 'filename' is the -name of the plaintext message file to inject. If omitted, or the string '-', -standard input is used. -""") - - def add_options(self): - super(ScriptOptions, self).add_options() - self.parser.add_option( - '-q', '--queue', - type='string', help=_("""\ -The name of the queue to inject the message to. The queuename must be one of -the directories inside the qfiles directory. If omitted, the incoming queue -is used.""")) - - def sanity_check(self): - if not self.options.listname: - self.parser.error(_('Missing listname')) - if len(self.arguments) == 0: - self.filename = '-' - elif len(self.arguments) > 1: - self.parser.print_error(_('Unexpected arguments')) - else: - self.filename = self.arguments[0] - - - -def main(): - options = ScriptOptions() - options.initialize() - - if options.options.queue is None: - qdir = config.INQUEUE_DIR - else: - qdir = os.path.join(config.QUEUE_DIR, options.options.queue) - if not os.path.isdir(qdir): - options.parser.error(_('Bad queue directory: $qdir')) - - fqdn_listname = options.options.listname - mlist = getUtility(IListManager).get(fqdn_listname) - if mlist is None: - options.parser.error(_('No such list: $fqdn_listname')) - - if options.filename == '-': - message_text = sys.stdin.read() - else: - with open(options.filename) as fp: - message_text = fp.read() - - inject_text(mlist, message_text, qdir=qdir) - - - -if __name__ == '__main__': - main() diff --git a/src/mailman/commands/cli_inject.py b/src/mailman/commands/cli_inject.py new file mode 100644 index 000000000..d1b1a9795 --- /dev/null +++ b/src/mailman/commands/cli_inject.py @@ -0,0 +1,104 @@ +# Copyright (C) 2009 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/>. + +"""Module stuff.""" + +from __future__ import absolute_import, unicode_literals + +__metaclass__ = type +__all__ = [ + 'Inject', + ] + + +import sys + +from zope.component import getUtility +from zope.interface import implements + +from mailman.config import config +from mailman.i18n import _ +from mailman.inject import inject_text +from mailman.interfaces.command import ICLISubCommand +from mailman.interfaces.listmanager import IListManager + + + +class Inject: + """Inject a message from a file into a mailing list's queue.""" + + implements(ICLISubCommand) + + name = 'inject' + + def add(self, parser, command_parser): + """See `ICLISubCommand`.""" + self.parser = parser + command_parser.add_argument( + '-q', '--queue', + type=unicode, help=_("""\ + The name of the queue to inject the message to. QUEUE must be one + of the directories inside the qfiles directory. If omitted, the + incoming queue is used.""")) + command_parser.add_argument( + '-s', '--show', + action='store_true', default=False, + help=_('Show a list of all available queue names and exit.')) + command_parser.add_argument( + '-f', '--filename', + type='string', help=_(""" + Name of file containing the message to inject. If not given, or + '-' (without the quotes) standard input is used. + """)) + # Required positional argument. + command_parser.add_argument( + 'listname', metavar='LISTNAME', nargs='?', + help=_("""\ + The 'fully qualified list name', i.e. the posting address of the + mailing list to inject the message into.""")) + + def process(self, args): + """See `ICLISubCommand`.""" + # Process --show first; if given, print output and exit, ignoring all + # other command line switches. + if args.show: + print 'Available queues:' + for switchboard in sorted(config.switchboards): + print ' ', switchboard + return + # Could be None or sequence of length 0. + if args.listname is None: + self.parser.error(_('List name is required')) + return + assert len(args.listname) == 1, ( + 'Unexpected positional arguments: %s' % args.listname) + fqdn_listname = args.listname[0] + mlist = getUtility(IListManager).get(fqdn_listname) + if mlist is None: + self.parser.error(_('No such list: $fqdn_listname')) + return + queue = ('in' if args.queue is None else args.queue) + switchboard = config.switchboards.get(queue) + if switchboard is None: + self.parser.error(_('No such queue: $queue')) + return + if args.filename in (None, '-'): + message_text = sys.stdin.read() + else: + with open(args.filename) as fp: + message_text = fp.read() + inject_text(mlist, message_text, switchboard=queue) diff --git a/src/mailman/commands/docs/echo.txt b/src/mailman/commands/docs/echo.txt index 31da2dfcb..99cb25589 100644 --- a/src/mailman/commands/docs/echo.txt +++ b/src/mailman/commands/docs/echo.txt @@ -14,7 +14,6 @@ to the sender. The original message is ignored, but the results receive the echoed command. - >>> from mailman.app.lifecycle import create_list >>> mlist = create_list('test@example.com') >>> from mailman.queue.command import Results diff --git a/src/mailman/commands/docs/end.txt b/src/mailman/commands/docs/end.txt index 8f2c98ec8..a11bea095 100644 --- a/src/mailman/commands/docs/end.txt +++ b/src/mailman/commands/docs/end.txt @@ -18,7 +18,6 @@ The 'end' command takes no arguments. The command itself is fairly simple; it just stops command processing, and the message isn't even looked at. - >>> from mailman.app.lifecycle import create_list >>> mlist = create_list('test@example.com') >>> from mailman.email.message import Message >>> print command.process(mlist, Message(), {}, (), None) diff --git a/src/mailman/commands/docs/inject.txt b/src/mailman/commands/docs/inject.txt new file mode 100644 index 000000000..b254569d3 --- /dev/null +++ b/src/mailman/commands/docs/inject.txt @@ -0,0 +1,193 @@ +============================== +Command line message injection +============================== + +You can inject a message directly into a queue directory via the command +line. + + >>> from mailman.commands.cli_inject import Inject + >>> command = Inject() + + >>> class FakeArgs: + ... queue = None + ... show = False + ... filename = None + ... listname = None + >>> args = FakeArgs() + + >>> class FakeParser: + ... def error(self, message): + ... print message + >>> command.parser = FakeParser() + +It's easy to find out which queues are available. + + >>> args.show = True + >>> command.process(args) + Available queues: + archive + bad + bounces + command + digest + in + lmtp + maildir + news + out + pipeline + rest + retry + shunt + virgin + + >>> args.show = False + +Usually, the text of the message to inject is in a file. + + >>> import os, tempfile + >>> fd, filename = tempfile.mkstemp() + >>> with os.fdopen(fd, 'w') as fp: + ... print >> fp, """\ + ... From: aperson@example.com + ... To: test@example.com + ... Subject: testing + ... + ... This is a test message. + ... """ + +However, the mailing list name is always required. + + >>> args.filename = filename + >>> command.process(args) + List name is required + +Let's provide a list name and try again. + + >>> mlist = create_list('test@example.com') + >>> transaction.commit() + + >>> in_queue = config.switchboards['in'] + >>> len(in_queue.files) + 0 + >>> args.listname = ['test@example.com'] + >>> command.process(args) + +By default, the incoming queue is used. + + >>> len(in_queue.files) + 1 + + >>> from mailman.testing.helpers import get_queue_messages + >>> item = get_queue_messages('in')[0] + >>> print item.msg.as_string() + From: aperson@example.com + To: test@example.com + Subject: testing + Message-ID: ... + Date: ... + <BLANKLINE> + This is a test message. + <BLANKLINE> + <BLANKLINE> + + >>> dump_msgdata(item.msgdata) + _parsemsg : False + listname : test@example.com + original_size: 90 + version : 3 + +But a different queue can be specified on the command line. + + >>> args.queue = 'virgin' + >>> command.process(args) + + >>> len(in_queue.files) + 0 + >>> virgin_queue = config.switchboards['virgin'] + >>> len(virgin_queue.files) + 1 + >>> item = get_queue_messages('virgin')[0] + >>> print item.msg.as_string() + From: aperson@example.com + To: test@example.com + Subject: testing + Message-ID: ... + Date: ... + <BLANKLINE> + This is a test message. + <BLANKLINE> + <BLANKLINE> + + >>> dump_msgdata(item.msgdata) + _parsemsg : False + listname : test@example.com + original_size: 90 + version : 3 + + # Clean up the tempfile. + >>> os.remove(filename) + + +Standard input +============== + +The message text can also be provided on standard input. + + >>> from StringIO import StringIO + + # Remember: we've got unicode literals turned on. + >>> standard_in = StringIO(str("""\ + ... From: bperson@example.com + ... To: test@example.com + ... Subject: another test + ... + ... This is another test message. + ... """)) + + >>> import sys + >>> sys.stdin = standard_in + >>> args.filename = '-' + >>> args.queue = None + + >>> command.process(args) + >>> len(in_queue.files) + 1 + >>> item = get_queue_messages('in')[0] + >>> print item.msg.as_string() + From: bperson@example.com + To: test@example.com + Subject: another test + Message-ID: ... + Date: ... + <BLANKLINE> + This is another test message. + <BLANKLINE> + <BLANKLINE> + + >>> dump_msgdata(item.msgdata) + _parsemsg : False + listname : test@example.com + original_size: 100 + version : 3 + + # Clean up. + >>> sys.stdin = sys.__stdin__ + >>> args.filename = filename + + +Errors +====== + +It is an error to specify a queue that doesn't exist. + + >>> args.queue = 'xxbogusxx' + >>> command.process(args) + No such queue: xxbogusxx + +It is also an error to specify a mailing list that doesn't exist. + + >>> args.queue = None + >>> args.listname = ['bogus'] + >>> command.process(args) + No such list: bogus diff --git a/src/mailman/commands/docs/join.txt b/src/mailman/commands/docs/join.txt index 695750e01..67c84c24c 100644 --- a/src/mailman/commands/docs/join.txt +++ b/src/mailman/commands/docs/join.txt @@ -26,7 +26,6 @@ No address to join ------------------ >>> from mailman.email.message import Message - >>> from mailman.app.lifecycle import create_list >>> from mailman.queue.command import Results >>> mlist = create_list('alpha@example.com') diff --git a/src/mailman/commands/docs/lists.txt b/src/mailman/commands/docs/lists.txt index 6a9bee665..7673ffb03 100644 --- a/src/mailman/commands/docs/lists.txt +++ b/src/mailman/commands/docs/lists.txt @@ -25,7 +25,6 @@ their fully qualified list names, with a description. >>> domain_mgr.add('example.net') <Domain example.net...> - >>> from mailman.app.lifecycle import create_list >>> mlist_1 = create_list('list-one@example.com') >>> mlist_1.description = 'List One' diff --git a/src/mailman/commands/docs/members.txt b/src/mailman/commands/docs/members.txt index c1374277a..9872b9ff0 100644 --- a/src/mailman/commands/docs/members.txt +++ b/src/mailman/commands/docs/members.txt @@ -4,7 +4,6 @@ Adding members You can add members to a mailing list from the command line. - >>> from mailman.app.lifecycle import create_list >>> mlist = create_list('test@example.com') >>> class FakeArgs: diff --git a/src/mailman/commands/docs/remove.txt b/src/mailman/commands/docs/remove.txt index 3f5c59bf4..0158c9b37 100644 --- a/src/mailman/commands/docs/remove.txt +++ b/src/mailman/commands/docs/remove.txt @@ -4,7 +4,6 @@ Command line list removal A system administrator can remove mailing lists by the command line. - >>> from mailman.app.lifecycle import create_list >>> create_list('test@example.com') <mailing list "test@example.com" at ...> @@ -31,7 +30,6 @@ A system administrator can remove mailing lists by the command line. You can also remove lists quietly. - >>> from mailman.app.lifecycle import create_list >>> create_list('test@example.com') <mailing list "test@example.com" at ...> @@ -47,7 +45,6 @@ Removing archives By default 'mailman remove' does not remove a mailing list's archives. - >>> from mailman.app.lifecycle import create_list >>> create_list('test@example.com') <mailing list "test@example.com" at ...> diff --git a/src/mailman/database/__init__.py b/src/mailman/database/__init__.py index 6e1ae46bb..748378ca7 100644 --- a/src/mailman/database/__init__.py +++ b/src/mailman/database/__init__.py @@ -54,7 +54,7 @@ class StockDatabase: def __init__(self): self.url = None - self._store = None + self.store = None def initialize(self, debug=None): """See `IDatabase`.""" diff --git a/src/mailman/database/listmanager.py b/src/mailman/database/listmanager.py index 157f4660c..929f00351 100644 --- a/src/mailman/database/listmanager.py +++ b/src/mailman/database/listmanager.py @@ -30,6 +30,7 @@ import datetime from zope.interface import implements from mailman.config import config +from mailman.core.errors import InvalidEmailAddress from mailman.database.mailinglist import MailingList from mailman.interfaces.listmanager import IListManager, ListAlreadyExistsError from mailman.interfaces.rest import IResolvePathNames @@ -44,7 +45,9 @@ class ListManager: # pylint: disable-msg=R0201 def create(self, fqdn_listname): """See `IListManager`.""" - listname, hostname = fqdn_listname.split('@', 1) + listname, at, hostname = fqdn_listname.partition('@') + if len(hostname) == 0: + raise InvalidEmailAddress(fqdn_listname) mlist = config.db.store.find( MailingList, MailingList.list_name == listname, @@ -58,7 +61,7 @@ class ListManager: def get(self, fqdn_listname): """See `IListManager`.""" - listname, hostname = fqdn_listname.split('@', 1) + listname, at, hostname = fqdn_listname.partition('@') mlist = config.db.store.find(MailingList, list_name=listname, host_name=hostname).one() diff --git a/src/mailman/database/mailinglist.py b/src/mailman/database/mailinglist.py index 5384e9895..447d4657a 100644 --- a/src/mailman/database/mailinglist.py +++ b/src/mailman/database/mailinglist.py @@ -178,7 +178,8 @@ class MailingList(Model): def __init__(self, fqdn_listname): super(MailingList, self).__init__() - listname, hostname = fqdn_listname.split('@', 1) + listname, at, hostname = fqdn_listname.partition('@') + assert hostname, 'Bad list name: {0}'.format(fqdn_listname) self.list_name = listname self.host_name = hostname # For the pending database diff --git a/src/mailman/docs/listmanager.txt b/src/mailman/docs/listmanager.txt index 63530ccda..e8af0d71d 100644 --- a/src/mailman/docs/listmanager.txt +++ b/src/mailman/docs/listmanager.txt @@ -36,11 +36,19 @@ list to the system. If you try to create a mailing list with the same name as an existing list, you will get an exception. - >>> mlist_dup = list_manager.create('_xtest@example.com') + >>> list_manager.create('_xtest@example.com') Traceback (most recent call last): ... ListAlreadyExistsError: _xtest@example.com +It is an error to create a mailing list that isn't a fully qualified list name +(i.e. posting address). + + >>> list_manager.create('foo') + Traceback (most recent call last): + ... + InvalidEmailAddress: foo + Deleting a mailing list ======================= @@ -73,6 +81,11 @@ If you try to get a list that doesn't existing yet, you get None. >>> print list_manager.get('_xtest_2@example.com') None +You also get None if the list name is invalid. + + >>> print list_manager.get('foo') + None + Iterating over all mailing lists ================================ diff --git a/src/mailman/queue/docs/incoming.txt b/src/mailman/queue/docs/incoming.txt index 926b60965..8635f2872 100644 --- a/src/mailman/queue/docs/incoming.txt +++ b/src/mailman/queue/docs/incoming.txt @@ -12,7 +12,6 @@ processing begins, with a global default. This chain is processed with the message eventually ending up in one of the four disposition states described above. - >>> from mailman.app.lifecycle import create_list >>> mlist = create_list('_xtest@example.com') >>> print mlist.start_chain built-in |
