diff options
Diffstat (limited to 'bin/withlist')
-rw-r--r-- | bin/withlist | 275 |
1 files changed, 275 insertions, 0 deletions
diff --git a/bin/withlist b/bin/withlist new file mode 100644 index 00000000..a9bd6361 --- /dev/null +++ b/bin/withlist @@ -0,0 +1,275 @@ +#! @PYTHON@ +# +# Copyright (C) 1998,1999,2000,2001,2002 by the Free Software Foundation, Inc. +# +# This program 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 2 +# of the License, or (at your option) any later version. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +"""General framework for interacting with a mailing list object. + +There are two ways to use this script: interactively or programmatically. +Using it interactively allows you to play with, examine and modify a MailList +object from Python's interactive interpreter. When running interactively, a +MailList object called `m' will be available in the global namespace. It also +loads the class MailList into the global namespace. + +Programmatically, you can write a function to operate on a MailList object, +and this script will take care of the housekeeping (see below for examples). +In that case, the general usage syntax is: + +%% bin/withlist [options] listname [args ...] + +Options: + + -l / --lock + Lock the list when opening. Normally the list is opened unlocked + (e.g. for read-only operations). You can always lock the file after + the fact by typing `m.Lock()' + + Note that if you use this option, you should explicitly call m.Save() + before exiting, since the interpreter's clean up procedure will not + automatically save changes to the MailList object (but it will unlock + the list). + + -i / --interactive + Leaves you at an interactive prompt after all other processing is + complete. This is the default unless the -r option is given. + + --run [module.]callable + -r [module.]callable + This can be used to run a script with the opened MailList object. + This works by attempting to import `module' (which must already be + accessible on your sys.path), and then calling `callable' from the + module. callable can be a class or function; it is called with the + MailList object as the first argument. If additional args are given + on the command line, they are passed as subsequent positional args to + the callable. + + Note that `module.' is optional; if it is omitted then a module with + the name `callable' will be imported. + + The global variable `r' will be set to the results of this call. + + --all / -a + This option only works with the -r option. Use this if you want to + execute the script on all mailing lists. When you use -a you should + not include a listname argument on the command line. The variable `r' + will be a list of all the results. + + --quiet / -q + Suppress all status messages. + + --help / -h + Print this message and exit + + +Here's an example of how to use the -r option. Say you have a file in the +Mailman installation directory called `listaddr.py', with the following +two functions: + +def listaddr(mlist): + print mlist.GetListEmail() + +def requestaddr(mlist): + print mlist.GetRequestEmail() + +Now, from the command line you can print the list's posting address by running +the following from the command line: + +%% bin/withlist -r listaddr mylist +Loading list: mylist (unlocked) +Importing listaddr ... +Running listaddr.listaddr() ... +mylist@myhost.com + +And you can print the list's request address by running: + +%% bin/withlist -r listaddr.requestaddr mylist +Loading list: mylist (unlocked) +Importing listaddr ... +Running listaddr.requestaddr() ... +mylist-request@myhost.com + +As another example, say you wanted to change the password for a particular +user on a particular list. You could put the following function in a file +called `changepw.py': + +from Mailman.Errors import NotAMember + +def changepw(mlist, addr, newpasswd): + try: + mlist.setMemberPassword(addr, newpasswd) + mlist.Save() + except NotAMember: + print 'No address matched:', addr + +and run this from the command line: +%% bin/withlist -l -r changepw mylist somebody@somewhere.org foobar +""" + +import sys +import getopt +import code + +import paths +from Mailman import Utils +from Mailman import MailList +from Mailman import Errors +from Mailman.i18n import _ + +# `m' will be the MailList object and `r' will be the results of the callable +m = None +r = None +VERBOSE = 1 +LOCK = 0 + + + +def usage(code, msg=''): + if code: + fd = sys.stderr + else: + fd = sys.stdout + print >> fd, _(__doc__) + if msg: + print >> fd, msg + sys.exit(code) + + +def atexit(): + """Unlock a locked list, but do not implicitly Save() it. + + This does not get run if the interpreter exits because of a signal, or if + os._exit() is called. It will get called if an exception occurs though. + """ + global m + if not m: + return + if m.Locked(): + if VERBOSE: + listname = m.internal_name() + print >> sys.stderr, _( + 'Unlocking (but not saving) list: %(listname)s') + m.Unlock() + if VERBOSE: + print >> sys.stderr, _('Finalizing') + del m + + + +def do_list(listname, args, func): + global m + # first try to open mailing list + if VERBOSE: + print >> sys.stderr, _('Loading list %(listname)s'), + if LOCK: + print >> sys.stderr, _('(locked)') + else: + print >> sys.stderr, _('(unlocked)') + + try: + m = MailList.MailList(listname, lock=LOCK) + except Errors.MMUnknownListError: + print >> sys.stderr, _('Unknown list: %(listname)s') + m = None + + # try to import the module and run the callable + if func: + return func(m, *args) + return None + + + +def main(): + global VERBOSE + global LOCK + global r + try: + opts, args = getopt.getopt( + sys.argv[1:], 'hlr:qia', + ['help', 'lock', 'run=', 'quiet', 'interactive', 'all']) + except getopt.error, msg: + usage(1, msg) + + run = None + interact = None + all = 0 + for opt, arg in opts: + if opt in ('-h', '--help'): + usage(0) + elif opt in ('-l', '--lock'): + LOCK = 1 + elif opt in ('-r', '--run'): + run = arg + elif opt in ('-q', '--quiet'): + VERBOSE = 0 + elif opt in ('-i', '--interactive'): + interact = 1 + elif opt in ('-a', '--all'): + all = 1 + + if len(args) < 1 and not all: + usage(1, _('No list name supplied.')) + + if all and not run: + usage(1, _('--all requires --run')) + + # The default for interact is 1 unless -r was given + if interact is None: + if run is None: + interact = 1 + else: + interact = 0 + + # try to import the module for the callable + func = None + if run: + i = run.find('.') + if i < 0: + module = run + callable = run + else: + module = run[:i] + callable = run[i+1:] + if VERBOSE: + print >> sys.stderr, _('Importing %(module)s...') + mod = __import__(module) + if VERBOSE: + print >> sys.stderr, _('Running %(module)s.%(callable)s()...') + func = getattr(mod, callable) + + if all: + r = [do_list(listname, args, func) for listname in Utils.list_names()] + else: + listname = args.pop(0).lower().strip() + r = do_list(listname, args, func) + + # Now go to interactive mode, perhaps + if interact: + # Attempt to import the readline module, so we emulate the interactive + # console as closely as possible. Don't worry if it doesn't import. + # readline works by side-effect. + try: + import readline + except ImportError: + pass + namespace = globals().copy() + namespace.update(locals()) + code.InteractiveConsole(namespace).interact( + _("The variable `m' is the %(listname)s MailList instance")) + + + +sys.exitfunc = atexit +main() |