# group.py - group entry lookup routines
#
# Copyright (C) 2010, 2011 Arthur de Jong
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library 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
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301 USA

import logging
import ldap.filter

import constants
import common
from passwd import dn2uid, uid2dn


def clean(lst):
    if lst:
        for i in lst:
            yield i.replace('\0', '')


attmap = common.Attributes(cn='cn',
                           userPassword='"*"',
                           gidNumber='gidNumber',
                           memberUid='memberUid',
                           member='member')
filter = '(|(objectClass=posixGroup)(objectClass=groupOfNames))'


class GroupRequest(common.Request):

    wantmembers = True

    def write(self, dn, attributes, parameters):
        # get group names and check against requested group name
        names = attributes['cn']
        if 'cn' in parameters:
            if parameters['cn'] not in names:
                return
            names = ( parameters['cn'], )
        # get group group password
        passwd = attributes['userPassword'][0]
        # get group id(s)
        gids = (  parameters['gidNumber'], ) if 'gidNumber' in parameters else attributes['gidNumber']
        gids = [ int(x) for x in gids ]
        # build member list
        members = set()
        if self.wantmembers:
            # add the memberUid values
            for member in clean(attributes['memberUid']):
                if common.isvalidname(member):
                    members.add(member)
            # translate and add the member values
            for memberdn in clean(attributes['member']):
                member = dn2uid(self.conn, memberdn)
                if member and common.isvalidname(member):
                    members.add(member)
        # actually return the results
        for name in names:
            if not common.isvalidname(name):
                print 'Warning: group entry %s contains invalid group name: "%s"' % ( dn, name )
            else:
                for gid in gids:
                    self.fp.write_int32(constants.NSLCD_RESULT_BEGIN)
                    self.fp.write_string(name)
                    self.fp.write_string(passwd)
                    self.fp.write_gid_t(gid)
                    self.fp.write_stringlist(members)


class GroupByNameRequest(GroupRequest):

    action = constants.NSLCD_ACTION_GROUP_BYNAME

    def read_parameters(self, fp):
        name = fp.read_string()
        common.validate_name(name)
        return dict(cn=name)


class GroupByGidRequest(GroupRequest):

    action = constants.NSLCD_ACTION_GROUP_BYGID

    def read_parameters(self, fp):
        return dict(gidNumber=fp.read_gid_t())


class GroupByMemberRequest(GroupRequest):

    action = constants.NSLCD_ACTION_GROUP_BYMEMBER
    wantmembers = False

    def __init__(self, *args, **kwargs):
        super(GroupByMemberRequest, self).__init__(*args, **kwargs)
        # set up our own attributes that leave out membership attributes
        self.attmap = common.Attributes(attmap)
        del self.attmap['memberUid']
        del self.attmap['member']

    def read_parameters(self, fp):
        memberuid = fp.read_string()
        common.validate_name(memberuid)
        return dict(memberUid=memberuid)

    def attributes(self):
        return self.attmap.attributes()

    def mk_filter(self, parameters):
        # we still need a custom mk_filter because this is an | query
        memberuid = parameters['memberUid']
        if attmap['member']:
            dn = uid2dn(self.conn, memberuid)
            if dn:
                return '(&%s(|(%s=%s)(%s=%s)))' % ( self.filter,
                          attmap['memberUid'], ldap.filter.escape_filter_chars(memberuid),
                          attmap['member'], ldap.filter.escape_filter_chars(dn) )
        return '(&%s(%s=%s))' % ( self.filter,
                  attmap['memberUid'], ldap.filter.escape_filter_chars(memberuid) )


class GroupAllRequest(GroupRequest):

    action = constants.NSLCD_ACTION_GROUP_ALL