diff options
Diffstat (limited to 'src/mailman/bin/list_members.py')
| -rw-r--r-- | src/mailman/bin/list_members.py | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/src/mailman/bin/list_members.py b/src/mailman/bin/list_members.py new file mode 100644 index 000000000..443f764d6 --- /dev/null +++ b/src/mailman/bin/list_members.py @@ -0,0 +1,201 @@ +# Copyright (C) 1998-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 sys + +from email.Utils import formataddr + +from mailman import Utils +from mailman.config import config +from mailman.core import errors +from mailman.i18n import _ +from mailman.interfaces import DeliveryStatus +from mailman.options import SingleMailingListOptions + + +COMMASPACE = ', ' + +WHYCHOICES = { + 'enabled' : DeliveryStatus.enabled, + 'byuser' : DeliveryStatus.by_user, + 'byadmin' : DeliveryStatus.by_moderator, + 'bybounce': DeliveryStatus.by_bounces, + } + +KINDCHOICES = set(('mime', 'plain', 'any')) + + + +class ScriptOptions(SingleMailingListOptions): + usage = _("""\ +%prog [options] + +List all the members of a mailing list. Note that with the options below, if +neither -r or -d is supplied, regular members are printed first, followed by +digest members, but no indication is given as to address status. + +listname is the name of the mailing list to use.""") + + def add_options(self): + super(ScriptOptions, self).add_options() + self.parser.add_option( + '-o', '--output', + type='string', help=_("""\ +Write output to specified file instead of standard out.""")) + self.parser.add_option( + '-r', '--regular', + default=None, action='store_true', + help=_('Print just the regular (non-digest) members.')) + self.parser.add_option( + '-d', '--digest', + default=None, type='string', metavar='KIND', + help=_("""\ +Print just the digest members. KIND can be 'mime', 'plain', or +'any'. 'mime' prints just the members receiving MIME digests, while 'plain' +prints just the members receiving plain text digests. 'any' prints all +members receiving any kind of digest.""")) + self.parser.add_option( + '-n', '--nomail', + type='string', metavar='WHY', help=_("""\ +Print the members that have delivery disabled. WHY selects just the subset of +members with delivery disabled for a particular reason, where 'any' prints all +disabled members. 'byadmin', 'byuser', 'bybounce', and 'unknown' prints just +the users who are disabled for that particular reason. WHY can also be +'enabled' which prints just those members for whom delivery is enabled.""")) + self.parser.add_option( + '-f', '--fullnames', + default=False, action='store_true', + help=_('Include the full names in the output')) + self.parser.add_option( + '-i', '--invalid', + default=False, action='store_true', help=_("""\ +Print only the addresses in the membership list that are invalid. Ignores -r, +-d, -n.""")) + + def sanity_check(self): + if not self.options.listname: + self.parser.error(_('Missing listname')) + if len(self.arguments) > 0: + self.parser.print_error(_('Unexpected arguments')) + if self.options.digest is not None: + self.options.kind = self.options.digest.lower() + if self.options.kind not in KINDCHOICES: + self.parser.error( + _('Invalid value for -d: $self.options.digest')) + if self.options.nomail is not None: + why = self.options.nomail.lower() + if why == 'any': + self.options.why = 'any' + elif why not in WHYCHOICES: + self.parser.error( + _('Invalid value for -n: $self.options.nomail')) + self.options.why = why + if self.options.regular is None and self.options.digest is None: + self.options.regular = self.options.digest = True + self.options.kind = 'any' + + + +def safe(string): + if not string: + return '' + return string.encode(sys.getdefaultencoding(), 'replace') + + +def isinvalid(addr): + try: + Utils.ValidateEmail(addr) + return False + except errors.EmailAddressError: + return True + + + +def whymatches(mlist, addr, why): + # Return true if the `why' matches the reason the address is enabled, or + # in the case of why is None, that they are disabled for any reason + # (i.e. not enabled). + status = mlist.getDeliveryStatus(addr) + if why in (None, 'any'): + return status <> DeliveryStatus.enabled + return status == WHYCHOICES[why] + + + +def main(): + options = ScriptOptions() + options.initialize() + + fqdn_listname = options.options.listname + if options.options.output: + try: + fp = open(options.output, 'w') + except IOError: + options.parser.error( + _('Could not open file for writing: $options.options.output')) + else: + fp = sys.stdout + + mlist = config.db.list_manager.get(fqdn_listname) + if mlist is None: + options.parser.error(_('No such list: $fqdn_listname')) + + # The regular delivery and digest members. + rmembers = set(mlist.regular_members.members) + dmembers = set(mlist.digest_members.members) + + fullnames = options.options.fullnames + if options.options.invalid: + all = sorted(member.address.address for member in rmembers + dmembers) + for address in all: + user = config.db.user_manager.get_user(address) + name = (user.real_name if fullnames and user else u'') + if options.options.invalid and isinvalid(address): + print >> fp, formataddr((safe(name), address)) + return + if options.options.regular: + for address in sorted(member.address.address for member in rmembers): + user = config.db.user_manager.get_user(address) + name = (user.real_name if fullnames and user else u'') + # Filter out nomails + if (options.options.nomail and + not whymatches(mlist, address, options.options.why)): + continue + print >> fp, formataddr((safe(name), address)) + if options.options.digest: + for address in sorted(member.address.address for member in dmembers): + user = config.db.user_manager.get_user(address) + name = (user.real_name if fullnames and user else u'') + # Filter out nomails + if (options.options.nomail and + not whymatches(mlist, address, options.options.why)): + continue + # Filter out digest kinds +## if mlist.getMemberOption(addr, config.DisableMime): +## # They're getting plain text digests +## if opts.kind == 'mime': +## continue +## else: +## # They're getting MIME digests +## if opts.kind == 'plain': +## continue + print >> fp, formataddr((safe(name), address)) + + + +if __name__ == '__main__': + main() |
