#! /usr/bin/env python
#
# Copyright (C) 1998,1999,2000,2001 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.  To do this, run the script as
follows:

%% python -i bin/withlist [options] listname [args ...]

This will load the list object named by listname (required) into an object
called `m' 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).

    --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.

    --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':

import string

def changepw(mlist, addr, newpasswd):
    addr = string.lower(addr)
    if mlist.passwords.has_key(addr):
        mlist.passwords[string.lower(addr)] = newpasswd
        mlist.Save()
    else:
        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 string

import paths
from Mailman.Utils import write
from Mailman.MailList import MailList

m = None
r = None



def usage(msg='', code=1):
    write(__doc__ % globals(), file=sys.stderr)
    if msg:
        write(msg, file=sys.stdout)
    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():
        write('Unlocking (but not saving) list:', m.internal_name(),
              file=sys.stderr)
        m.Unlock()
    write('Finalizing', file=sys.stderr)
    del m



def main():
    global m
    global r
    try:
        opts, args = getopt.getopt(sys.argv[1:], 'hlr:',
                                   ['help', 'lock', 'run='])
    except getopt.error, m:
        usage(m)

    lock = 0
    run = None
    for opt, arg in opts:
        if opt in ('-h', '--help'):
            usage(code=0)
        elif opt in ('-l', '--lock'):
            lock = 1
        elif opt in ('-r', '--run'):
            run = arg

    if len(args) < 1:
        usage('No list name supplied.')

    listname = string.lower(args.pop(0))

    # first try to open mailing list
    write('Loading list:', listname, file=sys.stderr, nl=0)
    if lock:
        write('(locked)', file=sys.stderr)
    else:
        write('(unlocked)', file=sys.stderr)

    m = MailList(listname, lock=lock)

    # try to import the module and run the callable
    if run:
        i = string.find(run, '.')
        if i < 0:
            module = run
            callable = run
        else:
            module = run[:i]
            callable = run[i+1:]
        write('Importing', module, '...', file=sys.stderr)
        mod = __import__(module)
        write('Running %s.%s()' % (module, callable), '...', file=sys.stderr)
        # getattr(mode, callable)(m, *args)
        r = apply(getattr(mod, callable), (m,) + tuple(args))



sys.exitfunc = atexit
main()
