cli_members.py 3.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
# 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/>.

"""The 'members' subcommand."""

from __future__ import absolute_import, unicode_literals

__metaclass__ = type
__all__ = [
    'Members',
    ]


28 29 30 31
import sys
import codecs

from email.utils import parseaddr
32
from zope.component import getUtility
33 34
from zope.interface import implements

35 36
from mailman.app.membership import add_member
from mailman.config import config
37
from mailman.core.i18n import _
38
from mailman.interfaces.command import ICLISubCommand
Barry Warsaw's avatar
Barry Warsaw committed
39
from mailman.interfaces.listmanager import IListManager
40
from mailman.interfaces.member import AlreadySubscribedError, DeliveryMode
41 42 43 44 45 46 47 48 49 50 51 52



class Members:
    """Manage list memberships"""

    implements(ICLISubCommand)

    name = 'members'

    def add(self, parser, command_parser):
        """See `ICLISubCommand`."""
53 54 55
        command_parser.add_argument(
            '-a', '--add',
            dest='filename',
56 57 58 59
            help=_("""\
            Add all member addresses in FILENAME.  FILENAME can be '-' to
            indicate standard input.  Blank lines and lines That start with a
            '#' are ignored."""))
60 61 62 63 64 65 66 67
        # Required positional argument.
        command_parser.add_argument(
            'listname', metavar='LISTNAME', nargs=1,
            help=_("""\
            The 'fully qualified list name', i.e. the posting address of the
            mailing list.  It must be a valid email address and the domain
            must be registered with Mailman.  List names are forced to lower
            case."""))
68 69 70

    def process(self, args):
        """See `ICLISubCommand`."""
71 72 73
        assert len(args.listname) == 1, (
            'Unexpected positional arguments: %s' % args.listname)
        fqdn_listname = args.listname[0]
74
        mlist = getUtility(IListManager).get(fqdn_listname)
75 76 77 78 79 80 81 82
        if mlist is None:
            self.parser.error(_('No such list: $fqdn_listname'))
        if args.filename == '-':
            fp = sys.stdin
        else:
            fp = codecs.open(args.filename, 'r', 'utf-8')
        try:
            for line in fp:
83 84 85
                # Ignore blank lines and lines that start with a '#'.
                if line.startswith('#') or len(line.strip()) == 0:
                    continue
86 87 88 89 90 91
                real_name, email = parseaddr(line)
                # If not given in the input data, parseaddr() will return the
                # empty string, as opposed to the empty unicode.  We need a
                # unicode real name here.
                if real_name == '':
                    real_name = u''
92 93 94 95 96 97 98 99
                try:
                    add_member(mlist, email, real_name, None,
                               DeliveryMode.regular,
                               mlist.preferred_language.code)
                except AlreadySubscribedError:
                    # It's okay if the address is already subscribed, just
                    # print a warning and continue.
                    print 'Already subscribed (skipping):', email, real_name
100 101 102 103
        finally:
            if fp is not sys.stdin:
                fp.close()
        config.db.commit()