#!/usr/local/bin/perl
#
# $Id: groupmodify,v 1.6 2004/06/01 20:08:40 visick Exp $
#
# groupmodify - edit a group in LDAP
#
# Copyright (C) 2002 Steven Barrus
# Copyright (C) 2002 Dana Dahlstrom
# Copyright (C) 2002 Robert Ricci
# Copyright (C) 2002 Spencer Visick
#
# See the AUTHORS file for contact info
#
# 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



use Getopt::Std;
use Term::ReadLine;

require 'usertools.ph';

use strict;
no strict "vars";

$term = new Term::ReadLine;

@fields = ( 'cn', 'gidNumber', 'memberUid' );
if ($config{group_attribute}){
  for (parse_csv($config{group_attribute})){
    push(@fields,$_)
  }
}

%special_sub = ( 'memberUid' => \&get_memberuids);
if($config{group_attribute}){
  for (@fields){
    if ($_ eq "owner"){
      $special_sub{owner} = \&get_dn;
    }
  }
}

# Check for -h
if ($ARGV[0] =~ /^-h/) {
  exit &usage;
}

# Connect to the LDAP server
$ldap = ldap_connect() || exit(1);

if (@ARGV) {
  foreach (@ARGV) {
    if ($_ =~ /(.+)=(.*)/){
      $attrs{$1} = $2;
    } else {
      push(@groups,$_);
    }
  }
  if (keys(%attrs)){
    foreach (@groups) {
      &setattr($_);
    }
  } else {
    foreach (@groups) {
      &chentry($_);
    }
  }
} else {
  while (1) {
    print "Lookup entry for group (blank to end): ";
    $group = <STDIN>;
    chomp $group;
    if ($group) {
      &chentry($group);
    } else {
      last;
    }
  }
}

sub chentry {
  $group = shift;

  $search = "(cn=" . $group . ")";
  $mesg = $ldap->search(base => $config{groupbase}, filter => $search);
  $entry = $mesg->entry();

  if ($entry) {
    print "Found LDAP entry for $group\n";
  } else {
    print "Unable to find LDAP entry for $group\n";
    return 0;
  }

  while (1) {
    print "\n";
    $index = 1;
    foreach ( @fields ) {
      $aref = $entry->get_value($_, asref => 1);
      printf("%2d)%20s: ",$index++,$_);
      if ($aref) {
        print join ", ", @$aref;
      }
      print "\n";
    }
    print " C)ancel all changes\n";
    print " S)ave changes\n";
    print " D)elete this group\n";
    
    print "\nSelection? ";
    $choice = lc(<STDIN>);
    chomp $choice;

    # C)ancel all changes
    if ($choice =~ /^c/) {
      return;
    }

    # D)elete this group
    if ($choice =~ /^d/) {
      print "Really delete $group? [y/N] ";
      $choice = lc(<STDIN>);
      if ($choice =~ /^y/) {
        $mesg = $ldap->delete($entry);
        warn $mesg->error . "\n" if $mesg->code;
        return;
      } else {
        next;
      }
    }

    # S)ave changes and exit
    if ($choice =~ /^s/) {
      $mesg = $entry->update( $ldap) ;
      warn $mesg->error . "\n" if $mesg->code;
      return;
    }

    next if ($choice eq "" or $choice < 1);

    $field = $fields[$choice-1];

    if ($special_sub{$field}) {
      &{$special_sub{$field}};
    } else {
      $value = $term->readline("$field: ", $entry->get_value($field));
      if ($value) {
        $mesg = $entry->replace($field => $value);
      } else {
        $mesg = $entry->delete($field);
      }
    }
  }
}

sub setattr {
  $group = shift;

  $search = "(cn=" . $group . ")";

  $mesg = $ldap->search( base => $config{groupbase}, filter => $search);
  $entry = $mesg->entry();

  if (!$entry) {
    print "Unable to find LDAP entry for $user\n";
    return 0;
  }
  foreach $field (keys(%attrs)){
     if ($attrs{$field}) {
       $mesg = $entry->replace($field => $attrs{$field});
     } else {
       $mesg = $entry->delete($field);
     }
  }
  $mesg = $entry->update($ldap) ;
  warn $mesg->error . "\n" if $mesg->code;
  return;
}


sub usage {

  print << "EOSTR";

Usage: $0 [groupnames]

If no group name is given, $0 will enter a loop, prompting for groups.

EOSTR

  1;
}

sub edit_list {
  if ($entry->get_value($field)) {
    $aref = $entry->get_value($field, asref => 1);
    $list_string = join ', ', @$aref;
  }
  $list_string = $term->readline("$field: ", $list_string);
  @new_array = parse_csv($list_string);
  foreach (@new_array) { s/^\s*// }
  $entry->replace($field => \@new_array);
}

sub get_memberuids {

  if ($entry->get_value($field)) {
    $aref = $entry->get_value($field, asref => 1);
    $list_string = join ', ', @$aref;
  }

  while (1) { 
    $list_string = $term->readline("Members: ", $list_string);
    @uids = parse_csv($list_string);
    @bad_uids = ();
    @good_uids = ();

    foreach $uid (@uids) {
      if (($ldap->search(base => $config{userbase},filter => "(uid=$uid)"))->entry()) {
        push @good_uids, $uid;
      } else {
        push @bad_uids, $uid;
      }
    }

    if (@bad_uids) {
      print "Sorry, the following usernames were not found in LDAP:\n";
      print join ", ", @bad_uids;
      print "\n";
    } else {
      $entry->replace($field => \@good_uids);
      return;
    }
  }

}

sub get_dn {

  while (1) {
    $input = $term->readline("$field: ", $entry->get_value($field)); 

    if ($input eq "") {
      $entry->replace($field =>  $input );
      return;
    } elsif ($input =~ /uid=/) {
      $uid = (parse_csv( $'))[0];
    } else {
      $uid = $input;
    }

    $mesg = $ldap->search(base => $config{userbase},filter => "(uid=$uid)");
    $search = $mesg->entry();

    if ($search) {
      $entry->replace($field => $search->dn()) ;
      return;
    } else {
      print "Sorry, $uid was not found in LDAP. Try another username.\n";
    }
  }

}

__END__
=head1 NAME

groupmodify - edit a group in LDAP

=head1 SYNOPSIS

B<groupmodify> [groupnames]

B<groupmodify> [groupnames] [attr=value] ...

B<groupmodify> [-h]
     

=head1 DESCRIPTION

B<groupmodify> allows changes to a group in the LDAP directory 
specified in /etc/usertools.conf or $HOME/.usertoolsrc. 
You will be prompted for a password with which to bind. If no 
group name is given, B<groupmodify> will enter a loop, prompting 
for groups.

If I<attr=value> pair is given the attribute will be silently 
updated for all groups specified on the command line. If no group 
name is specified, no attributes will be modified.


You may edit cn, gid number, members, and any custom attribute
in the list group_attribute in your configuration file.

=head1 OPTIONS

B<-h>

Print out usage information.

=head1 BUGS

lots probably, sorry. Contact usertools-bugs@nongnu.org if you find any.

=head1 AUTHORS

The usertools were written at the CADE by various opers. See the AUTHORS file 
for details.

=head1 SEE ALSO

groupcreate(1), groupsearch(1),
usercreate(1), usermodify(1), userrevert(1), usersearch(1), userdelete(1).


=cut 

