diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/mailman/bin/bumpdigests.py | 74 | ||||
| -rw-r--r-- | src/mailman/bin/checkdbs.py | 209 | ||||
| -rw-r--r-- | src/mailman/bin/config_list.py | 332 | ||||
| -rw-r--r-- | src/mailman/bin/disabled.py | 201 | ||||
| -rw-r--r-- | src/mailman/bin/export.py | 310 | ||||
| -rw-r--r-- | src/mailman/bin/find_member.py | 135 | ||||
| -rw-r--r-- | src/mailman/bin/gate_news.py | 244 | ||||
| -rw-r--r-- | src/mailman/bin/list_owners.py | 90 | ||||
| -rw-r--r-- | src/mailman/bin/senddigests.py | 83 | ||||
| -rw-r--r-- | src/mailman/bin/show_config.py | 97 |
10 files changed, 0 insertions, 1775 deletions
diff --git a/src/mailman/bin/bumpdigests.py b/src/mailman/bin/bumpdigests.py deleted file mode 100644 index f30772ca8..000000000 --- a/src/mailman/bin/bumpdigests.py +++ /dev/null @@ -1,74 +0,0 @@ -# Copyright (C) 1998-2015 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 -import optparse - -from mailman import errors -from mailman import MailList -from mailman.configuration import config -from mailman.core.i18n import _ -from mailman.version import MAILMAN_VERSION - -# Work around known problems with some RedHat cron daemons -import signal -signal.signal(signal.SIGCHLD, signal.SIG_DFL) - - - -def parseargs(): - parser = optparse.OptionParser(version=MAILMAN_VERSION, - usage=_("""\ -%prog [options] [listname ...] - -Increment the digest volume number and reset the digest number to one. All -the lists named on the command line are bumped. If no list names are given, -all lists are bumped.""")) - parser.add_option('-C', '--config', - help=_('Alternative configuration file to use')) - opts, args = parser.parse_args() - return opts, args, parser - - - -def main(): - opts, args, parser = parseargs() - config.load(opts.config) - - listnames = set(args or config.list_manager.names) - if not listnames: - print(_('Nothing to do.')) - sys.exit(0) - - for listname in listnames: - try: - # Be sure the list is locked - mlist = MailList.MailList(listname) - except errors.MMListError: - parser.print_help() - print(_('No such list: $listname'), file=sys.stderr) - sys.exit(1) - try: - mlist.bump_digest_volume() - finally: - mlist.Save() - mlist.Unlock() - - - -if __name__ == '__main__': - main() diff --git a/src/mailman/bin/checkdbs.py b/src/mailman/bin/checkdbs.py deleted file mode 100644 index 61aa6b6f1..000000000 --- a/src/mailman/bin/checkdbs.py +++ /dev/null @@ -1,209 +0,0 @@ -# Copyright (C) 1998-2015 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 -import time -import optparse - -from email.Charset import Charset - -from mailman import MailList -from mailman import Utils -from mailman.app.requests import handle_request -from mailman.configuration import config -from mailman.core.i18n import _ -from mailman.email.message import UserNotification -from mailman.initialize import initialize -from mailman.interfaces.requests import IListRequests, RequestType -from mailman.version import MAILMAN_VERSION - -# Work around known problems with some RedHat cron daemons -import signal -signal.signal(signal.SIGCHLD, signal.SIG_DFL) - -NL = u'\n' -now = time.time() - - - -def parseargs(): - parser = optparse.OptionParser(version=MAILMAN_VERSION, - usage=_("""\ -%prog [options] - -Check for pending admin requests and mail the list owners if necessary.""")) - parser.add_option('-C', '--config', - help=_('Alternative configuration file to use')) - opts, args = parser.parse_args() - if args: - parser.print_help() - print(_('Unexpected arguments'), file=sys.stderr) - sys.exit(1) - return opts, args, parser - - - -def pending_requests(mlist): - # Must return a byte string - lcset = mlist.preferred_language.charset - pending = [] - first = True - requestsdb = IListRequests(mlist) - for request in requestsdb.of_type(RequestType.subscription): - if first: - pending.append(_('Pending subscriptions:')) - first = False - key, data = requestsdb.get_request(request.id) - when = data['when'] - addr = data['addr'] - fullname = data['fullname'] - passwd = data['passwd'] - digest = data['digest'] - lang = data['lang'] - if fullname: - if isinstance(fullname, unicode): - fullname = fullname.encode(lcset, 'replace') - fullname = ' (%s)' % fullname - pending.append(' %s%s %s' % (addr, fullname, time.ctime(when))) - first = True - for request in requestsdb.of_type(RequestType.held_message): - if first: - pending.append(_('\nPending posts:')) - first = False - key, data = requestsdb.get_request(request.id) - when = data['when'] - sender = data['sender'] - subject = data['subject'] - reason = data['reason'] - text = data['text'] - msgdata = data['msgdata'] - subject = Utils.oneline(subject, lcset) - date = time.ctime(when) - reason = _(reason) - pending.append(_("""\ -From: $sender on $date -Subject: $subject -Cause: $reason""")) - pending.append('') - # Coerce all items in pending to a Unicode so we can join them - upending = [] - charset = mlist.preferred_language.charset - for s in pending: - if isinstance(s, unicode): - upending.append(s) - else: - upending.append(unicode(s, charset, 'replace')) - # Make sure that the text we return from here can be encoded to a byte - # string in the charset of the list's language. This could fail if for - # example, the request was pended while the list's language was French, - # but then it was changed to English before checkdbs ran. - text = NL.join(upending) - charset = Charset(mlist.preferred_language.charset) - incodec = charset.input_codec or 'ascii' - outcodec = charset.output_codec or 'ascii' - if isinstance(text, unicode): - return text.encode(outcodec, 'replace') - # Be sure this is a byte string encodeable in the list's charset - utext = unicode(text, incodec, 'replace') - return utext.encode(outcodec, 'replace') - - - -def auto_discard(mlist): - # Discard old held messages - discard_count = 0 - expire = config.days(mlist.max_days_to_hold) - requestsdb = IListRequests(mlist) - heldmsgs = list(requestsdb.of_type(RequestType.held_message)) - if expire and heldmsgs: - for request in heldmsgs: - key, data = requestsdb.get_request(request.id) - if now - data['date'] > expire: - handle_request(mlist, request.id, config.DISCARD) - discard_count += 1 - mlist.Save() - return discard_count - - - -# Figure out epoch seconds of midnight at the start of today (or the given -# 3-tuple date of (year, month, day). -def midnight(date=None): - if date is None: - date = time.localtime()[:3] - # -1 for dst flag tells the library to figure it out - return time.mktime(date + (0,)*5 + (-1,)) - - -def main(): - opts, args, parser = parseargs() - initialize(opts.config) - - for name in config.list_manager.names: - # The list must be locked in order to open the requests database - mlist = MailList.MailList(name) - try: - count = IListRequests(mlist).count - # While we're at it, let's evict yesterday's autoresponse data - midnight_today = midnight() - evictions = [] - for sender in mlist.hold_and_cmd_autoresponses.keys(): - date, respcount = mlist.hold_and_cmd_autoresponses[sender] - if midnight(date) < midnight_today: - evictions.append(sender) - if evictions: - for sender in evictions: - del mlist.hold_and_cmd_autoresponses[sender] - # This is the only place we've changed the list's database - mlist.Save() - if count: - # Set the default language the the list's preferred language. - _.default = mlist.preferred_language - realname = mlist.real_name - discarded = auto_discard(mlist) - if discarded: - count = count - discarded - text = _('Notice: $discarded old request(s) ' - 'automatically expired.\n\n') - else: - text = '' - if count: - text += Utils.maketext( - 'checkdbs.txt', - {'count' : count, - 'mail_host': mlist.mail_host, - 'adminDB' : mlist.GetScriptURL('admindb', - absolute=1), - 'real_name': realname, - }, mlist=mlist) - text += '\n' + pending_requests(mlist) - subject = _('$count $realname moderator ' - 'request(s) waiting') - else: - subject = _('$realname moderator request check result') - msg = UserNotification(mlist.GetOwnerEmail(), - mlist.GetBouncesEmail(), - subject, text, - mlist.preferred_language) - msg.send(mlist, **{'tomoderators': True}) - finally: - mlist.Unlock() - - - -if __name__ == '__main__': - main() diff --git a/src/mailman/bin/config_list.py b/src/mailman/bin/config_list.py deleted file mode 100644 index a0b2a54f4..000000000 --- a/src/mailman/bin/config_list.py +++ /dev/null @@ -1,332 +0,0 @@ -# Copyright (C) 1998-2015 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 re -import sys -import time -import optparse - -from mailman import MailList -from mailman import errors -from mailman.configuration import config -from mailman.core.i18n import _ -from mailman.initialize import initialize -from mailman.utilities.string import wrap -from mailman.version import MAILMAN_VERSION - - -NL = '\n' -nonasciipat = re.compile(r'[\x80-\xff]') - - - -def parseargs(): - parser = optparse.OptionParser(version=MAILMAN_VERSION, - usage=_("""\ -%prog [options] listname - -Configure a list from a text file description, or dump a list's configuration -settings.""")) - parser.add_option('-i', '--inputfile', - metavar='FILENAME', default=None, type='string', - help=_("""\ -Configure the list by assigning each module-global variable in the file to an -attribute on the mailing list object, then save the list. The named file is -loaded with execfile() and must be legal Python code. Any variable that isn't -already an attribute of the list object is ignored (a warning message is -printed). See also the -c option. - -A special variable named 'mlist' is put into the globals during the execfile, -which is bound to the actual MailList object. This lets you do all manner of -bizarre thing to the list object, but BEWARE! Using this can severely (and -possibly irreparably) damage your mailing list! - -The may not be used with the -o option.""")) - parser.add_option('-o', '--outputfile', - metavar='FILENAME', default=None, type='string', - help=_("""\ -Instead of configuring the list, print out a mailing list's configuration -variables in a format suitable for input using this script. In this way, you -can easily capture the configuration settings for a particular list and -imprint those settings on another list. FILENAME is the file to output the -settings to. If FILENAME is `-', standard out is used. - -This may not be used with the -i option.""")) - parser.add_option('-c', '--checkonly', - default=False, action='store_true', help=_("""\ -With this option, the modified list is not actually changed. This is only -useful with the -i option.""")) - parser.add_option('-v', '--verbose', - default=False, action='store_true', help=_("""\ -Print the name of each attribute as it is being changed. This is only useful -with the -i option.""")) - parser.add_option('-C', '--config', - help=_('Alternative configuration file to use')) - opts, args = parser.parse_args() - if len(args) > 1: - parser.print_help() - parser.error(_('Unexpected arguments')) - if not args: - parser.error(_('List name is required')) - return parser, opts, args - - - -def do_output(listname, outfile, parser): - closep = False - try: - if outfile == '-': - outfp = sys.stdout - else: - outfp = open(outfile, 'w') - closep = True - # Open the specified list unlocked, since we're only reading it. - try: - mlist = MailList.MailList(listname, lock=False) - except errors.MMListError: - parser.error(_('No such list: $listname')) - # Preamble for the config info. PEP 263 charset and capture time. - charset = mlist.preferred_language.charset - # Set the system's default language. - _.default = mlist.preferred_language.code - if not charset: - charset = 'us-ascii' - when = time.ctime(time.time()) - print >> outfp, _('''\ -# -*- python -*- -# -*- coding: $charset -*- -## "$listname" mailing list configuration settings -## captured on $when -''') - # Get all the list config info. All this stuff is accessible via the - # web interface. - for k in config.ADMIN_CATEGORIES: - subcats = mlist.GetConfigSubCategories(k) - if subcats is None: - do_list_categories(mlist, k, None, outfp) - else: - for subcat in [t[0] for t in subcats]: - do_list_categories(mlist, k, subcat, outfp) - finally: - if closep: - outfp.close() - - - -def do_list_categories(mlist, k, subcat, outfp): - info = mlist.GetConfigInfo(k, subcat) - label, gui = mlist.GetConfigCategories()[k] - if info is None: - return - charset = mlist.preferred_language.charset - print >> outfp, '##', k.capitalize(), _('options') - print >> outfp, '#' - # First, massage the descripton text, which could have obnoxious - # leading whitespace on second and subsequent lines due to - # triple-quoted string nonsense in the source code. - desc = NL.join([s.lstrip() for s in info[0].splitlines()]) - # Print out the category description - desc = wrap(desc) - for line in desc.splitlines(): - print >> outfp, '#', line - print >> outfp - for data in info[1:]: - if not isinstance(data, tuple): - continue - varname = data[0] - # Variable could be volatile - if varname[0] == '_': - continue - vtype = data[1] - # First, massage the descripton text, which could have - # obnoxious leading whitespace on second and subsequent lines - # due to triple-quoted string nonsense in the source code. - desc = NL.join([s.lstrip() for s in data[-1].splitlines()]) - # Now strip out all HTML tags - desc = re.sub('<.*?>', '', desc) - # And convert </> to <> - desc = re.sub('<', '<', desc) - desc = re.sub('>', '>', desc) - # Print out the variable description. - desc = wrap(desc) - for line in desc.split('\n'): - print >> outfp, '#', line - # munge the value based on its type - value = None - if hasattr(gui, 'getValue'): - value = gui.getValue(mlist, vtype, varname, data[2]) - if value is None and not varname.startswith('_'): - value = getattr(mlist, varname) - if vtype in (config.String, config.Text, config.FileUpload): - print >> outfp, varname, '=', - lines = value.splitlines() - if not lines: - print >> outfp, "''" - elif len(lines) == 1: - if charset != 'us-ascii' and nonasciipat.search(lines[0]): - # This is more readable for non-english list. - print >> outfp, '"' + lines[0].replace('"', '\\"') + '"' - else: - print >> outfp, repr(lines[0]) - else: - if charset == 'us-ascii' and nonasciipat.search(value): - # Normally, an english list should not have non-ascii char. - print >> outfp, repr(NL.join(lines)) - else: - outfp.write(' """') - outfp.write(NL.join(lines).replace('"', '\\"')) - outfp.write('"""\n') - elif vtype in (config.Radio, config.Toggle): - print >> outfp, '#' - print >> outfp, '#', _('legal values are:') - # TBD: This is disgusting, but it's special cased - # everywhere else anyway... - if varname == 'subscribe_policy' and \ - not config.ALLOW_OPEN_SUBSCRIBE: - i = 1 - else: - i = 0 - for choice in data[2]: - print >> outfp, '# ', i, '= "%s"' % choice - i += 1 - print >> outfp, varname, '=', repr(value) - else: - print >> outfp, varname, '=', repr(value) - print >> outfp - - - -def getPropertyMap(mlist): - guibyprop = {} - categories = mlist.GetConfigCategories() - for category, (label, gui) in categories.items(): - if not hasattr(gui, 'GetConfigInfo'): - continue - subcats = mlist.GetConfigSubCategories(category) - if subcats is None: - subcats = [(None, None)] - for subcat, sclabel in subcats: - for element in gui.GetConfigInfo(mlist, category, subcat): - if not isinstance(element, tuple): - continue - propname = element[0] - wtype = element[1] - guibyprop[propname] = (gui, wtype) - return guibyprop - - -class FakeDoc: - # Fake the error reporting API for the htmlformat.Document class - def addError(self, s, tag=None, *args): - if tag: - print >> sys.stderr, tag - print >> sys.stderr, s % args - - def set_language(self, val): - pass - - - -def do_input(listname, infile, checkonly, verbose, parser): - fakedoc = FakeDoc() - # Open the specified list locked, unless checkonly is set - try: - mlist = MailList.MailList(listname, lock=not checkonly) - except errors.MMListError as error: - parser.error(_('No such list "$listname"\n$error')) - savelist = False - guibyprop = getPropertyMap(mlist) - try: - globals = {'mlist': mlist} - # Any exception that occurs in execfile() will cause the list to not - # be saved, but any other problems are not save-fatal. - execfile(infile, globals) - savelist = True - for k, v in globals.items(): - if k in ('mlist', '__builtins__'): - continue - if not hasattr(mlist, k): - print >> sys.stderr, _('attribute "$k" ignored') - continue - if verbose: - print >> sys.stderr, _('attribute "$k" changed') - missing = [] - gui, wtype = guibyprop.get(k, (missing, missing)) - if gui is missing: - # This isn't an official property of the list, but that's - # okay, we'll just restore it the old fashioned way - print >> sys.stderr, _('Non-standard property restored: $k') - setattr(mlist, k, v) - else: - # BAW: This uses non-public methods. This logic taken from - # the guts of GUIBase.handleForm(). - try: - validval = gui._getValidValue(mlist, k, wtype, v) - except ValueError: - print >> sys.stderr, _('Invalid value for property: $k') - except errors.EmailAddressError: - print >> sys.stderr, _( - 'Bad email address for option $k: $v') - else: - # BAW: Horrible hack, but then this is special cased - # everywhere anyway. :( Privacy._setValue() knows that - # when ALLOW_OPEN_SUBSCRIBE is false, the web values are - # 0, 1, 2 but these really should be 1, 2, 3, so it adds - # one. But we really do provide [0..3] so we need to undo - # the hack that _setValue adds. :( :( - if k == 'subscribe_policy' and \ - not config.ALLOW_OPEN_SUBSCRIBE: - validval -= 1 - # BAW: Another horrible hack. This one is just too hard - # to fix in a principled way in Mailman 2.1 - elif k == 'new_member_options': - # Because this is a Checkbox, _getValidValue() - # transforms the value into a list of one item. - validval = validval[0] - validval = [bitfield for bitfield, bitval - in config.OPTINFO.items() - if validval & bitval] - gui._setValue(mlist, k, validval, fakedoc) - # BAW: when to do gui._postValidate()??? - finally: - if savelist and not checkonly: - mlist.Save() - mlist.Unlock() - - - -def main(): - parser, opts, args = parseargs() - initialize(opts.config) - listname = args[0] - - # Sanity check - if opts.inputfile and opts.outputfile: - parser.error(_('Only one of -i or -o is allowed')) - if not opts.inputfile and not opts.outputfile: - parser.error(_('One of -i or -o is required')) - - if opts.outputfile: - do_output(listname, opts.outputfile, parser) - else: - do_input(listname, opts.inputfile, opts.checkonly, - opts.verbose, parser) - - - -if __name__ == '__main__': - main() diff --git a/src/mailman/bin/disabled.py b/src/mailman/bin/disabled.py deleted file mode 100644 index b190556c2..000000000 --- a/src/mailman/bin/disabled.py +++ /dev/null @@ -1,201 +0,0 @@ -# Copyright (C) 2001-2015 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 time -import logging -import optparse - -from mailman import MailList -from mailman import MemberAdaptor -from mailman import Pending -from mailman import loginit -from mailman.Bouncer import _BounceInfo -from mailman.configuration import config -from mailman.core.i18n import _ -from mailman.interfaces.member import NotAMemberError -from mailman.version import MAILMAN_VERSION - - -# Work around known problems with some RedHat cron daemons -import signal -signal.signal(signal.SIGCHLD, signal.SIG_DFL) - -ALL = (MemberAdaptor.BYBOUNCE, - MemberAdaptor.BYADMIN, - MemberAdaptor.BYUSER, - MemberAdaptor.UNKNOWN, - ) - - - -def who_callback(option, opt, value, parser): - dest = getattr(parser.values, option.dest) - if opt in ('-o', '--byadmin'): - dest.add(MemberAdaptor.BYADMIN) - elif opt in ('-m', '--byuser'): - dest.add(MemberAdaptor.BYUSER) - elif opt in ('-u', '--unknown'): - dest.add(MemberAdaptor.UNKNOWN) - elif opt in ('-b', '--notbybounce'): - dest.discard(MemberAdaptor.BYBOUNCE) - elif opt in ('-a', '--all'): - dest.update(ALL) -x5o - -def parseargs(): - parser = optparse.OptionParser(version=MAILMAN_VERSION, - usage=_("""\ -%prog [options] - -Process disabled members, recommended once per day. - -This script iterates through every mailing list looking for members whose -delivery is disabled. If they have been disabled due to bounces, they will -receive another notification, or they may be removed if they've received the -maximum number of notifications. - -Use the --byadmin, --byuser, and --unknown flags to also send notifications to -members whose accounts have been disabled for those reasons. Use --all to -send the notification to all disabled members.""")) - # This is the set of working flags for who to send notifications to. By - # default, we notify anybody who has been disable due to bounces. - parser.set_defaults(who=set([MemberAdaptor.BYBOUNCE])) - parser.add_option('-o', '--byadmin', - callback=who_callback, action='callback', dest='who', - help=_("""\ -Also send notifications to any member disabled by the list -owner/administrator.""")) - parser.add_option('-m', '--byuser', - callback=who_callback, action='callback', dest='who', - help=_("""\ -Also send notifications to any member who has disabled themself.""")) - parser.add_option('-u', '--unknown', - callback=who_callback, action='callback', dest='who', - help=_("""\ -Also send notifications to any member disabled for unknown reasons -(usually a legacy disabled address).""")) - parser.add_option('-b', '--notbybounce', - callback=who_callback, action='callback', dest='who', - help=_("""\ -Don't send notifications to members disabled because of bounces (the -default is to notify bounce disabled members).""")) - parser.add_option('-a', '--all', - callback=who_callback, action='callback', dest='who', - help=_('Send notifications to all disabled members')) - parser.add_option('-f', '--force', - default=False, action='store_true', - help=_("""\ -Send notifications to disabled members even if they're not due a new -notification yet.""")) - parser.add_option('-l', '--listname', - dest='listnames', action='append', default=[], - type='string', help=_("""\ -Process only the given list, otherwise do all lists.""")) - parser.add_option('-C', '--config', - help=_('Alternative configuration file to use')) - opts, args = parser.parse_args() - return opts, args, parser - - - -def main(): - opts, args, parser = parseargs() - config.load(opts.config) - - loginit.initialize(propagate=True) - elog = logging.getLogger('mailman.error') - blog = logging.getLogger('mailman.bounce') - - listnames = set(opts.listnames or config.list_manager.names) - who = tuple(opts.who) - - msg = _('[disabled by periodic sweep and cull, no message available]') - today = time.mktime(time.localtime()[:3] + (0,) * 6) - for listname in listnames: - # List of members to notify - notify = [] - mlist = MailList.MailList(listname) - try: - interval = mlist.bounce_you_are_disabled_warnings_interval - # Find all the members who are currently bouncing and see if - # they've reached the disable threshold but haven't yet been - # disabled. This is a sweep through the membership catching - # situations where they've bounced a bunch, then the list admin - # lowered the threshold, but we haven't (yet) seen more bounces - # from the member. Note: we won't worry about stale information - # or anything else since the normal bounce processing code will - # handle that. - disables = [] - for member in mlist.getBouncingMembers(): - if mlist.getDeliveryStatus(member) <> MemberAdaptor.ENABLED: - continue - info = mlist.getBounceInfo(member) - if info.score >= mlist.bounce_score_threshold: - disables.append((member, info)) - if disables: - for member, info in disables: - mlist.disableBouncingMember(member, info, msg) - # Go through all the members who have delivery disabled, and find - # those that are due to have another notification. If they are - # disabled for another reason than bouncing, and we're processing - # them (because of the command line switch) then they won't have a - # bounce info record. We can piggyback on that for all disable - # purposes. - members = mlist.getDeliveryStatusMembers(who) - for member in members: - info = mlist.getBounceInfo(member) - if not info: - # See if they are bounce disabled, or disabled for some - # other reason. - status = mlist.getDeliveryStatus(member) - if status == MemberAdaptor.BYBOUNCE: - elog.error( - '%s disabled BYBOUNCE lacks bounce info, list: %s', - member, mlist.internal_name()) - continue - info = _BounceInfo( - member, 0, today, - mlist.bounce_you_are_disabled_warnings, - mlist.pend_new(Pending.RE_ENABLE, - mlist.internal_name(), - member)) - mlist.setBounceInfo(member, info) - lastnotice = time.mktime(info.lastnotice + (0,) * 6) - if opts.force or today >= lastnotice + interval: - notify.append(member) - # Now, send notifications to anyone who is due - for member in notify: - blog.info('Notifying disabled member %s for list: %s', - member, mlist.internal_name()) - try: - mlist.sendNextNotification(member) - except NotAMemberError: - # There must have been some problem with the data we have - # on this member. Most likely it's that they don't have a - # password assigned. Log this and delete the member. - blog.info( - 'Cannot send disable notice to non-member: %s', - member) - mlist.ApprovedDeleteMember(member, 'cron/disabled') - mlist.Save() - finally: - mlist.Unlock() - - - -if __name__ == '__main__': - main() diff --git a/src/mailman/bin/export.py b/src/mailman/bin/export.py deleted file mode 100644 index 279abc36f..000000000 --- a/src/mailman/bin/export.py +++ /dev/null @@ -1,310 +0,0 @@ -# Copyright (C) 2006-2015 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/>. - -"""Export an XML representation of a mailing list.""" - -import sys -import codecs -import datetime -import optparse - -from xml.sax.saxutils import escape - -from mailman import Defaults -from mailman import errors -from mailman import MemberAdaptor -from mailman.MailList import MailList -from mailman.configuration import config -from mailman.core.i18n import _ -from mailman.initialize import initialize -from mailman.version import MAILMAN_VERSION - - -SPACE = ' ' - -TYPES = { - Defaults.Toggle : 'bool', - Defaults.Radio : 'radio', - Defaults.String : 'string', - Defaults.Text : 'text', - Defaults.Email : 'email', - Defaults.EmailList : 'email_list', - Defaults.Host : 'host', - Defaults.Number : 'number', - Defaults.FileUpload : 'upload', - Defaults.Select : 'select', - Defaults.Topics : 'topics', - Defaults.Checkbox : 'checkbox', - Defaults.EmailListEx : 'email_list_ex', - Defaults.HeaderFilter : 'header_filter', - } - - - -class Indenter: - def __init__(self, fp, indentwidth=4): - self._fp = fp - self._indent = 0 - self._width = indentwidth - - def indent(self): - self._indent += 1 - - def dedent(self): - self._indent -= 1 - assert self._indent >= 0 - - def write(self, s): - if s <> '\n': - self._fp.write(self._indent * self._width * ' ') - self._fp.write(s) - - - -class XMLDumper(object): - def __init__(self, fp): - self._fp = Indenter(fp) - self._tagbuffer = None - self._stack = [] - - def _makeattrs(self, tagattrs): - # The attribute values might contain angle brackets. They might also - # be None. - attrs = [] - for k, v in tagattrs.items(): - if v is None: - v = '' - else: - v = escape(str(v)) - attrs.append('%s="%s"' % (k, v)) - return SPACE.join(attrs) - - def _flush(self, more=True): - if not self._tagbuffer: - return - name, attributes = self._tagbuffer - self._tagbuffer = None - if attributes: - attrstr = ' ' + self._makeattrs(attributes) - else: - attrstr = '' - if more: - print >> self._fp, '<%s%s>' % (name, attrstr) - self._fp.indent() - self._stack.append(name) - else: - print >> self._fp, '<%s%s/>' % (name, attrstr) - - # Use this method when you know you have sub-elements. - def _push_element(self, _name, **_tagattrs): - self._flush() - self._tagbuffer = (_name, _tagattrs) - - def _pop_element(self, _name): - buffered = bool(self._tagbuffer) - self._flush(more=False) - if not buffered: - name = self._stack.pop() - assert name == _name, 'got: %s, expected: %s' % (_name, name) - self._fp.dedent() - print >> self._fp, '</%s>' % name - - # Use this method when you do not have sub-elements - def _element(self, _name, _value=None, **_attributes): - self._flush() - if _attributes: - attrs = ' ' + self._makeattrs(_attributes) - else: - attrs = '' - if _value is None: - print >> self._fp, '<%s%s/>' % (_name, attrs) - else: - # The value might contain angle brackets. - value = escape(_value.decode('utf-8')) - print >> self._fp, '<%s%s>%s</%s>' % (_name, attrs, value, _name) - - def _do_list_categories(self, mlist, k, subcat=None): - info = mlist.GetConfigInfo(k, subcat) - label, gui = mlist.GetConfigCategories()[k] - if info is None: - return - for data in info[1:]: - if not isinstance(data, tuple): - continue - varname = data[0] - # Variable could be volatile - if varname.startswith('_'): - continue - vtype = data[1] - # Munge the value based on its type - value = None - if hasattr(gui, 'getValue'): - value = gui.getValue(mlist, vtype, varname, data[2]) - if value is None: - value = getattr(mlist, varname) - widget_type = TYPES[vtype] - if isinstance(value, list): - self._push_element('option', name=varname, type=widget_type) - for v in value: - self._element('value', v) - self._pop_element('option') - else: - self._element('option', value, name=varname, type=widget_type) - - def _dump_list(self, mlist): - # Write list configuration values - self._push_element('list', name=mlist.fqdn_listname) - self._push_element('configuration') - self._element('option', - mlist.preferred_language, - name='preferred_language') - for k in config.ADMIN_CATEGORIES: - subcats = mlist.GetConfigSubCategories(k) - if subcats is None: - self._do_list_categories(mlist, k) - else: - for subcat in [t[0] for t in subcats]: - self._do_list_categories(mlist, k, subcat) - self._pop_element('configuration') - # Write membership - self._push_element('roster') - digesters = set(mlist.getDigestMemberKeys()) - for member in sorted(mlist.getMembers()): - attrs = dict(id=member) - cased = mlist.getMemberCPAddress(member) - if cased <> member: - attrs['original'] = cased - self._push_element('member', **attrs) - self._element('realname', mlist.getMemberName(member)) - self._element('password', mlist.getMemberPassword(member)) - self._element('language', mlist.getMemberLanguage(member)) - # Delivery status, combined with the type of delivery - attrs = {} - status = mlist.getDeliveryStatus(member) - if status == MemberAdaptor.ENABLED: - attrs['status'] = 'enabled' - else: - attrs['status'] = 'disabled' - attrs['reason'] = {MemberAdaptor.BYUSER : 'byuser', - MemberAdaptor.BYADMIN : 'byadmin', - MemberAdaptor.BYBOUNCE : 'bybounce', - }.get(mlist.getDeliveryStatus(member), - 'unknown') - if member in digesters: - if mlist.getMemberOption(member, Defaults.DisableMime): - attrs['delivery'] = 'plain' - else: - attrs['delivery'] = 'mime' - else: - attrs['delivery'] = 'regular' - changed = mlist.getDeliveryStatusChangeTime(member) - if changed: - when = datetime.datetime.fromtimestamp(changed) - attrs['changed'] = when.isoformat() - self._element('delivery', **attrs) - for option, flag in Defaults.OPTINFO.items(): - # Digest/Regular delivery flag must be handled separately - if option in ('digest', 'plain'): - continue - value = mlist.getMemberOption(member, flag) - self._element(option, value) - topics = mlist.getMemberTopics(member) - if not topics: - self._element('topics') - else: - self._push_element('topics') - for topic in topics: - self._element('topic', topic) - self._pop_element('topics') - self._pop_element('member') - self._pop_element('roster') - self._pop_element('list') - - def dump(self, listnames): - print >> self._fp, '<?xml version="1.0" encoding="UTF-8"?>' - self._push_element('mailman', **{ - 'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance', - 'xsi:noNamespaceSchemaLocation': 'ssi-1.0.xsd', - }) - for listname in sorted(listnames): - try: - mlist = MailList(listname, lock=False) - except errors.MMUnknownListError: - print >> sys.stderr, _('No such list: $listname') - continue - self._dump_list(mlist) - self._pop_element('mailman') - - def close(self): - while self._stack: - self._pop_element() - - - -def parseargs(): - parser = optparse.OptionParser(version=MAILMAN_VERSION, - usage=_("""\ -%prog [options] - -Export the configuration and members of a mailing list in XML format.""")) - parser.add_option('-o', '--outputfile', - metavar='FILENAME', default=None, type='string', - help=_("""\ -Output XML to FILENAME. If not given, or if FILENAME is '-', standard out is -used.""")) - parser.add_option('-l', '--listname', - default=[], action='append', type='string', - metavar='LISTNAME', dest='listnames', help=_("""\ -The list to include in the output. If not given, then all mailing lists are -included in the XML output. Multiple -l flags may be given.""")) - parser.add_option('-C', '--config', - help=_('Alternative configuration file to use')) - opts, args = parser.parse_args() - if args: - parser.print_help() - parser.error(_('Unexpected arguments')) - return parser, opts, args - - - -def main(): - parser, opts, args = parseargs() - initialize(opts.config) - - close = False - if opts.outputfile in (None, '-'): - writer = codecs.getwriter('utf-8') - fp = writer(sys.stdout) - else: - fp = codecs.open(opts.outputfile, 'w', 'utf-8') - close = True - - try: - dumper = XMLDumper(fp) - if opts.listnames: - listnames = [] - for listname in opts.listnames: - if '@' not in listname: - listname = '%s@%s' % (listname, config.DEFAULT_EMAIL_HOST) - listnames.append(listname) - else: - listnames = config.list_manager.names - dumper.dump(listnames) - dumper.close() - finally: - if close: - fp.close() diff --git a/src/mailman/bin/find_member.py b/src/mailman/bin/find_member.py deleted file mode 100644 index 349af8247..000000000 --- a/src/mailman/bin/find_member.py +++ /dev/null @@ -1,135 +0,0 @@ -# Copyright (C) 1998-2015 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 re -import sys -import optparse - -from mailman import errors -from mailman import MailList -from mailman.configuration import config -from mailman.core.i18n import _ -from mailman.version import MAILMAN_VERSION - - -AS_MEMBER = 0x01 -AS_OWNER = 0x02 - - - -def parseargs(): - parser = optparse.OptionParser(version=MAILMAN_VERSION, - usage=_("""\ -%prog [options] regex [regex ...] - -Find all lists that a member's address is on. - -The interaction between -l and -x (see below) is as follows. If any -l option -is given then only the named list will be included in the search. If any -x -option is given but no -l option is given, then all lists will be search -except those specifically excluded. - -Regular expression syntax uses the Python 're' module. Complete -specifications are at: - -http://www.python.org/doc/current/lib/module-re.html - -Address matches are case-insensitive, but case-preserved addresses are -displayed.""")) - parser.add_option('-l', '--listname', - type='string', default=[], action='append', - dest='listnames', - help=_('Include only the named list in the search')) - parser.add_option('-x', '--exclude', - type='string', default=[], action='append', - dest='excludes', - help=_('Exclude the named list from the search')) - parser.add_option('-w', '--owners', - default=False, action='store_true', - help=_('Search list owners as well as members')) - parser.add_option('-C', '--config', - help=_('Alternative configuration file to use')) - opts, args = parser.parse_args() - if not args: - parser.print_help() - print >> sys.stderr, _('Search regular expression required') - sys.exit(1) - return parser, opts, args - - - -def main(): - parser, opts, args = parseargs() - config.load(opts.config) - - listnames = opts.listnames or config.list_manager.names - includes = set(listname.lower() for listname in listnames) - excludes = set(listname.lower() for listname in opts.excludes) - listnames = includes - excludes - - if not listnames: - print _('No lists to search') - return - - cres = [] - for r in args: - cres.append(re.compile(r, re.IGNORECASE)) - # dictionary of {address, (listname, ownerp)} - matches = {} - for listname in listnames: - try: - mlist = MailList.MailList(listname, lock=False) - except errors.MMListError: - print _('No such list: $listname') - continue - if opts.owners: - owners = mlist.owner - else: - owners = [] - for cre in cres: - for member in mlist.getMembers(): - if cre.search(member): - addr = mlist.getMemberCPAddress(member) - entries = matches.get(addr, {}) - aswhat = entries.get(listname, 0) - aswhat |= AS_MEMBER - entries[listname] = aswhat - matches[addr] = entries - for owner in owners: - if cre.search(owner): - entries = matches.get(owner, {}) - aswhat = entries.get(listname, 0) - aswhat |= AS_OWNER - entries[listname] = aswhat - matches[owner] = entries - addrs = matches.keys() - addrs.sort() - for k in addrs: - hits = matches[k] - lists = hits.keys() - print k, _('found in:') - for name in lists: - aswhat = hits[name] - if aswhat & AS_MEMBER: - print ' ', name - if aswhat & AS_OWNER: - print ' ', name, _('(as owner)') - - - -if __name__ == '__main__': - main() diff --git a/src/mailman/bin/gate_news.py b/src/mailman/bin/gate_news.py deleted file mode 100644 index 72568cd1b..000000000 --- a/src/mailman/bin/gate_news.py +++ /dev/null @@ -1,244 +0,0 @@ -# Copyright (C) 1998-2015 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 -import time -import socket -import logging -import nntplib -import optparse -import email.Errors - -from email.Parser import Parser -from flufl.lock import Lock, TimeOutError -from lazr.config import as_host_port - -from mailman import MailList -from mailman import Message -from mailman import loginit -from mailman.configuration import config -from mailman.core.i18n import _ -from mailman.core.switchboard import Switchboard -from mailman.version import MAILMAN_VERSION - -# Work around known problems with some RedHat cron daemons -import signal -signal.signal(signal.SIGCHLD, signal.SIG_DFL) - -NL = '\n' - -log = None - -class _ContinueLoop(Exception): - pass - - - -def parseargs(): - parser = optparse.OptionParser(version=MAILMAN_VERSION, - usage=_("""\ -%prog [options] - -Poll the NNTP servers for messages to be gatewayed to mailing lists.""")) - parser.add_option('-C', '--config', - help=_('Alternative configuration file to use')) - opts, args = parser.parse_args() - if args: - parser.print_help() - print >> sys.stderr, _('Unexpected arguments') - sys.exit(1) - return opts, args, parser - - - -_hostcache = {} - -def open_newsgroup(mlist): - # Split host:port if given. - nntp_host, nntp_port = as_host_port(mlist.nntp_host, default_port=119) - # Open up a "mode reader" connection to nntp server. This will be shared - # for all the gated lists having the same nntp_host. - conn = _hostcache.get(mlist.nntp_host) - if conn is None: - try: - conn = nntplib.NNTP(nntp_host, nntp_port, - readermode=True, - user=config.NNTP_USERNAME, - password=config.NNTP_PASSWORD) - except (socket.error, nntplib.NNTPError, IOError) as e: - log.error('error opening connection to nntp_host: %s\n%s', - mlist.nntp_host, e) - raise - _hostcache[mlist.nntp_host] = conn - # Get the GROUP information for the list, but we're only really interested - # in the first article number and the last article number - r, c, f, l, n = conn.group(mlist.linked_newsgroup) - return conn, int(f), int(l) - - -def clearcache(): - for conn in set(_hostcache.values()): - conn.quit() - _hostcache.clear() - - - -# This function requires the list to be locked. -def poll_newsgroup(mlist, conn, first, last, glock): - listname = mlist.internal_name() - # NEWNEWS is not portable and has synchronization issues. - for num in range(first, last): - glock.refresh() - try: - headers = conn.head(repr(num))[3] - found_to = False - beenthere = False - for header in headers: - i = header.find(':') - value = header[:i].lower() - if i > 0 and value == 'to': - found_to = True - # FIXME 2010-02-16 barry use List-Post header. - if value <> 'x-beenthere': - continue - if header[i:] == ': %s' % mlist.posting_address: - beenthere = True - break - if not beenthere: - body = conn.body(repr(num))[3] - # Usenet originated messages will not have a Unix envelope - # (i.e. "From " header). This breaks Pipermail archiving, so - # we will synthesize one. Be sure to use the format searched - # for by mailbox.UnixMailbox._isrealfromline(). BAW: We use - # the -bounces address here in case any downstream clients use - # the envelope sender for bounces; I'm not sure about this, - # but it's the closest to the old semantics. - lines = ['From %s %s' % (mlist.GetBouncesEmail(), - time.ctime(time.time()))] - lines.extend(headers) - lines.append('') - lines.extend(body) - lines.append('') - p = Parser(Message.Message) - try: - msg = p.parsestr(NL.join(lines)) - except email.Errors.MessageError as e: - log.error('email package exception for %s:%d\n%s', - mlist.linked_newsgroup, num, e) - raise _ContinueLoop - if found_to: - del msg['X-Originally-To'] - msg['X-Originally-To'] = msg['To'] - del msg['To'] - msg['To'] = mlist.posting_address - # Post the message to the locked list - inq = Switchboard(config.INQUEUE_DIR) - inq.enqueue(msg, - listid=mlist.list_id, - fromusenet=True) - log.info('posted to list %s: %7d', listname, num) - except nntplib.NNTPError as e: - log.exception('NNTP error for list %s: %7d', listname, num) - except _ContinueLoop: - continue - # Even if we don't post the message because it was seen on the - # list already, update the watermark - mlist.usenet_watermark = num - - - -def process_lists(glock): - for listname in config.list_manager.names: - glock.refresh() - # Open the list unlocked just to check to see if it is gating news to - # mail. If not, we're done with the list. Otherwise, lock the list - # and gate the group. - mlist = MailList.MailList(listname, lock=False) - if not mlist.gateway_to_mail: - continue - # Get the list's watermark, i.e. the last article number that we gated - # from news to mail. None means that this list has never polled its - # newsgroup and that we should do a catch up. - watermark = getattr(mlist, 'usenet_watermark', None) - # Open the newsgroup, but let most exceptions percolate up. - try: - conn, first, last = open_newsgroup(mlist) - except (socket.error, nntplib.NNTPError): - break - log.info('%s: [%d..%d]', listname, first, last) - try: - try: - if watermark is None: - mlist.Lock(timeout=config.LIST_LOCK_TIMEOUT) - # This is the first time we've tried to gate this - # newsgroup. We essentially do a mass catch-up, otherwise - # we'd flood the mailing list. - mlist.usenet_watermark = last - log.info('%s caught up to article %d', listname, last) - else: - # The list has been polled previously, so now we simply - # grab all the messages on the newsgroup that have not - # been seen by the mailing list. The first such article - # is the maximum of the lowest article available in the - # newsgroup and the watermark. It's possible that some - # articles have been expired since the last time gate_news - # has run. Not much we can do about that. - start = max(watermark + 1, first) - if start > last: - log.info('nothing new for list %s', listname) - else: - mlist.Lock(timeout=config.LIST_LOCK_TIMEOUT) - log.info('gating %s articles [%d..%d]', - listname, start, last) - # Use last+1 because poll_newsgroup() employes a for - # loop over range, and this will not include the last - # element in the list. - poll_newsgroup(mlist, conn, start, last + 1, glock) - except TimeOutError: - log.error('Could not acquire list lock: %s', listname) - finally: - if mlist.Locked(): - mlist.Save() - mlist.Unlock() - log.info('%s watermark: %d', listname, mlist.usenet_watermark) - - - -def main(): - opts, args, parser = parseargs() - config.load(opts.config) - - GATENEWS_LOCK_FILE = os.path.join(config.LOCK_DIR, 'gate_news.lock') - LOCK_LIFETIME = config.hours(2) - - loginit.initialize(propagate=True) - log = logging.getLogger('mailman.fromusenet') - - try: - with Lock(GATENEWS_LOCK_FILE, - # It's okay to hijack this - lifetime=LOCK_LIFETIME) as lock: - process_lists(lock) - clearcache() - except TimeOutError: - log.error('Could not acquire gate_news lock') - - - -if __name__ == '__main__': - main() diff --git a/src/mailman/bin/list_owners.py b/src/mailman/bin/list_owners.py deleted file mode 100644 index 5b5fca2bf..000000000 --- a/src/mailman/bin/list_owners.py +++ /dev/null @@ -1,90 +0,0 @@ -# Copyright (C) 2002-2015 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 -import optparse - -from zope.component import getUtility - -from mailman.MailList import MailList -from mailman.core.i18n import _ -from mailman.initialize import initialize -from mailman.interfaces.listmanager import IListManager -from mailman.version import MAILMAN_VERSION - - - -def parseargs(): - parser = optparse.OptionParser(version=MAILMAN_VERSION, - usage=_("""\ -%prog [options] [listname ...] - -List the owners of a mailing list, or all mailing lists if no list names are -given.""")) - parser.add_option('-w', '--with-listnames', - default=False, action='store_true', - help=_("""\ -Group the owners by list names and include the list names in the output. -Otherwise, the owners will be sorted and uniquified based on the email -address.""")) - parser.add_option('-m', '--moderators', - default=False, action='store_true', - help=_('Include the list moderators in the output.')) - parser.add_option('-C', '--config', - help=_('Alternative configuration file to use')) - opts, args = parser.parse_args() - return parser, opts, args - - - -def main(): - parser, opts, args = parseargs() - initialize(opts.config) - - list_manager = getUtility(IListManager) - listnames = set(args or list_manager.names) - bylist = {} - - for listname in listnames: - mlist = list_manager.get(listname) - addrs = [addr.address for addr in mlist.owners.addresses] - if opts.moderators: - addrs.extend([addr.address for addr in mlist.moderators.addresses]) - bylist[listname] = addrs - - if opts.with_listnames: - for listname in listnames: - unique = set() - for addr in bylist[listname]: - unique.add(addr) - keys = list(unique) - keys.sort() - print listname - for k in keys: - print '\t', k - else: - unique = set() - for listname in listnames: - for addr in bylist[listname]: - unique.add(addr) - for k in sorted(unique): - print k - - - -if __name__ == '__main__': - main() diff --git a/src/mailman/bin/senddigests.py b/src/mailman/bin/senddigests.py deleted file mode 100644 index 59c03de2d..000000000 --- a/src/mailman/bin/senddigests.py +++ /dev/null @@ -1,83 +0,0 @@ -# Copyright (C) 1998-2015 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 -import optparse - -from mailman import MailList -from mailman.core.i18n import _ -from mailman.initialize import initialize -from mailman.version import MAILMAN_VERSION - -# Work around known problems with some RedHat cron daemons -import signal -signal.signal(signal.SIGCHLD, signal.SIG_DFL) - - - -def parseargs(): - parser = optparse.OptionParser(version=MAILMAN_VERSION, - usage=_("""\ -%prog [options] - -Dispatch digests for lists w/pending messages and digest_send_periodic -set.""")) - parser.add_option('-l', '--listname', - type='string', default=[], action='append', - dest='listnames', help=_("""\ -Send the digest for the given list only, otherwise the digests for all -lists are sent out. Multiple -l options may be given.""")) - parser.add_option('-C', '--config', - help=_('Alternative configuration file to use')) - opts, args = parser.parse_args() - if args: - parser.print_help() - print >> sys.stderr, _('Unexpected arguments') - sys.exit(1) - return opts, args, parser - - - -def main(): - opts, args, parser = parseargs() - initialize(opts.config) - - for listname in set(opts.listnames or config.list_manager.names): - mlist = MailList.MailList(listname, lock=False) - if mlist.digest_send_periodic: - mlist.Lock() - try: - try: - mlist.send_digest_now() - mlist.Save() - # We are unable to predict what exception may occur in digest - # processing and we don't want to lose the other digests, so - # we catch everything. - except Exception as errmsg: - print >> sys.stderr, \ - 'List: %s: problem processing %s:\n%s' % \ - (listname, - os.path.join(mlist.data_path, 'digest.mbox'), - errmsg) - finally: - mlist.Unlock() - - - -if __name__ == '__main__': - main() diff --git a/src/mailman/bin/show_config.py b/src/mailman/bin/show_config.py deleted file mode 100644 index 290840ae3..000000000 --- a/src/mailman/bin/show_config.py +++ /dev/null @@ -1,97 +0,0 @@ -# Copyright (C) 2006-2015 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 re -import sys -import pprint -import optparse - -from mailman.configuration import config -from mailman.core.i18n import _ -from mailman.version import MAILMAN_VERSION - - -# List of names never to show even if --verbose -NEVER_SHOW = ['__builtins__', '__doc__'] - - - -def parseargs(): - parser = optparse.OptionParser(version=MAILMAN_VERSION, - usage=_("""\ -%%prog [options] [pattern ...] - -Show the values of various Defaults.py/mailman.cfg variables. -If one or more patterns are given, show only those variables -whose names match a pattern""")) - parser.add_option('-v', '--verbose', - default=False, action='store_true', - help=_( -"Show all configuration names, not just 'settings'.")) - parser.add_option('-i', '--ignorecase', - default=False, action='store_true', - help=_("Match patterns case-insensitively.")) - parser.add_option('-C', '--config', - help=_('Alternative configuration file to use')) - opts, args = parser.parse_args() - return parser, opts, args - - - -def main(): - parser, opts, args = parseargs() - - patterns = [] - if opts.ignorecase: - flag = re.IGNORECASE - else: - flag = 0 - for pattern in args: - patterns.append(re.compile(pattern, flag)) - - pp = pprint.PrettyPrinter(indent=4) - config.load(opts.config) - names = config.__dict__.keys() - names.sort() - for name in names: - if name in NEVER_SHOW: - continue - if not opts.verbose: - if name.startswith('_') or re.search('[a-z]', name): - continue - if patterns: - hit = False - for pattern in patterns: - if pattern.search(name): - hit = True - break - if not hit: - continue - value = config.__dict__[name] - if isinstance(value, str): - if re.search('\n', value): - print '%s = """%s"""' %(name, value) - else: - print "%s = '%s'" % (name, value) - else: - print '%s = ' % name, - pp.pprint(value) - - - -if __name__ == '__main__': - main() |
