#! /usr/bin/python
#
# July 2010, Anthony R. Thompson, almost an exact copy of change_pw,
# modified to change the moderator password instead of list password.
#
# Since this is 95% the same code, it might just be better if
# change_pw took a -m flag to set the moderator password instead of
# the list password, but this script is an interim step allowing one
# to set the moderator password from the command line or shell script.
#
# Copyright (C) 2001-2007 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., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.
#

"""Change a list's moderator password.

Change the moderator password for one or more lists, based on the
change_pw program.  See usage for change_pw for password crypt format
information.

Like change_pw, if not given a password this program will set the
moderator password to a randomly-generated password.

Thus, this script will generate or set moderator passwords for a list,
and optionally sends it to all the owners and moderators of the list.

Usage: change_mod_pw [options]

Options:

    --all / -a
        Change the moderator password for all lists.

    --domain=domain
    -d domain
        Change the moderator password for all lists in the virtual
        domain `domain'.  It is okay to give multiple -d options.

    --listname=listname
    -l listname
        Change the moderator password only for the named list.  It is
        okay to give multiple -l options.

    --password=newpassword
    -p newpassword
        Use the supplied plain text password `newpassword' as the new
        moderator password for any lists that are being changed (as
        specified by the -a, -d, and -l options).  If not given, lists
        will be assigned a randomly generated new moderator password.

    --quiet / -q
        Don't notify list owners and moderators of the new moderator
        password.  You'll have to have some other way of letting the
        list owners and moderators know the new moderator password
        (presumably out-of-band).

    --help / -h
        Print this help message and exit.
"""

import sys
import sha
import getopt

# This next line might not be necessary if this script is put in the
# same directory as the change_pw script
sys.path.append('/usr/lib/mailman/')  # INSTALL; Mailman directory location

from Mailman import mm_cfg
from Mailman import Utils
from Mailman import MailList
from Mailman import Errors
from Mailman import Message
from Mailman import i18n

_ = i18n._

SPACE = ' '



def usage(code, msg=''):
    if code:
        fd = sys.stderr
    else:
        fd = sys.stdout
    print >> fd, _(__doc__)
    if msg:
        print >> fd, msg
    sys.exit(code)



_listcache = {}

def openlist(listname):
    missing = []
    mlist = _listcache.get(listname, missing)
    if mlist is missing:
        try:
            mlist = MailList.MailList(listname, lock=0)
        except Errors.MMListError, e:
            usage(1, _('No such list "%(listname)s"\n%(e)s'))
        _listcache[listname] = mlist
    return mlist



def main():
    # Parse options
    try:
        opts, args = getopt.getopt(
            sys.argv[1:], 'ad:l:p:qh',
            ['all', 'domain=', 'listname=', 'password=', 'quiet', 'help'])
    except getopt.error, msg:
        usage(1, msg)

    # defaults
    listnames = {}
    domains = {}
    password = None
    quiet = 0

    for opt, arg in opts:
        if opt in ('-h', '--help'):
            usage(0)
        elif opt in ('-a', '--all'):
            for name in Utils.list_names():
                listnames[name] = 1
        elif opt in ('-d', '--domain'):
            domains[arg] = 1
        elif opt in ('-l', '--listname'):
            listnames[arg.lower()] = 1
        elif opt in ('-p', '--password'):
            password = arg
        elif opt in ('-q', '--quiet'):
            quiet = 1

    if args:
        strargs = SPACE.join(args)
        usage(1, _('Bad arguments: %(strargs)s'))

    if password is not None:
        if not password:
            usage(1, _('Empty list moderator passwords are not allowed'))
        shapassword = sha.new(password).hexdigest()

    if domains:
        for name in Utils.list_names():
            mlist = openlist(name)
            if domains.has_key(mlist.host_name):
                listnames[name] = 1

    if not listnames:
        print >> sys.stderr, _('Nothing to do.')
        sys.exit(0)

    # Set the moderator password on the lists
    for listname in listnames.keys():
        mlist = openlist(listname)
        mlist.Lock()
        try:
            if password is None:
                randompw = Utils.MakeRandomPassword(
                    mm_cfg.ADMIN_PASSWORD_LENGTH)
                shapassword = sha.new(randompw).hexdigest()
                notifypassword = randompw
            else:
                notifypassword = password

            mlist.mod_password = shapassword
            mlist.Save()
        finally:
            mlist.Unlock()

        # Notification
        print _('New %(listname)s moderator password: %(notifypassword)s')
        if not quiet:
            otrans = i18n.get_translation()
            i18n.set_language(mlist.preferred_language)
            try:
                hostname = mlist.host_name
                adminurl = mlist.GetScriptURL('admin', absolute=1)
                msg = Message.UserNotification(
                    mlist.owner[:] + mlist.moderator[:],
                    Utils.get_site_email(),
                    _('Your new %(listname)s moderator password'),
                    _('''\
The site administrator at %(hostname)s has changed the moderator
password for your mailing list %(listname)s.  It is now

    %(notifypassword)s

Please be sure to use this for all future list moderation.  If you own
this list, you may want to log in now and change the moderator
password to something more to your liking.  Visit your list admin page
at

    %(adminurl)s
'''),
                    mlist.preferred_language)
            finally:
                i18n.set_translation(otrans)
            msg.send(mlist)



if __name__ == '__main__':
    main()
