Add 'rm' for a fully qualified DN, instead of only working with RDN.
authorMahlon E. Smith <mahlon@laika.com>
Mon, 11 Aug 2014 11:07:00 -0700
changeset 67 86e3374a40a3
parent 63 f1ca808f165e
child 68 1a480ba231b6
Add 'rm' for a fully qualified DN, instead of only working with RDN. Reported by Lars Tauber <taeuber@bbaw.de>.
CONTRIBUTORS
shelldap
--- a/CONTRIBUTORS	Tue Dec 03 11:47:01 2013 -0800
+++ b/CONTRIBUTORS	Mon Aug 11 11:07:00 2014 -0700
@@ -6,6 +6,7 @@
 Jonathan Rozes <jonathan@laika.com>
 Josef Wells <Josefwells@alumni.utexas.net>
 Landry Breuil <landry@cvs.openbsd.org>
+Lars Täuber <taeuber@bbaw.de>
 Michael Granger <ged@faeriemud.org>
 Michael Raitza <spacefrogg-devel@meterriblecrew.net>
 Mike Hix <m@hix.io>
@@ -14,3 +15,4 @@
 Rong-En Fan <rafan@FreeBSD.org>
 Salvatore Bonaccorso <carnil@debian.org>
 Yann Cezard <yann.cezard@univ-pau.fr>
+
--- a/shelldap	Tue Dec 03 11:47:01 2013 -0800
+++ b/shelldap	Mon Aug 11 11:07:00 2014 -0700
@@ -291,10 +291,12 @@
 =item B<delete>
 
 Remove an entry from the directory.  Globbing is supported.
-All deletes are sanity-prompted.
+All deletes are sanity-prompted.  The -v flag prints the entries out
+for review before delete.
 
     delete uid=mahlon
     delete uid=ma*
+    rm -v uid=mahlon,ou=People,dc=example,o=company l=office
 
 aliased to: rm
 
@@ -400,6 +402,8 @@
 Show current auth credentials.  Unless you specified a binddn, this
 will just show an anonymous bind.
 
+aliased to: id
+
 =back
 
 =head1 TODO
@@ -1450,31 +1454,76 @@
 sub run_delete
 {
 	my $self = shift;
-	my @DNs  = @_;
-
-	unless ( scalar @DNs ) {
+	my @args  = @_;
+	my @matches;
+	my $s;
+	my $verbose;
+
+	unless ( scalar @args ) {
 		print "No dn specified.\n";
 		return;
 	}
 
-	my $filter;
-	unless ( $DNs[0] eq '*' ) {
-		$filter = $self->make_filter( \@DNs ) or return;
+	# Flags.
+	#
+	if ( $args[0] =~ /^\-v/ ) {
+		$verbose = 1;
+		shift @args;
 	}
-
-	my $s = $self->search({ scope => 'one', filter => $filter });
-	unless ( $s->{'code'} == LDAP_SUCCESS ) {
-		print "$s->{'message'}\n";
+	
+	# Separate real args from filter arguments.
+	#
+	foreach my $dn ( @args ) {
+		if ( $dn eq '*' ) {
+			$s = $self->search({ scope => 'one' });
+			map { push @matches, $_ } @{ $s->{'entries'} } if $s->{'code'} == LDAP_SUCCESS;
+		}
+
+		# Search by filter
+		#
+		else {
+
+			my $filter = $self->make_filter( [$dn] ) or next;
+			$s = $self->search({ scope => 'one', filter => $filter });
+			if ( scalar @{$s->{'entries'}} != 0 ) {
+				map { push @matches, $_ } @{ $s->{'entries'} } if $s->{'code'} == LDAP_SUCCESS;
+			}
+
+			# Search by exact DN.
+			#
+			else {
+				$dn = $self->path_to_dn( $dn );
+				$s = $self->search({ base => $dn, vals => 0 });
+				my $e = ${ $s->{'entries'} }[0];
+				push @matches, $e if $s->{'code'} == LDAP_SUCCESS;
+			}
+		}
+	}
+
+	# Unique the matchset for a consistent count, keyed by DN.
+	#
+	my @uniq_matches = keys %{{ map { $_->dn => 1 } @matches }};
+
+	my $mcount = scalar @uniq_matches;
+	if ( $mcount == 0 ) {
+		print "Nothing matched.\n";
 		return;
 	}
 
-	print "Are you sure? [Ny]: ";
+	if ( $verbose ) {
+		print "* $_\n" foreach @uniq_matches;
+	}
+
+	print "About to remove $mcount item(s).  Are you sure? [Ny]: ";
 	chomp( my $resp = <STDIN> );
 	return unless $resp =~ /^y/i;
-   
-	foreach my $e ( @{ $s->{'entries'} } ) {
+
+	my %seen;
+	foreach my $e ( @matches ) {
 		my $dn = $e->dn();
+		next if $seen{ $dn };
 		my $rv = $self->ldap->delete( $dn );
+		$seen{ $dn }++;
 		print "$dn: ", $rv->error(), "\n";
 	}
    
@@ -1538,7 +1587,6 @@
 		}
 		close LDIF;
 	}
-
 	# checksum it, then open it in an editor
 	#
 	my $hash_orig = $self->chksum( $self->{'ldif_fname'} );