#! /usr/local/bin/python
#
# Copyright (C) 1998-2003 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.

"""Find all lists that a member's address is on.

Usage:
    find_member [options] regex [regex [...]]

Where:
    --listname=listname
    -l listname
        Include only the named list in the search.

    --exclude=listname
    -x listname
        Exclude the named list from the search.

    --owners
    -w
        Search list owners as well as members.

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

    regex
        A Python regular expression to match against.

The interaction between -l and -x 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 is Perl5-like, using 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.

"""

import sys
import re
import getopt

import paths
from Mailman import Utils
from Mailman import MailList
from Mailman import Errors
from Mailman.i18n import _

AS_MEMBER = 0x01
AS_OWNER = 0x02



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 scanlists(options):
    cres = []
    for r in options.regexps:
        cres.append(re.compile(r, re.IGNORECASE))
    #
    # dictionary of {address, (listname, ownerp)}
    matches = {}
    for listname in options.listnames:
        try:
            mlist = MailList.MailList(listname, lock=0)
        except Errors.MMListError:
            print _('No such list: %(listname)s')
            continue
        if options.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
    return matches



class Options:
    listnames = Utils.list_names()
    owners = None


def main():
    try:
        opts, args = getopt.getopt(sys.argv[1:], 'l:x:wh',
                                   ['listname=', 'exclude=', 'owners',
                                    'help'])
    except getopt.error, msg:
        usage(1, msg)

    options = Options()
    loptseen = 0
    excludes = []
    for opt, arg in opts:
        if opt in ('-h', '--help'):
            usage(0)
        elif opt in ('-l', '--listname'):
            if not loptseen:
                options.listnames = []
                loptseen = 1
            options.listnames.append(arg.lower())
        elif opt in ('-x', '--exclude'):
            excludes.append(arg.lower())
        elif opt in ('-w', '--owners'):
            options.owners = 1

    for ex in excludes:
        try:
            options.listnames.remove(ex)
        except ValueError:
            pass

    if not args:
        usage(1, _('Search regular expression required'))

    options.regexps = args

    if not options.listnames:
        print _('No lists to search')
        return

    matches = scanlists(options)
    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()
