ldapsh-cvs Mailing List for LDAP shell
Status: Beta
Brought to you by:
rcorvalan
You can subscribe to this list here.
2002 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
(7) |
Aug
|
Sep
(1) |
Oct
|
Nov
|
Dec
|
---|---|---|---|---|---|---|---|---|---|---|---|---|
2003 |
Jan
|
Feb
|
Mar
|
Apr
|
May
(5) |
Jun
|
Jul
(12) |
Aug
(3) |
Sep
(11) |
Oct
|
Nov
(4) |
Dec
(10) |
2004 |
Jan
(2) |
Feb
(8) |
Mar
(4) |
Apr
|
May
|
Jun
(1) |
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2007 |
Jan
|
Feb
|
Mar
(1) |
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: <rco...@us...> - 2007-03-13 23:30:52
|
Update of /cvsroot/ldapsh/ldapsh In directory sc8-pr-cvs6.sourceforge.net:/tmp/cvs-serv31753 Modified Files: ldapsh Log Message: Added Pages Results ("pagesize" command) Added "diff" command to compare 2 entries Added "-noheader" option to csv command Index: ldapsh =================================================================== RCS file: /cvsroot/ldapsh/ldapsh/ldapsh,v retrieving revision 1.57 retrieving revision 1.58 diff -C2 -d -r1.57 -r1.58 *** ldapsh 3 Jun 2004 15:34:20 -0000 1.57 --- ldapsh 13 Mar 2007 23:30:44 -0000 1.58 *************** *** 301,305 **** use Term::ReadLine; use Data::Dumper qw(Dumper); ! #use Unicode::MapUTF8 qw(to_utf8 from_utf8); use subs qw(bind connect delete dump exit mkdir rename reset); --- 301,305 ---- use Term::ReadLine; use Data::Dumper qw(Dumper); ! use subs qw(bind connect delete dump exit mkdir rename reset); *************** *** 308,311 **** --- 308,312 ---- BEGIN { require Net::LDAP; + require Net::LDAP::Control::Paged; require Cwd; require Devel::Symdump; *************** *** 346,350 **** SSL => 0, BINDDN => '', ! LDAPVERSION => '3' }, RIGHTS => 'RWL' --- 347,352 ---- SSL => 0, BINDDN => '', ! LDAPVERSION => '3', ! PAGESIZE => 0 }, RIGHTS => 'RWL' *************** *** 588,593 **** sub _search { my %SearchParams = @_; ! ! my $result = _searchWEC( base => $SearchParams{BaseDN}, scope => $SearchParams{Scope}, --- 590,594 ---- sub _search { my %SearchParams = @_; ! my %SearchParams2 = ( base => $SearchParams{BaseDN}, scope => $SearchParams{Scope}, *************** *** 595,609 **** attrs => $SearchParams{Attrs} ); - return unless defined($result); ! if (_isReallyLDAPError($result->code)) { ! printf STDERR (qq(Error on LDAP search. Code='%s'. Message='%s'\n), $result->code, $result->error); ! return; ! } else { ! $Globals->{ENTRIES}{VALUE} = [] unless $Globals->{_APPENDRESULTS}{VALUE}; my @entries = $result->entries(); push @{$Globals->{ENTRIES}{VALUE}}, @entries; ! return \@entries; } } --- 596,641 ---- attrs => $SearchParams{Attrs} ); ! my $page; ! if ($Globals->{CONNPARAMS}{VALUE}{PAGESIZE}) { ! $page = Net::LDAP::Control::Paged->new( size => $Globals->{CONNPARAMS}{VALUE}{PAGESIZE} ); ! $SearchParams2{control} = [ $page ]; ! } ! ! my $isFirst = 1; ! my $isError = 0; ! my $cookie; ! while(1) { ! my $result = $isFirst ? _searchWEC(%SearchParams2) : $Globals->{LDAPCONN}{VALUE}->search(%SearchParams2); ! ! return unless defined($result); ! ! if (_isReallyLDAPError($result->code)) { ! printf STDERR (qq(Error on LDAP search. Code='%s'. Message='%s'\n), $result->code, $result->error); ! return; ! } ! ! if ($isFirst) { ! $Globals->{ENTRIES}{VALUE} = [] unless $Globals->{_APPENDRESULTS}{VALUE}; ! } my @entries = $result->entries(); push @{$Globals->{ENTRIES}{VALUE}}, @entries; ! ! $isFirst = 0; ! if ($Globals->{CONNPARAMS}{VALUE}{PAGESIZE}) { ! my ($result2) = $result->control(Net::LDAP::Constant::LDAP_CONTROL_PAGED()); ! unless ($result2) { ! $isError = 1; ! last; ! } ! last unless ($cookie = $result2->cookie); ! $page->cookie($cookie); ! } else { ! last; ! } } + + return undef if $isError; + return $Globals->{ENTRIES}{VALUE}; } *************** *** 1120,1125 **** $parser = new Pod::Text::Termcap; } if (defined($cmd) && $cmd eq "all") { ! $parser->parse_from_file($0, $Output->{FILEHANDLE}); } else { --- 1152,1159 ---- $parser = new Pod::Text::Termcap; } + $parser->output_fh($Output->{FILEHANDLE}); if (defined($cmd) && $cmd eq "all") { ! #$parser->parse_from_file($0, $Output->{FILEHANDLE}); ! $parser->parse_from_file($0); } else { *************** *** 1150,1154 **** if (-s $podfile) { print {$Output->{FILEHANDLE}} "\n------------------------------\n"; ! $parser->parse_from_file($podfile, $Output->{FILEHANDLE}); print {$Output->{FILEHANDLE}} "\n------------------------------\n"; $found = 1; --- 1184,1189 ---- if (-s $podfile) { print {$Output->{FILEHANDLE}} "\n------------------------------\n"; ! #$parser->parse_from_file($podfile, $Output->{FILEHANDLE}); ! $parser->parse_from_file($podfile); print {$Output->{FILEHANDLE}} "\n------------------------------\n"; $found = 1; *************** *** 1453,1470 **** =head3 diff ! TODO =cut sub diff($$) { ! my ($e1, $e2) = (shift, shift); my %attrs = (); ! map {$attrs{$_}=1} $e1->attributes; ! map {$attrs{$_}=1} $e2->attributes; my %diffs = (); ! foreach my $attr (keys(%attrs)) { ! my $values1 = $e1->get_value($attr, asref => 1); ! my $values2 = $e2->get_value($attr, asref => 1); } } --- 1488,1577 ---- =head3 diff ! B<Synopsis>: C<diff E<lt>entry1E<gt>, E<lt>entry1E<gt>> ! ! B<Synopsis>: C<diff E<lt>rdn1E<gt>, E<lt>rdn2E<gt>> ! ! Compare two objects and print on STDERR the differences: ! ! =over 8 ! ! =item * Attributes that are only on one side ! ! =item * Attribute values differences ! ! =back ! ! The arguments can either be ! ! =over 8 ! ! =item * Net::LDAP::Entry objects ! ! =item * RDN (relative distinguished names) that will be searched ! ! =back =cut sub diff($$) { ! my ($rdn1, $rdn2) = (shift, shift); ! my ($e1, $e2); ! if (ref($rdn1)) { ! $e1 = [$rdn1]; ! } else { ! $e1 = _entriesExpander(undef, $rdn1); ! return 0 unless defined($e1); ! unless (scalar(@$e1) == 1) { ! printf STDERR qq{The first argument ("%s") expanded to %d results\n}, $rdn1, scalar(@$e1); ! return 0; ! } ! } ! if (ref($rdn2)) { ! $e2 = [$rdn2]; ! } else { ! $e2 = _entriesExpander(undef, $rdn2); ! return 0 unless defined($e2); ! unless (scalar(@$e2) == 1) { ! printf STDERR qq{The second argument ("%s") expanded to %d results\n}, $rdn2, scalar(@$e2); ! return 0; ! } ! } ! my %attrs = (); ! map {$attrs{$_}=1} $e1->[0]->attributes; ! map {$attrs{$_}=1} $e2->[0]->attributes; my %diffs = (); ! my $nbNewlines = 1; ! foreach my $attr (sort keys(%attrs)) { ! my (%left, %right, %all, %onlyInLeft, %onlyInRight); ! foreach my $value (@{$e1->[0]->get_value($attr, asref => 1) || []}) { ! $left{$value} = 1; ! } ! foreach my $value (@{$e2->[0]->get_value($attr, asref => 1) || []}) { ! $right{$value} = 1; ! $onlyInRight{$value} = 1 unless exists $left{$value}; ! } ! foreach my $value (keys %left) { ! $onlyInLeft{$value} = 1 unless exists $right{$value}; ! } ! ! if (scalar(keys(%onlyInLeft)) > 0 or scalar(keys(%onlyInRight)) > 0) { ! printf {$Output->{FILEHANDLE}} "\n" x $nbNewlines; ! printf {$Output->{FILEHANDLE}} "[%s]\n", $attr; ! foreach my $value (sort keys(%onlyInLeft)) { ! printf {$Output->{FILEHANDLE}} " < %s\n", $value; ! } ! if (scalar(keys(%onlyInLeft)) > 0 and scalar(keys(%onlyInRight)) > 0) { ! print {$Output->{FILEHANDLE}} " -----------\n"; ! } ! foreach my $value (sort keys(%onlyInRight)) { ! printf {$Output->{FILEHANDLE}} " > %s\n", $value; ! } ! ! $nbNewlines = 2; ! } } + + return 0; } *************** *** 1940,1943 **** --- 2047,2052 ---- =item * C<-dn>: Output the DN of the entries. + =item * C<-noheader>: Don't print the file header. + =back *************** *** 1945,1950 **** sub csv { ! my $localArgs = {fs => ';', vs => '|', 'mv' => 1, 'dn' => 0}; ! my $entries = _entriesExpander [$localArgs, 'fs=s', 'vs=s', 'mv!', 'dn!'], @_; return 0 unless defined $entries; --- 2054,2059 ---- sub csv { ! my $localArgs = {fs => ';', vs => '|', 'mv' => 1, 'dn' => 0, 'header' => 1}; ! my $entries = _entriesExpander [$localArgs, 'fs=s', 'vs=s', 'mv!', 'dn!', 'header!'], @_; return 0 unless defined $entries; *************** *** 1958,1962 **** unshift @fields, 'DN' if $localArgs->{'dn'}; ! print {$Output->{FILEHANDLE}} join($localArgs->{'fs'}, @fields) . "\n"; foreach my $entry (@$entries) { print {$Output->{FILEHANDLE}} join( --- 2067,2072 ---- unshift @fields, 'DN' if $localArgs->{'dn'}; ! print {$Output->{FILEHANDLE}} (join($localArgs->{'fs'}, @fields) . "\n") ! if($localArgs->{'header'}); foreach my $entry (@$entries) { print {$Output->{FILEHANDLE}} join( *************** *** 1965,1969 **** my @vals = $_ eq 'DN' ? ($entry->dn()) : sort($entry->get_value($_)); if ($localArgs->{'mv'}) { ! join($localArgs->{'vs'}, @vals); } else { defined($vals[0]) ? $vals[0] : ''; --- 2075,2079 ---- my @vals = $_ eq 'DN' ? ($entry->dn()) : sort($entry->get_value($_)); if ($localArgs->{'mv'}) { ! join($localArgs->{'vs'}, map {utf8::decode($_); $_;} @vals); } else { defined($vals[0]) ? $vals[0] : ''; *************** *** 2957,2960 **** --- 3067,3090 ---- + =head3 pagesize + + B<Synopsis>: C<pagesize [E<lt>pagesizeE<gt>]> + + Set the PageSize for all future requests in the active connection. Setting this value using this command is equivalent to set L<$CONNPARAMS-E<gt>{PAGESIZE}|"_connparams__pagesize_"> + + Returns the previous value. + + If no parameter is given, do nothing but returning the current value. + + =cut + + sub pagesize { + my $newValue = shift; + my $oldValue = $Globals->{CONNPARAMS}{VALUE}{PAGESIZE}; + $Globals->{CONNPARAMS}{VALUE}{PAGESIZE} = $newValue if defined($newValue); + return $oldValue; + } + + =head3 append *************** *** 3091,3094 **** --- 3221,3228 ---- The protocol version to use (3 by default). + =head2 $CONNPARAMS-E<gt>{PAGESIZE} + + The PageSize for the searches, as described by RFC-2696. 0 means do not use paged searches. + =head2 $CONNPARAMS-E<gt>{SSL} *************** *** 3236,3240 **** } - package ldapsh; --- 3370,3373 ---- |
From: <po...@us...> - 2004-06-03 15:34:31
|
Update of /cvsroot/ldapsh/ldapsh In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv28732 Modified Files: ldapsh Log Message: tiny nobrainer to make !<command> not evaluate <command> as a perl expression after system()-ing it. Index: ldapsh =================================================================== RCS file: /cvsroot/ldapsh/ldapsh/ldapsh,v retrieving revision 1.56 retrieving revision 1.57 diff -C2 -d -r1.56 -r1.57 *** ldapsh 19 Mar 2004 12:24:10 -0000 1.56 --- ldapsh 3 Jun 2004 15:34:20 -0000 1.57 *************** *** 3336,3341 **** if ($PSH_SUPPORT) { Psh::_evl(eval {Psh::Parser::parse_line($_) }) if $_; ! } ! else { s/^\s+//; --- 3336,3340 ---- if ($PSH_SUPPORT) { Psh::_evl(eval {Psh::Parser::parse_line($_) }) if $_; ! } else { s/^\s+//; *************** *** 3343,3347 **** if (s/^!//) { system($_); ! next; } --- 3342,3346 ---- if (s/^!//) { system($_); ! goto NEXT; } *************** *** 3371,3374 **** --- 3370,3374 ---- } + NEXT: my $APP = $Globals->{_APPENDRESULTS}{VALUE} ? '** ' : ''; my $P = eval('return("' . $Globals->{PROMPT}{VALUE} . '")'); |
From: <j-d...@us...> - 2004-03-19 12:33:59
|
Update of /cvsroot/ldapsh/ldapsh In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv13670 Modified Files: ldapsh Log Message: * Escape special LDAP characters when completing RDNs. * Enable tab-completion for RDNs with whitespace. Notes: only works when a user has psh installed; this feature does not yet extend to the task of filter completion. Index: ldapsh =================================================================== RCS file: /cvsroot/ldapsh/ldapsh/ldapsh,v retrieving revision 1.55 retrieving revision 1.56 diff -C2 -d -r1.55 -r1.56 *** ldapsh 19 Mar 2004 12:18:18 -0000 1.55 --- ldapsh 19 Mar 2004 12:24:10 -0000 1.56 *************** *** 837,853 **** $TermAttribs->{completion_append_character} = ','; ! #my @parts1 = split(/\s*,\s*/, $text, -1); ! my @parts1 = _splitdn($text, -1); ! my $partToComplete = pop @parts1 || ''; ! my $prefix = join(',', @parts1); my @parts2 = reverse(@parts1); - my $BaseDN = join(',', @parts2, $Globals->{CWD}{VALUE}); #$TermAttribs->{completion_append_character} = "\0"; if ($partToComplete =~ m/=/) { ! return _RDNCompletion($prefix, $partToComplete, $BaseDN); } else { --- 837,875 ---- $TermAttribs->{completion_append_character} = ','; ! # if $text is preceded by '\ ', then prepend ' ' and search back to the ! # previous space. Note 1: perhaps there are more delimiters that should be ! # recognised. Note 2: the following is only known to work with ASCII. ! my ($newstart, $newtext) = ($start, $text); ! while (substr($line, 0, $newstart) =~ /^(.* )([^ ]*\\ )$/) { ! $newtext = $2.$newtext; ! $newstart = length($1); ! } ! if ($PSH_SUPPORT) { ! $newtext = _unescape($newtext); ! } ! # figure out our proper BaseDN (may extend beyond what readline has told us) ! my @parts1 = _splitdn($newtext, -1); ! my $partToComplete = pop @parts1 || ''; my @parts2 = reverse(@parts1); my $BaseDN = join(',', @parts2, $Globals->{CWD}{VALUE}); + # now figure out which part of the BaseDN is actually being completed + my @parts3 = _splitdn($text, -1); + pop @parts3; + my $prefix = join(',', @parts3); + #$TermAttribs->{completion_append_character} = "\0"; if ($partToComplete =~ m/=/) { ! my @result = _RDNCompletion($prefix, $partToComplete, $BaseDN); ! if (scalar(@result) && $PSH_SUPPORT && length($prefix) == 0 && $text ne $newtext) { ! my ($common, @possible_entries) = @result; ! my $trimlen = length(_escape($newtext)) - length(_escape($text)); ! map {$_ = substr($_, $trimlen)} @possible_entries; ! $common = substr($common, $trimlen); ! return ($common, @possible_entries); ! } ! return @result; } else { *************** *** 868,872 **** #return Psh::OS::_escape(shift); my $text = shift; ! $text =~ s/(?<!\\)([ ])/\\$1/g; return $text; } --- 890,894 ---- #return Psh::OS::_escape(shift); my $text = shift; ! $text =~ s/(?<!\\)([ ()])/\\$1/g; return $text; } *************** *** 875,879 **** #return Psh::Parser::remove_backslash(shift); my $text = shift; ! $text =~ s/\\([ ])/$1/g; return $text; } --- 897,901 ---- #return Psh::Parser::remove_backslash(shift); my $text = shift; ! $text =~ s/\\([ ()])/$1/g; return $text; } *************** *** 911,914 **** --- 933,939 ---- } if ($prefix) { + if ($PSH_SUPPORT) { + $prefix = _escape($prefix); + } map {$_ = "${prefix},$_"} @possible_entries; $common = "${prefix},${common}"; *************** *** 925,929 **** scope => 'one', attrs => [], ! filter => "$partToComplete*" ); return undef unless defined($result); --- 950,955 ---- scope => 'one', attrs => [], ! filter => _escape_filter( $partToComplete )."*" ! ); return undef unless defined($result); *************** *** 938,942 **** } else { my @entries = $result->entries; ! my @possible_entries = map {rdn($_->dn)} @entries; @possible_entries = grep {/^$partToComplete/i} @possible_entries; return undef unless scalar(@possible_entries); --- 964,969 ---- } else { my @entries = $result->entries; ! my @possible_entries = map {my $it = rdn($_->dn); $it =~ s/\\/\\\\/g; $it} @entries; ! # the following line in known to fail if $partToComplete contains regex characters! @possible_entries = grep {/^$partToComplete/i} @possible_entries; return undef unless scalar(@possible_entries); *************** *** 946,951 **** $common = "${prefix},${common}"; } ! if ($PSH_SUPPORT && scalar(@possible_entries) == 1) { ! $possible_entries[0] = _escape($possible_entries[0]); } return $common, @possible_entries; --- 973,979 ---- $common = "${prefix},${common}"; } ! if ($PSH_SUPPORT) { ! map {$_ = _escape($_)} @possible_entries; ! $common = _escape($common); } return $common, @possible_entries; |
From: <j-d...@us...> - 2004-03-19 12:28:07
|
Update of /cvsroot/ldapsh/ldapsh In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv12820 Modified Files: ldapsh Log Message: * Fix up warnings during non-psh operation. Index: ldapsh =================================================================== RCS file: /cvsroot/ldapsh/ldapsh/ldapsh,v retrieving revision 1.54 retrieving revision 1.55 diff -C2 -d -r1.54 -r1.55 *** ldapsh 13 Mar 2004 10:59:19 -0000 1.54 --- ldapsh 19 Mar 2004 12:18:18 -0000 1.55 *************** *** 397,402 **** }; our ($COLUMNS, $CONNPARAMS, $CWD, $DNSEP, $EDITOR, $ENTRIES, $G, $LDAPCONN, $OLDWD, $PROMPT, $LASTFILE); ! our ($LDAPSH_PARSER, $PERL_RL); # read-only values my ($Term, $TermAttribs, $OffLine); --- 397,408 ---- }; + # read/write values our ($COLUMNS, $CONNPARAMS, $CWD, $DNSEP, $EDITOR, $ENTRIES, $G, $LDAPCONN, $OLDWD, $PROMPT, $LASTFILE); ! use vars qw($COLUMNS $CONNPARAMS $CWD $DNSEP $EDITOR $ENTRIES $G $LDAPCONN $OLDWD $PROMPT $LASTFILE); ! ! # read-only values ! our ($LDAPSH_PARSER, $PERL_RL); ! use vars qw($LDAPSH_PARSER $PERL_RL); ! my ($Term, $TermAttribs, $OffLine); *************** *** 725,729 **** my @dots = split(m{[,/]}, $1); my @dn = reverse _splitdn($2, 0); ! my @pwd = _splitdn($CWD, 0); while(scalar(@dots)) { if (shift(@dots) =~ /^\.\.$/) { --- 731,735 ---- my @dots = split(m{[,/]}, $1); my @dn = reverse _splitdn($2, 0); ! my @pwd = _splitdn($Globals->{CWD}{VALUE}, 0); while(scalar(@dots)) { if (shift(@dots) =~ /^\.\.$/) { *************** *** 2169,2174 **** my ($fh, $tempfile); if ($localArgs{X}) { ! if (defined($LASTFILE)) { ! $tempfile = $LASTFILE; $fh = undef; } --- 2175,2180 ---- my ($fh, $tempfile); if ($localArgs{X}) { ! if (length($Globals->{LASTFILE}{VALUE})) { ! $tempfile = $Globals->{LASTFILE}{VALUE}; $fh = undef; } *************** *** 2184,2188 **** my @parts = _splitdn($dn,2); if (scalar(@parts) == 1) { ! print $fh "dn: $dn, $CWD\n"; } else { --- 2190,2194 ---- my @parts = _splitdn($dn,2); if (scalar(@parts) == 1) { ! print $fh "dn: $dn, ".$Globals->{CWD}{VALUE}."\n"; } else { *************** *** 2262,2266 **** } ! $LASTFILE = undef; my $mtime = (stat($tempfile))[9]; --- 2268,2272 ---- } ! $Globals->{LASTFILE}{VALUE} = undef; my $mtime = (stat($tempfile))[9]; *************** *** 2302,2306 **** } else { ! $LASTFILE = $tempfile; print STDERR "LDIF stored in $tempfile\n\n"; } --- 2308,2312 ---- } else { ! $Globals->{LASTFILE}{VALUE} = $tempfile; print STDERR "LDIF stored in $tempfile\n\n"; } *************** *** 2330,2334 **** if ($cleanup) { if ($localArgs{k}) { ! $LASTFILE = $tempfile; print STDERR "LDIF stored in $tempfile\n\n"; } --- 2336,2340 ---- if ($cleanup) { if ($localArgs{k}) { ! $Globals->{LASTFILE}{VALUE} = $tempfile; print STDERR "LDIF stored in $tempfile\n\n"; } *************** *** 2342,2346 **** } else { ! $LASTFILE = $tempfile; print STDERR "LDIF stored in $tempfile\n\n"; } --- 2348,2352 ---- } else { ! $Globals->{LASTFILE}{VALUE} = $tempfile; print STDERR "LDIF stored in $tempfile\n\n"; } *************** *** 2528,2532 **** =cut ! sub rename($$) { my ($from, $to) = @_; $from = "objectclass=*" if ($from eq "*"); --- 2534,2538 ---- =cut ! sub rename { my ($from, $to) = @_; $from = "objectclass=*" if ($from eq "*"); |
From: <j-d...@us...> - 2004-03-13 11:08:04
|
Update of /cvsroot/ldapsh/ldapsh In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv22209 Modified Files: ldapsh Log Message: * Updated dates in copyright notice. Index: ldapsh =================================================================== RCS file: /cvsroot/ldapsh/ldapsh/ldapsh,v retrieving revision 1.53 retrieving revision 1.54 diff -C2 -d -r1.53 -r1.54 *** ldapsh 13 Mar 2004 10:56:56 -0000 1.53 --- ldapsh 13 Mar 2004 10:59:19 -0000 1.54 *************** *** 4,8 **** ##################################################################### ! # Copyright (c) 2002, 2003 Rafael Corvalan # All rights reserved. # This program is free software; you can redistribute it and/or --- 4,8 ---- ##################################################################### ! # Copyright (c) 2002, 2003, 2004 Rafael Corvalan # All rights reserved. # This program is free software; you can redistribute it and/or |
From: <j-d...@us...> - 2004-03-13 11:05:41
|
Update of /cvsroot/ldapsh/ldapsh In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv21779 Modified Files: ldapsh Log Message: * Resolve subroutine synonyms when using _LDAPShellCommandHelp. Index: ldapsh =================================================================== RCS file: /cvsroot/ldapsh/ldapsh/ldapsh,v retrieving revision 1.52 retrieving revision 1.53 diff -C2 -d -r1.52 -r1.53 *** ldapsh 25 Feb 2004 02:09:31 -0000 1.52 --- ldapsh 13 Mar 2004 10:56:56 -0000 1.53 *************** *** 382,385 **** --- 382,400 ---- }; + my $Synonyms = { + 'which' => 'help', + 'quit' => 'exit', + 'disconnect' => 'unbind', + 'source' => 'loadrc', + 'cat' => 'ldif', + 'sink' => 'redir', + 'nosink' => 'noredir', + 'new' => 'create', + 'mkdir' => 'create', + 'rm' => 'remove', + 'mv' => 'rename', + 'change' => 'apply', + }; + our ($COLUMNS, $CONNPARAMS, $CWD, $DNSEP, $EDITOR, $ENTRIES, $G, $LDAPCONN, $OLDWD, $PROMPT, $LASTFILE); our ($LDAPSH_PARSER, $PERL_RL); # read-only values *************** *** 684,687 **** --- 699,703 ---- if (defined($1)) { my $cmd = reverse($1); + $cmd = $Synonyms->{$cmd} if defined $Synonyms->{$cmd}; print "..."; help($cmd); |
From: <j-d...@us...> - 2004-02-25 02:24:11
|
Update of /cvsroot/ldapsh/ldapsh In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv25200 Modified Files: ldapsh Log Message: * Hint about using ./ou=Blah with 'cp' Index: ldapsh =================================================================== RCS file: /cvsroot/ldapsh/ldapsh/ldapsh,v retrieving revision 1.51 retrieving revision 1.52 diff -C2 -d -r1.51 -r1.52 *** ldapsh 25 Feb 2004 02:03:20 -0000 1.51 --- ldapsh 25 Feb 2004 02:09:31 -0000 1.52 *************** *** 205,208 **** --- 205,213 ---- ou=OU Within Other OU, ou=Other OU, o=Parent Organisation + For commands, such as L<cp|cp>, that can accept either an RDN or a DN, + you can rapidly create a DN from an RDN using the following syntax: + + ./ou=A + =head2 REDIRECTION |
From: <j-d...@us...> - 2004-02-25 02:17:58
|
Update of /cvsroot/ldapsh/ldapsh In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv23533 Modified Files: ldapsh Log Message: * Where DN splitting occurs, always use _splitdn * Fix: _splitdn no longer splits in the middle of RDNs that contain \, * Feature: rename, cp and acd now accept a shell-like DN syntax (e.g. ../../ou=Blah). See "Interpretation of Target DNs". Index: ldapsh =================================================================== RCS file: /cvsroot/ldapsh/ldapsh/ldapsh,v retrieving revision 1.50 retrieving revision 1.51 diff -C2 -d -r1.50 -r1.51 *** ldapsh 24 Feb 2004 05:44:02 -0000 1.50 --- ldapsh 25 Feb 2004 02:03:20 -0000 1.51 *************** *** 184,187 **** --- 184,208 ---- =back + =head2 Interpretation of Target DNs + + For some commands (L<rename|rename>, L<cp|cp>, L<acd|acd>), B<ldapsh> + supports an alternative DN syntax that allows you to specify pseudo-DNs using + shell-like notation. If your target DN begins with a dot (.), it will be + interpreted like a commas-separated file path (you may also choose to separate + your dot sequences with slashes, as shown in the example below). Any futher + comma-separated RDNs will be interpreted in 'file path' order, which is the + reverse of DN order. If the I<current working directory> is: + + ou=B, ou=A, o=Parent Organisation + + And you provide one of the following pseudo-DNs: + + "cn=New CN", "../../ou=Other OU,ou=OU Within Other OU" + "cn=New CN", ".., .., ou=Other OU, ou=OU Within Other OU" + + Then the target would be interpreted as: + + ou=OU Within Other OU, ou=Other OU, o=Parent Organisation + =head2 REDIRECTION *************** *** 671,675 **** sub _splitdn($$) { return (undef, undef) unless defined $_[0]; ! split(/\s*,\s*/, shift, shift); } --- 692,720 ---- sub _splitdn($$) { return (undef, undef) unless defined $_[0]; ! split(/\s*(?<!\\),\s*/, shift, shift); ! } ! ! sub _calc_shell_rdn($) { ! # accepts invalid DNs such as ! # ./cn=A,ou=B or .,cn=A,ou=B ! # to mean ou=B,cn=A,$CWD ! # Moreover, .. can be used. ! my ($to) = shift; ! if ($to =~ m{^([.,/]+)(.*)$}) { ! my @dots = split(m{[,/]}, $1); ! my @dn = reverse _splitdn($2, 0); ! my @pwd = _splitdn($CWD, 0); ! while(scalar(@dots)) { ! if (shift(@dots) =~ /^\.\.$/) { ! shift @pwd; ! } ! # silently ignored . and ... ! } ! push @dn, @pwd; ! return join(",", @dn); ! } ! else { ! return $to; ! } } *************** *** 765,769 **** $TermAttribs->{completion_append_character} = ','; ! my @parts1 = split(/\s*,\s*/, $text, -1); my $partToComplete = pop @parts1 || ''; --- 810,815 ---- $TermAttribs->{completion_append_character} = ','; ! #my @parts1 = split(/\s*,\s*/, $text, -1); ! my @parts1 = _splitdn($text, -1); my $partToComplete = pop @parts1 || ''; *************** *** 1466,1470 **** $SubPath =~ s/\s*,\s*$//; ! $SubPath = join(',', reverse(split(/\s*,\s*/, $SubPath))); # Now the $SubPath variable contains a SubDN where we wanna go, in --- 1512,1517 ---- $SubPath =~ s/\s*,\s*$//; ! #$SubPath = join(',', reverse(split(/\s*,\s*/, $SubPath))); ! $SubPath = join(',', reverse(_splitdn($SubPath, 0))); # Now the $SubPath variable contains a SubDN where we wanna go, in *************** *** 1492,1496 **** B<Synopsis>: C<setdn 'E<lt>DNE<gt>'> ! Change the current directory to the specified DN. Unlike the L<cd|cd> command, the argument is a B<DN>, not an B<RDN>. This command has a synonym named L<acd|acd>. =cut --- 1539,1544 ---- B<Synopsis>: C<setdn 'E<lt>DNE<gt>'> ! Change the current directory to the specified DN. Unlike the L<cd|cd> command, the argument is a B<DN>, not an B<RDN>. ! See also L<acd|acd>. =cut *************** *** 1533,1546 **** B<Synopsis>: C<acd 'E<lt>DNE<gt>'> ! A synonym for L<setdn|setdn>. (The name is an abbreviaton of "B<a>bsolute B<cd>".) =cut sub acd { ! setdn(@_); } - - =head3 pushd --- 1581,1597 ---- B<Synopsis>: C<acd 'E<lt>DNE<gt>'> ! Similar to L<setdn|setdn>. (The name is an abbreviaton of "B<a>bsolute B<cd>".) ! ! You may specify a valid DN, or use alternative syntax that allows you to ! specify pseudo-DNs with shell-like notation (see L<Target DNs|"Interpretation ! of Target DNs">). =cut sub acd { ! my $to = _calc_shell_rdn( join(",", @_) ); ! setdn($to); } =head3 pushd *************** *** 2372,2378 **** the filter C<(objectclass=*)>. ! If the C<to> parameter is an RDN, a single object will be copied to a new RDN within ! the same level of the LDAP tree, and you will get an error if C<from-expansion> ! expands to more than one object. If C<to> is a DN, all the objects from C<from-expansion> will be be copied to --- 2423,2431 ---- the filter C<(objectclass=*)>. ! If the C<to> parameter is an RDN, a single object will be copied to a new RDN ! within the same level of the LDAP tree, and you will get an error if ! C<from-expansion> expands to more than one object. B<ldapsh> also supports an ! alternative DN syntax that allows you to specify C<to> with shell-like notation ! (see L<Target DNs|"Interpretation of Target DNs">). If C<to> is a DN, all the objects from C<from-expansion> will be be copied to *************** *** 2388,2391 **** --- 2441,2445 ---- my ($from, $to) = @_; $from = "objectclass=*" if ($from eq "*"); + $to = _calc_shell_rdn( $to ); my $localcopy = (scalar(_splitdn($to,2)) == 1); #I.e $to is an RDN. my $entries = _entriesExpander undef, $from; *************** *** 2443,2446 **** --- 2497,2504 ---- rename "cn=New CN", "ou=New OU, $CWD" + For C<to>, B<ldapsh> also supports an alternative DN syntax that allows you to + specify DNs with shell-like notation (see L<Target DNs|"Interpretation of + Target DNs">). + If your directory server does not allow subtrees to be moved, you may have to copy entries to a new location and then remove the old subtree (see L<cp|cp> *************** *** 2453,2456 **** --- 2511,2515 ---- $from = "objectclass=*" if ($from eq "*"); my $entries = _entriesExpander undef, $from; + $to = _calc_shell_rdn( $to ); if (scalar(@$entries) > 1) { foreach my $entry (@$entries) { *************** *** 3017,3021 **** Will save the entries found during the last search, so you can use this later. You only have one global variable for your own use, so if you need more than one, set this variable to a hash: ! B<Example>: C<$G = {ENTRIES => $ENTRIES, PWD => $PWD}; $G->{TIME} = time();> =head2 $LASTFILE --- 3076,3080 ---- Will save the entries found during the last search, so you can use this later. You only have one global variable for your own use, so if you need more than one, set this variable to a hash: ! B<Example>: C<$G = {ENTRIES => $ENTRIES, CWD => $CWD}; $G->{TIME} = time();> =head2 $LASTFILE |
From: <j-d...@us...> - 2004-02-24 05:58:01
|
Update of /cvsroot/ldapsh/ldapsh In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24500 Modified Files: ldapsh Log Message: * Another attempt at filter escaping (now available without psh support). Index: ldapsh =================================================================== RCS file: /cvsroot/ldapsh/ldapsh/ldapsh,v retrieving revision 1.49 retrieving revision 1.50 diff -C2 -d -r1.49 -r1.50 *** ldapsh 24 Feb 2004 05:19:12 -0000 1.49 --- ldapsh 24 Feb 2004 05:44:02 -0000 1.50 *************** *** 622,626 **** BaseDN => $Globals->{CWD}{VALUE}, Scope => $Options->{r} ? 'sub' : 'one', ! Filter => $spec, Attribs => [] ); --- 622,626 ---- BaseDN => $Globals->{CWD}{VALUE}, Scope => $Options->{r} ? 'sub' : 'one', ! Filter => _escape_filter( $spec ), Attribs => [] ); *************** *** 783,791 **** } sub _escape { #return Psh::OS::_escape(shift); my $text = shift; $text =~ s/(?<!\\)([ ])/\\$1/g; - $text =~ s/(?<!\\)([*()])/\\\\$1/g; return $text; } --- 783,799 ---- } + sub _escape_filter { + my $text = shift; + # escape special characters in LDAP filters (e.g. those that result + # from tab completion), unless it appears that the user constructed + # a complex filter by hand. + $text =~ s/(?<!\\)([*()\\])/\\$1/g unless $text =~ /^\(/; + return $text; + } + sub _escape { #return Psh::OS::_escape(shift); my $text = shift; $text =~ s/(?<!\\)([ ])/\\$1/g; return $text; } *************** *** 794,798 **** #return Psh::Parser::remove_backslash(shift); my $text = shift; ! $text =~ s/\\([ *()])/$1/g; return $text; } --- 802,806 ---- #return Psh::Parser::remove_backslash(shift); my $text = shift; ! $text =~ s/\\([ ])/$1/g; return $text; } *************** *** 1672,1676 **** BaseDN => $basedn, Scope => $scope, ! Filter => $filter, Attrs => \@attr ); --- 1680,1684 ---- BaseDN => $basedn, Scope => $scope, ! Filter => _escape_filter( $filter ), Attrs => \@attr ); |
From: <j-d...@us...> - 2004-02-24 05:33:12
|
Update of /cvsroot/ldapsh/ldapsh In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv20130 Modified Files: ldapsh Log Message: * An attempt at escaping some LDAP filter characters (currently only available with psh support). Index: ldapsh =================================================================== RCS file: /cvsroot/ldapsh/ldapsh/ldapsh,v retrieving revision 1.48 retrieving revision 1.49 diff -C2 -d -r1.48 -r1.49 *** ldapsh 11 Feb 2004 00:09:45 -0000 1.48 --- ldapsh 24 Feb 2004 05:19:12 -0000 1.49 *************** *** 787,790 **** --- 787,791 ---- my $text = shift; $text =~ s/(?<!\\)([ ])/\\$1/g; + $text =~ s/(?<!\\)([*()])/\\\\$1/g; return $text; } *************** *** 793,797 **** #return Psh::Parser::remove_backslash(shift); my $text = shift; ! $text =~ s/\\([ ])/$1/g; return $text; } --- 794,798 ---- #return Psh::Parser::remove_backslash(shift); my $text = shift; ! $text =~ s/\\([ *()])/$1/g; return $text; } |
From: <j-d...@us...> - 2004-02-11 00:13:29
|
Update of /cvsroot/ldapsh/ldapsh In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv634 Modified Files: ldapsh Log Message: * Fixed an amusing regex bug. Index: ldapsh =================================================================== RCS file: /cvsroot/ldapsh/ldapsh/ldapsh,v retrieving revision 1.47 retrieving revision 1.48 diff -C2 -d -r1.47 -r1.48 *** ldapsh 9 Feb 2004 09:07:17 -0000 1.47 --- ldapsh 11 Feb 2004 00:09:45 -0000 1.48 *************** *** 2193,2197 **** while (<LDIF>) { # Simplification of RFC 2849 ! if (/^[0-9a-zA-Z][^:<]*(:|::|<)\W*$/) { # is an attribute with an "empty" value printf $fh "#%s", $_; --- 2193,2197 ---- while (<LDIF>) { # Simplification of RFC 2849 ! if (/^[0-9a-zA-Z][^:<]*(:|::|<)\s*$/) { # is an attribute with an "empty" value printf $fh "#%s", $_; |
From: <j-d...@us...> - 2004-02-09 09:10:32
|
Update of /cvsroot/ldapsh/ldapsh In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv17734 Modified Files: ldapsh Log Message: * Added '-k' option for 'vi'. Index: ldapsh =================================================================== RCS file: /cvsroot/ldapsh/ldapsh/ldapsh,v retrieving revision 1.46 retrieving revision 1.47 diff -C2 -d -r1.46 -r1.47 *** ldapsh 9 Feb 2004 08:27:34 -0000 1.46 --- ldapsh 9 Feb 2004 09:07:17 -0000 1.47 *************** *** 2497,2501 **** =head3 vi ! B<Synopsis>: C<vi E<lt>expansionE<gt>> Show the entries matched by the expansion (see L<Expansion|"Expansion of LDAP DNs and Filters">) in a text editor. --- 2497,2501 ---- =head3 vi ! B<Synopsis>: C<vi ['-k',] E<lt>expansionE<gt>> Show the entries matched by the expansion (see L<Expansion|"Expansion of LDAP DNs and Filters">) in a text editor. *************** *** 2504,2514 **** the search results. Any changes can be viewed using L<changes|changes> and will need to be committed using L<commit|commit>. ! BUG (TODO): If you add an attribute to an entry (so, if you add a value to an attribute ! that hadn't previously a value), it will not be detected. We should do a two-way check. =cut sub vi { ! my $entries = _entriesExpander undef, @_; return 0 unless defined $entries; --- 2504,2516 ---- the search results. Any changes can be viewed using L<changes|changes> and will need to be committed using L<commit|commit>. ! ! Normally, the LDIF file is deleted once the changes have been read in. ! The C<-k> parameter prevents this. =cut sub vi { ! my $localArgs = {}; ! my $entries = _entriesExpander [$localArgs, 'k'], @_; return 0 unless defined $entries; *************** *** 2588,2592 **** } } ! unlink $tempfile; return $entries; } --- 2590,2599 ---- } } ! if ($localArgs->{k}) { ! print STDERR "LDIF stored in $tempfile\n\n"; ! } ! else { ! unlink $tempfile; ! } return $entries; } |
From: <j-d...@us...> - 2004-02-09 08:30:46
|
Update of /cvsroot/ldapsh/ldapsh In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv10661 Modified Files: ldapsh Log Message: * Extra documentation for 'rename'. Index: ldapsh =================================================================== RCS file: /cvsroot/ldapsh/ldapsh/ldapsh,v retrieving revision 1.45 retrieving revision 1.46 diff -C2 -d -r1.45 -r1.46 *** ldapsh 9 Feb 2004 08:09:54 -0000 1.45 --- ldapsh 9 Feb 2004 08:27:34 -0000 1.46 *************** *** 2428,2431 **** --- 2428,2436 ---- (see L<Expansion|"Expansion of LDAP DNs and Filters">), with the addition that C<*> corresponds to the filter C<(objectclass=*)>. + C<to> needs to be a valid RDN or DN, depending on whether you are changing an + RDN or moving an entry to a new location. For example: + + rename "cn=Old CN", "cn=New CN" + rename "cn=New CN", "ou=New OU, $CWD" If your directory server does not allow subtrees to be moved, you may have to |
From: <j-d...@us...> - 2004-02-09 08:13:08
|
Update of /cvsroot/ldapsh/ldapsh In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv6894 Modified Files: ldapsh Log Message: * Added -p option for the 'create' command to 'prune' out attributes with empty values (actually, it comments them out). * Added -X option for the 'create' command to easily 'resume' using the most recent LDIF file. * Added $LASTFILE to support the -X option. * Modified some system(...) calls so that $EDITOR may contain command-line arguments. Index: ldapsh =================================================================== RCS file: /cvsroot/ldapsh/ldapsh/ldapsh,v retrieving revision 1.44 retrieving revision 1.45 diff -C2 -d -r1.44 -r1.45 *** ldapsh 3 Feb 2004 01:09:42 -0000 1.44 --- ldapsh 9 Feb 2004 08:09:54 -0000 1.45 *************** *** 326,329 **** --- 326,330 ---- LDAPCONN => {VALUE => undef, RIGHTS => 'RW'}, DNSEP => {VALUE => "; ", RIGHTS => 'RWL'}, + LASTFILE => {VALUE => undef, RIGHTS => 'RWL'}, ENTRIES => {VALUE => [], RIGHTS => 'RW'}, COLUMNS => {VALUE => *************** *** 355,359 **** }; ! our ($COLUMNS, $CONNPARAMS, $CWD, $DNSEP, $EDITOR, $ENTRIES, $G, $LDAPCONN, $OLDWD, $PROMPT); our ($LDAPSH_PARSER, $PERL_RL); # read-only values my ($Term, $TermAttribs, $OffLine); --- 356,360 ---- }; ! our ($COLUMNS, $CONNPARAMS, $CWD, $DNSEP, $EDITOR, $ENTRIES, $G, $LDAPCONN, $OLDWD, $PROMPT, $LASTFILE); our ($LDAPSH_PARSER, $PERL_RL); # read-only values my ($Term, $TermAttribs, $OffLine); *************** *** 2029,2033 **** =head3 create ! B<Synopsis>: C<create ['-d',|'-k',|'-m',|'-n',|'-q',|'-v',] 'E<lt>RDN|DNE<gt>' [,'E<lt>objectclassE<gt>' ...]> Create a new LDIF file based on the specified distinguished named and object --- 2030,2036 ---- =head3 create ! B<Synopsis>: C<create ['-d',|'-k',|'-m',|'-n',|'-p',|'-q',|'-v',] 'E<lt>RDN|DNE<gt>' [,'E<lt>objectclassE<gt>' ...]> ! ! B<Synopsis>: C<create ['-d',|'-k',|'-p',] '-X'> Create a new LDIF file based on the specified distinguished named and object *************** *** 2036,2042 **** on the LDIF file. In the file is subsequently edited, a new LDAP entry will be created. Upon success, the LDIF file is deleted. Note: you must be sure to ! create a valid LDIF file from the template that is provided to you. If you do ! not, an entry cannot be created. If this error occurs, your invalid LDIF file ! will be preserved for your convenience. By default, the LDIF file is populated with all attributes specified in the schema --- 2039,2047 ---- on the LDIF file. In the file is subsequently edited, a new LDAP entry will be created. Upon success, the LDIF file is deleted. Note: you must be sure to ! create a valid LDIF file from the template that is provided to you (use the C<-p> ! option to allow B<ldapsh> to prune empty attributes from your LDIF file). If ! you do not, an entry cannot be created. If this error occurs, your invalid LDIF ! file will be preserved for your convenience (you can resume your attempt by ! using the C<-X> option). By default, the LDIF file is populated with all attributes specified in the schema *************** *** 2049,2052 **** --- 2054,2059 ---- while C<-d> forces deletion (regardless of failure). + Note: the effectiveness and correctness of the C<-p> option cannot be guaranteed. + =cut *************** *** 2054,2058 **** my @entries; my @successes; ! my %localArgs = ('d' => 0, 'k' => 0, 'm' => 0, 'n' => 0, 'q' => 0, 'v' => 0); @ARGV = @_; --- 2061,2065 ---- my @entries; my @successes; ! my %localArgs = ('d' => 0, 'k' => 0, 'm' => 0, 'n' => 0, 'p' => 0, 'q' => 0, 'v' => 0, 'X' => 0); @ARGV = @_; *************** *** 2060,2066 **** my $dn = shift(@ARGV); ! unless ($dn) { ! print STDERR "A distinguished name is required.\n"; ! return undef; } --- 2067,2081 ---- my $dn = shift(@ARGV); ! if ($localArgs{X}) { ! if ($dn) { ! print STDERR "No distinguished name allowed with -X.\n"; ! return undef; ! } ! } ! else { ! unless ($dn) { ! print STDERR "A distinguished name is required.\n"; ! return undef; ! } } *************** *** 2071,2122 **** require File::Temp; ! my ($fh, $tempfile) = File::Temp::tempfile('LDAPShell_vi_XXXXXXXXXX', SUFFIX => '.ldif'); ! ! # Print DN ! my @parts = _splitdn($dn,2); ! if (scalar(@parts) == 1) { ! print $fh "dn: $dn, $CWD\n"; } else { ! print $fh "dn: $dn\n"; ! } ! @parts = split('=',$parts[0]); ! # Deal with objectclasses ! my %attrs = (); ! if (@ARGV > 0) { ! $attrs{"objectclass"} = 1; ! foreach (@ARGV) { ! print $fh "objectclass: $_\n"; # caution: user might have supplied bad data } ! if (!$localArgs{n}) { ! my $schema = $Globals->{LDAPCONN}{VALUE}->schema(dn=>"cn=Subschema"); ! if ($schema) { ! foreach (@ARGV) { ! my $objectclass = $_; ! my @must = $schema->must($objectclass); ! foreach (@must) { ! my %attr = %$_; ! my $name = lc($attr{name}); ! if (!$attrs{$name}) { ! if ($localArgs{v}) { ! print $fh "# MUST $objectclass \"$attr{desc}\" ($name)\n"; ! } ! elsif (!$localArgs{q}) { ! print $fh "# MUST\n"; ! } ! if ("$name" eq "$parts[0]") { ! print $fh "$name: $parts[1]\n"; ! } ! else { ! print $fh "$name: \n"; ! } ! $attrs{$name} = 1; ! } ! } ! } ! if (!$localArgs{m}) { foreach (@ARGV) { my $objectclass = $_; ! my @must = $schema->may($objectclass); foreach (@must) { my %attr = %$_; --- 2086,2125 ---- require File::Temp; ! my ($fh, $tempfile); ! if ($localArgs{X}) { ! if (defined($LASTFILE)) { ! $tempfile = $LASTFILE; ! $fh = undef; ! } ! else { ! print STDERR "Cannot use -X: no file available.\n"; ! return undef; ! } } else { ! ($fh, $tempfile) = File::Temp::tempfile('LDAPShell_vi_XXXXXXXXXX', SUFFIX => '.ldif'); ! ! # Print DN ! my @parts = _splitdn($dn,2); ! if (scalar(@parts) == 1) { ! print $fh "dn: $dn, $CWD\n"; } ! else { ! print $fh "dn: $dn\n"; ! } ! @parts = split('=',$parts[0]); ! # Deal with objectclasses ! my %attrs = (); ! if (@ARGV > 0) { ! $attrs{"objectclass"} = 1; ! foreach (@ARGV) { ! print $fh "objectclass: $_\n"; # caution: user might have supplied bad data ! } ! if (!$localArgs{n}) { ! my $schema = $Globals->{LDAPCONN}{VALUE}->schema(dn=>"cn=Subschema"); ! if ($schema) { foreach (@ARGV) { my $objectclass = $_; ! my @must = $schema->must($objectclass); foreach (@must) { my %attr = %$_; *************** *** 2124,2131 **** if (!$attrs{$name}) { if ($localArgs{v}) { ! print $fh "# MAY $objectclass \"$attr{desc}\" ($name)\n"; } elsif (!$localArgs{q}) { ! print $fh "# MAY\n"; } if ("$name" eq "$parts[0]") { --- 2127,2134 ---- if (!$attrs{$name}) { if ($localArgs{v}) { ! print $fh "# MUST $objectclass \"$attr{desc}\" ($name)\n"; } elsif (!$localArgs{q}) { ! print $fh "# MUST\n"; } if ("$name" eq "$parts[0]") { *************** *** 2139,2160 **** } } } - } - else { - print $fh "# Server did not provide a schema (do you have permission?).\n"; - print $fh "$parts[0]: $parts[1]\n"; } } ! } ! if (!$attrs{$parts[0]}) { ! print $fh "$parts[0]: $parts[1]\n"; } ! close $fh; my $mtime = (stat($tempfile))[9]; my $cleanup = 1; # success => unlink $tempfile by default ! system($Globals->{EDITOR}{VALUE}, $tempfile); if ( (stat($tempfile))[9] > $mtime ) { my $ldif = Net::LDAP::LDIF->new($tempfile, "r", onerror => undef); while (not $ldif->eof()) { --- 2142,2214 ---- } } + if (!$localArgs{m}) { + foreach (@ARGV) { + my $objectclass = $_; + my @must = $schema->may($objectclass); + foreach (@must) { + my %attr = %$_; + my $name = lc($attr{name}); + if (!$attrs{$name}) { + if ($localArgs{v}) { + print $fh "# MAY $objectclass \"$attr{desc}\" ($name)\n"; + } + elsif (!$localArgs{q}) { + print $fh "# MAY\n"; + } + if ("$name" eq "$parts[0]") { + print $fh "$name: $parts[1]\n"; + } + else { + print $fh "$name: \n"; + } + $attrs{$name} = 1; + } + } + } + } + } + else { + print $fh "# Server did not provide a schema (do you have permission?).\n"; + print $fh "$parts[0]: $parts[1]\n"; } } } ! if (!$attrs{$parts[0]}) { ! print $fh "$parts[0]: $parts[1]\n"; ! } ! ! close $fh; } ! $LASTFILE = undef; ! my $mtime = (stat($tempfile))[9]; my $cleanup = 1; # success => unlink $tempfile by default ! system("$Globals->{EDITOR}{VALUE} $tempfile"); if ( (stat($tempfile))[9] > $mtime ) { + if ($localArgs{p}) { + if (open(LDIF, "<", $tempfile)) { + my ($fh, $secondfile) = File::Temp::tempfile('LDAPShell_vi_XXXXXXXXXX', SUFFIX => '.ldif'); + while (<LDIF>) { + # Simplification of RFC 2849 + if (/^[0-9a-zA-Z][^:<]*(:|::|<)\W*$/) { + # is an attribute with an "empty" value + printf $fh "#%s", $_; + } + else { + printf $fh $_; + } + } + close(LDIF); + unlink $tempfile; + + close($fh); + $tempfile = $secondfile; + } + else { + printf STDERR "Warning: could not open file %s for pruning.\n", $tempfile; + } + } my $ldif = Net::LDAP::LDIF->new($tempfile, "r", onerror => undef); while (not $ldif->eof()) { *************** *** 2167,2170 **** --- 2221,2225 ---- } else { + $LASTFILE = $tempfile; print STDERR "LDIF stored in $tempfile\n\n"; } *************** *** 2194,2197 **** --- 2249,2253 ---- if ($cleanup) { if ($localArgs{k}) { + $LASTFILE = $tempfile; print STDERR "LDIF stored in $tempfile\n\n"; } *************** *** 2205,2208 **** --- 2261,2265 ---- } else { + $LASTFILE = $tempfile; print STDERR "LDIF stored in $tempfile\n\n"; } *************** *** 2458,2462 **** my $mtime = (stat($tempfile))[9]; ! system($Globals->{EDITOR}{VALUE}, $tempfile); # If modified, load as LDIF entry and compare to the same DNs in our directory (if they exist). --- 2515,2519 ---- my $mtime = (stat($tempfile))[9]; ! system("$Globals->{EDITOR}{VALUE} $tempfile"); # If modified, load as LDIF entry and compare to the same DNs in our directory (if they exist). *************** *** 2941,2944 **** --- 2998,3005 ---- B<Example>: C<$G = {ENTRIES => $ENTRIES, PWD => $PWD}; $G->{TIME} = time();> + =head2 $LASTFILE + + The name of the last file edited unsuccessfully (facilitates C<create -X>). + =head2 $LDAPCONN |
From: <rco...@us...> - 2004-01-05 16:56:45
|
Update of /cvsroot/ldapsh/ldapsh In directory sc8-pr-cvs1:/tmp/cvs-serv23577 Modified Files: ldapsh Log Message: Corrected a typo on the previously added note Index: ldapsh =================================================================== RCS file: /cvsroot/ldapsh/ldapsh/ldapsh,v retrieving revision 1.42 retrieving revision 1.43 diff -C2 -d -r1.42 -r1.43 *** ldapsh 5 Jan 2004 13:11:32 -0000 1.42 --- ldapsh 5 Jan 2004 16:56:39 -0000 1.43 *************** *** 264,268 **** =over 8 ! =item * Term::ReadLine::Gnu is not available from ActiveState repository. Term::ReadLine::Gnu is very buggy on Win32 (at least on my box). If you are getting strange characters on the terminal, I suggest you to set the environment variable C<PERL_RL> to "C<0 ornaments=0>" so that Term::ReadLine use stub functions instead of Term::ReadLine::Perl. =back --- 264,268 ---- =over 8 ! =item * Term::ReadLine::Gnu is not available from ActiveState repository, while Term::ReadLine::Perl is very buggy on Win32 (at least on my box). If you are getting strange characters on the terminal, I suggest you to set the environment variable C<PERL_RL> to "C<0 ornaments=0>" so that Term::ReadLine use stub functions instead of Term::ReadLine::Perl. =back |
From: <rco...@us...> - 2004-01-05 13:11:37
|
Update of /cvsroot/ldapsh/ldapsh In directory sc8-pr-cvs1:/tmp/cvs-serv14572 Modified Files: ldapsh Log Message: Added a note for usage on Win32 platform, due to some problems using Term::ReadLine Index: ldapsh =================================================================== RCS file: /cvsroot/ldapsh/ldapsh/ldapsh,v retrieving revision 1.41 retrieving revision 1.42 diff -C2 -d -r1.41 -r1.42 *** ldapsh 23 Dec 2003 12:26:50 -0000 1.41 --- ldapsh 5 Jan 2004 13:11:32 -0000 1.42 *************** *** 256,259 **** --- 256,271 ---- =back + =head1 NOTES + + =head2 Win32 Platform + + Not all modules are available for Win32 platform. LDAPsh has been tested with ActiveState ActivePerl 5.8. Here are some hints to get it working: + + =over 8 + + =item * Term::ReadLine::Gnu is not available from ActiveState repository. Term::ReadLine::Gnu is very buggy on Win32 (at least on my box). If you are getting strange characters on the terminal, I suggest you to set the environment variable C<PERL_RL> to "C<0 ornaments=0>" so that Term::ReadLine use stub functions instead of Term::ReadLine::Perl. + + =back + =cut |
From: <j-d...@us...> - 2003-12-23 12:26:53
|
Update of /cvsroot/ldapsh/ldapsh In directory sc8-pr-cvs1:/tmp/cvs-serv23511 Modified Files: ldapsh Log Message: * Corrected error message in _filterCommandCompletion Index: ldapsh =================================================================== RCS file: /cvsroot/ldapsh/ldapsh/ldapsh,v retrieving revision 1.40 retrieving revision 1.41 diff -C2 -d -r1.40 -r1.41 *** ldapsh 23 Dec 2003 10:46:45 -0000 1.40 --- ldapsh 23 Dec 2003 12:26:50 -0000 1.41 *************** *** 910,914 **** } ! printf STDERR "Cannot change BaseDN. LDAP Error no %s (%s)\n", $result->code, $result->error; return undef; } --- 910,914 ---- } ! printf STDERR "Cannot search. LDAP Error no %s (%s)\n", $result->code, $result->error; return undef; } |
From: <rco...@us...> - 2003-12-23 10:46:49
|
Update of /cvsroot/ldapsh/ldapsh In directory sc8-pr-cvs1:/tmp/cvs-serv8594 Modified Files: ldapsh Log Message: Removed the usage of Unicode::MapUTF8 package since it has some problems to compile on some boxes, and it is not available on Win32. We should look at a better and more portable solution. Perl 5.8 handles Unicode without needing any external module? Index: ldapsh =================================================================== RCS file: /cvsroot/ldapsh/ldapsh/ldapsh,v retrieving revision 1.39 retrieving revision 1.40 diff -C2 -d -r1.39 -r1.40 *** ldapsh 15 Dec 2003 12:27:02 -0000 1.39 --- ldapsh 23 Dec 2003 10:46:45 -0000 1.40 *************** *** 236,241 **** =item * B<Term::ReadLine> - =item * B<Unicode::MapUTF8> - =back --- 236,239 ---- *************** *** 265,269 **** use Term::ReadLine; use Data::Dumper qw(Dumper); ! use Unicode::MapUTF8 qw(to_utf8 from_utf8); use subs qw(bind connect delete dump exit mkdir rename reset); --- 263,267 ---- use Term::ReadLine; use Data::Dumper qw(Dumper); ! #use Unicode::MapUTF8 qw(to_utf8 from_utf8); use subs qw(bind connect delete dump exit mkdir rename reset); |
From: <j-d...@us...> - 2003-12-15 12:27:05
|
Update of /cvsroot/ldapsh/ldapsh In directory sc8-pr-cvs1:/tmp/cvs-serv14704 Modified Files: CHANGES README ldapsh Log Message: * Updated for 0.9.4pre1 Index: CHANGES =================================================================== RCS file: /cvsroot/ldapsh/ldapsh/CHANGES,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** CHANGES 6 Jun 2002 16:33:54 -0000 1.1 --- CHANGES 15 Dec 2003 12:27:02 -0000 1.2 *************** *** 1,3 **** --- 1,25 ---- ######################## + ## 0.9.3 -> 0.9.4 ## + ######################## + + * File: >> ldapsh << + - new commands: 'cp', 'mv', 'rm', 'mkdir', 'history', + 'add', 'replace', 'delete'. + - 'vi' command now supports editing. + - 'cd' command now supports '-' and two-argument syntaxes. + - system-wide rc files. + - improved GNU Readline support. + - expanded documentation and an enhanced 'help' command. + - improved handling of errors. + - expanded tab-completion. + - an improved mechanism for redirection of output. + - additional pre-set variables. + - ldapsh will interpret expressions given on the command line + (such as the name of a subroutine from your .ldapshrc). + - 'ls' now includes a multi-column format. + - support for enhanced shell-style system via an optional + third-party package. + + ######################## ## 0.9.2 -> 0.9.3 ## ######################## Index: README =================================================================== RCS file: /cvsroot/ldapsh/ldapsh/README,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** README 28 May 2002 15:11:48 -0000 1.1 --- README 15 Dec 2003 12:27:02 -0000 1.2 *************** *** 2,6 **** This is an LDAP Shell. The purpose is to give an easy access to an LDAP server, and to make easier the directory content changes. ! See the POD documentation embedded in the sheel itself (using pod2man, pod2text, pod2html or pod2whatever). The HTML version of the documentation is included in the realease (ldapsh.html). Rafael Corvalan --- 2,6 ---- This is an LDAP Shell. The purpose is to give an easy access to an LDAP server, and to make easier the directory content changes. ! See the POD documentation embedded in the shell itself (using pod2man, pod2text, pod2html or pod2whatever). The HTML version of the documentation is included in the release (ldapsh.html). Rafael Corvalan Index: ldapsh =================================================================== RCS file: /cvsroot/ldapsh/ldapsh/ldapsh,v retrieving revision 1.38 retrieving revision 1.39 diff -C2 -d -r1.38 -r1.39 *** ldapsh 14 Dec 2003 07:32:16 -0000 1.38 --- ldapsh 15 Dec 2003 12:27:02 -0000 1.39 *************** *** 293,297 **** } ! our $RELEASE = '0.9.3-2'; my $Opts = { --- 293,297 ---- } ! our $RELEASE = '0.9.4pre1'; my $Opts = { |
From: <j-d...@us...> - 2003-12-14 09:18:48
|
Update of /cvsroot/ldapsh/ldapsh In directory sc8-pr-cvs1:/tmp/cvs-serv23725 Modified Files: ldapsh Log Message: * A minor pod syntax correction. Index: ldapsh =================================================================== RCS file: /cvsroot/ldapsh/ldapsh/ldapsh,v retrieving revision 1.37 retrieving revision 1.38 diff -C2 -d -r1.37 -r1.38 *** ldapsh 14 Dec 2003 04:15:36 -0000 1.37 --- ldapsh 14 Dec 2003 07:32:16 -0000 1.38 *************** *** 1374,1382 **** If no RDN is specified, the I<current working directory> is not changed. ! If C<-> is specified, L<$OLDWD|$OLDWD> is swapped with the I<current working directory>. If C<foo> and C<bar> are specified, C<bar> will be substituted for C<foo> in the I<current working directory> and the result will be used to ! invoke L<setdn|setdn>. If C<foo> was not present in L<$CWD|$CWD>, the I<current working directory> is not changed. --- 1374,1382 ---- If no RDN is specified, the I<current working directory> is not changed. ! If C<-> is specified, L<$OLDWD|"$OLDWD"> is swapped with the I<current working directory>. If C<foo> and C<bar> are specified, C<bar> will be substituted for C<foo> in the I<current working directory> and the result will be used to ! invoke L<setdn|setdn>. If C<foo> was not present in L<$CWD|"$CWD">, the I<current working directory> is not changed. |
From: <j-d...@us...> - 2003-12-14 08:50:22
|
Update of /cvsroot/ldapsh/ldapsh In directory sc8-pr-cvs1:/tmp/cvs-serv25614 Modified Files: ldapsh Log Message: * Added warnings/errors when 'redir' command fails. * Added a primitive 'history' command to view Term::ReadLine::Gnu command history. * Added Psh support: - Documented Psh command-line syntax (dual documentation of ldapsh and Psh syntaxes). - Added dynamic check for availability of Psh module. - Replaced Perl -w option with $^W=1 to suppress warnings when Psh is in use. - Change some 'my' to 'our' so that $ENTRIES is available to Psh Perl evaluation. - Added variables $PSH_SUPPORT and $LDAPSH_PARSER to indicate whether Psh is in use. - Provided Psh::Strategy::Ldapsh::Perlfunc and Psh::Strategy hooks. - Modified main loop to use Psh, when it is available. Index: ldapsh =================================================================== RCS file: /cvsroot/ldapsh/ldapsh/ldapsh,v retrieving revision 1.36 retrieving revision 1.37 diff -C2 -d -r1.36 -r1.37 *** ldapsh 14 Dec 2003 02:51:59 -0000 1.36 --- ldapsh 14 Dec 2003 04:15:36 -0000 1.37 *************** *** 1,3 **** ! #!/usr/bin/perl -w # vim:ts=4:sw=4:noet:ai: --- 1,3 ---- ! #!/usr/bin/perl # vim:ts=4:sw=4:noet:ai: *************** *** 88,92 **** of Perl functions and all you do is to call functions from a prompt. ! In fact, whatever you type at the prompt will either be: =over 8 --- 88,107 ---- of Perl functions and all you do is to call functions from a prompt. ! You can request help typing L<help [E<lt>commandE<gt>]|help> or, if you use ! B<Term::ReadLine::Gnu>, you can type C<E<lt>CTRL-tE<gt>> after a command ! to get help on it. ! ! B<ldapsh> includes a simple command-line interpreter. It can also make use of ! the optional B<Psh> module for an enhanced user experience. This manual ! describes both interpreters as indicated by [ldapsh] and [Psh], respectively. Both ! interpreters facilitate evaluation of Perl expressions and you may use the ! L<$G|"$G"> variable to store your own data. ! ! In this manual, command options are shown as C<'-l',> to be compatible with the ! Perl C<eval()> function. However, you do not usually need to type the ! apostrophes because B<ldapsh> will insert them automatically. If you have ! B<Psh> installed, you do not need to use commas, either. ! ! [ldapsh] Whatever you type at the prompt will either be: =over 8 *************** *** 96,111 **** =item * Evaluated as a Perl expression (using C<eval()>). For convenience, a few commands (such as L<cd|cd>, L<lcd|lcd> and L<help|help>) automatically quote their arguments. Thus, you can type C<cd ou=Users> instead of C<cd "ou=Users">. - You may use the L<$G|"$G"> variable to store values such as your results. ! =back ! You can request help typing L<help [E<lt>commandE<gt>]|help> or, if you use ! B<Term::ReadLine::Gnu>, you can type C<E<lt>CTRL-tE<gt>> after a command ! to get help on it. ! =head2 Expansion Almost every function that uses LDAP entries (L<ls|ls>, L<cat|cat>, --- 111,153 ---- =item * Evaluated as a Perl expression (using C<eval()>). + =back + For convenience, a few commands (such as L<cd|cd>, L<lcd|lcd> and L<help|help>) automatically quote their arguments. Thus, you can type C<cd ou=Users> instead of C<cd "ou=Users">. ! [Psh] What you type at the prompt will be passed through a number of handlers ! that facilitate a rich shell-like syntax. The order of precedence is: ! exclamation mark, brace, B<ldapsh> commands, Perl functions, shell executables, ! Perl evaluation. Please note the following examples for correct quoting of ! strings, arrays, and hashes: ! =over 8 ! =item * Correct (expands L<$CWD|"$CWD">): echo $CWD ! ! =item * Correct (expands L<$CWD|"$CWD">): echo "$CWD" ! ! =item * Prints C<$CWD> literally: echo '$CWD' ! ! =item * Correct (expands L<$ENTRIES|"$ENTRIES">): ls $ENTRIES ! ! =item * Correct (expands L<$ENTRIES|"$ENTRIES">): nbentries $ENTRIES ! ! =item * Incorrect (converts array reference to a string): nbentries "$ENTRIES" ! ! =item * Incorrect (does not expand the variable): nbentries '$ENTRIES' ! ! =item * Expands $ENV{PATH}: echo "$ENV{PATH}" ! ! =item * Expands $ENV{PATH}: echo $ENV\{PATH\} ! ! =item * $ENV expanded on its own: echo $ENV{PATH} ! ! =item * Prints C<$ENV{PATH}> literally: echo '$ENV{PATH}' ! ! =back ! ! =head2 Expansion of LDAP DNs and Filters Almost every function that uses LDAP entries (L<ls|ls>, L<cat|cat>, *************** *** 113,119 **** identified in the documentation with a usage like: C<ls E<lt>expansionE<gt>> - I tried -- even if it's by far incomplete -- to simulate the mechanism of the - shell parser and its variable substitution, wildcard expansion, etc. - The three syntaxes are: --- 155,158 ---- *************** *** 126,130 **** is the I<current working directory>. ! The results of the search are put in the L<$ENTRIES|"$ENTRIES"> array ref (composed of B<Net::LDAP::Entry> entries). --- 165,169 ---- is the I<current working directory>. ! The results of the search are put in the L<$ENTRIES|"$ENTRIES"> array reference (composed of B<Net::LDAP::Entry> entries). *************** *** 151,157 **** You may redirect search results using the L<redir|redir> command. This will ! stay in effect until L<noredir> is called. ! Alternatively, you can use a special shell syntax which will have only a temporary effect. The special syntax is appending "; | ..." to your command, where "..." is a parameter to the C<open> function. --- 190,199 ---- You may redirect search results using the L<redir|redir> command. This will ! stay in effect until L<noredir|noredir> is called. ! [Psh] Psh allows you to use standard shell symbols such as "|" (for piping) ! and ">" (for output redirection). ! ! [ldapsh] Alternatively, you can use a special shell syntax which will have only a temporary effect. The special syntax is appending "; | ..." to your command, where "..." is a parameter to the C<open> function. *************** *** 206,213 **** --- 248,259 ---- =item * B<POSIX::Termios> + =item * B<Psh> + =item * B<Term::ReadKey> =item * B<Term::ReadLine::Gnu> + =item * B<Term::Size> + =back *************** *** 222,225 **** --- 268,273 ---- use subs qw(bind connect delete dump exit mkdir rename reset); + my $PSH_SUPPORT; + BEGIN { require Net::LDAP; *************** *** 230,236 **** Getopt::Long::Configure ('bundling_override'); } ! my $RELEASE = '0.9.3-2'; my $Opts = { --- 278,297 ---- Getopt::Long::Configure ('bundling_override'); + + if ($ENV{LDAPSH_PARSER}) { + $PSH_SUPPORT = $ENV{LDAPSH_PARSER} eq "Psh" && eval "require Psh"; + } + else { + $PSH_SUPPORT = eval "require Psh"; + } + + if (!$PSH_SUPPORT) { + #use warnings; + $^W = 1; + # leave warnings off when psh is in use + } } ! our $RELEASE = '0.9.3-2'; my $Opts = { *************** *** 264,267 **** --- 325,329 ---- EDITOR => {VALUE => $ENV{VISUAL} ? $ENV{VISUAL} : ($ENV{EDITOR} ? $ENV{EDITOR} : 'vi'), RIGHTS => 'RWL'}, G => {VALUE => undef, RIGHTS => 'RWL'}, + LDAPSH_PARSER => {VALUE => $PSH_SUPPORT ? "Psh" : "ldapsh", RIGHTS => 'RL'}, _APPENDRESULTS => {VALUE => 0, RIGHTS => ''}, _DIRSSTACK => {VALUE => [], RIGHTS => ''}, *************** *** 283,288 **** }; ! my ($CWD, $OLDWD, $PROMPT, $CONNPARAMS, $LDAPCONN, $ENTRIES, $EDITOR, $COLUMNS, $DNSEP, $G); ! my ($PERL_RL); # read-only values my ($Term, $TermAttribs); --- 345,350 ---- }; ! our ($COLUMNS, $CONNPARAMS, $CWD, $DNSEP, $EDITOR, $ENTRIES, $G, $LDAPCONN, $OLDWD, $PROMPT); ! our ($LDAPSH_PARSER, $PERL_RL); # read-only values my ($Term, $TermAttribs); *************** *** 303,306 **** --- 365,372 ---- $SIG{INT} = 'IGNORE'; $SIG{__DIE__} = \&_resetTermReadline; + + if ($PSH_SUPPORT) { + eval('Psh::minimal_initialize(); Psh::finish_initialize(); $Psh::eval_preamble = "package ldapsh;"; $Psh::PerlEval::current_package = "ldapsh";'); + } } *************** *** 680,683 **** --- 746,763 ---- } + sub _escape { + #return Psh::OS::_escape(shift); + my $text = shift; + $text =~ s/(?<!\\)([ ])/\\$1/g; + return $text; + } + + sub _unescape { + #return Psh::Parser::remove_backslash(shift); + my $text = shift; + $text =~ s/\\([ ])/$1/g; + return $text; + } + sub _attributeNamesDNCompletion($$$) { my ($prefix, $partToComplete, $BaseDN) = @_; *************** *** 747,750 **** --- 827,833 ---- $common = "${prefix},${common}"; } + if ($PSH_SUPPORT && scalar(@possible_entries) == 1) { + $possible_entries[0] = _escape($possible_entries[0]); + } return $common, @possible_entries; } *************** *** 778,781 **** --- 861,867 ---- return undef unless scalar(@possible_entries); # TODO find longest common prefix + if ($PSH_SUPPORT && scalar(@possible_entries) == 1) { + $possible_entries[0] = _escape($possible_entries[0]); + } return $text, @possible_entries; } else { *************** *** 807,811 **** _bindneeded() or return undef; ! $TermAttribs->{completion_append_character} = '\0'; # match the 'filtertype' portion of an LDAP filter (RFC 2254 and RFC 2251) --- 893,897 ---- _bindneeded() or return undef; ! $TermAttribs->{completion_append_character} = "\0"; # match the 'filtertype' portion of an LDAP filter (RFC 2254 and RFC 2251) *************** *** 834,837 **** --- 920,926 ---- my @possible_entries = map {$prefix.$attr.$extra.scalar($_->get_value($attr))} @entries; # Bug: only uses first attribute value. my $common = _maxCommon(@possible_entries); + if ($PSH_SUPPORT && scalar(@possible_entries) == 1) { + $possible_entries[0] = _escape($possible_entries[0]); + } return $common, @possible_entries; } *************** *** 1232,1235 **** --- 1321,1338 ---- + =head3 history + + B<Synopsis>: C<history> + + Print out each line of the command-line history, if B<Term::ReadLine::Gnu> is available. + + =cut + sub history { + if (_isGnuReadLine) { + print {$Output->{FILEHANDLE}} join("\n", $Term->GetHistory()) . "\n"; + } + } + + =head3 reset *************** *** 1547,1551 **** B<Synopsis>: C<search E<lt>expansionE<gt>> ! Search for the entries matched by the expansion (see L<Expansion|expansion>). Does not dump the entries themselves, only a summary of the search results. --- 1650,1654 ---- B<Synopsis>: C<search E<lt>expansionE<gt>> ! Search for the entries matched by the expansion (see L<Expansion|"Expansion of LDAP DNs and Filters">). Does not dump the entries themselves, only a summary of the search results. *************** *** 1574,1578 **** B<Synopsis>: C<ldif E<lt>expansionE<gt>> ! Display the entries matched by the expansion (see L<Expansion|expansion>) using the LDIF format. See also L<cat|cat>. --- 1677,1681 ---- B<Synopsis>: C<ldif E<lt>expansionE<gt>> ! Display the entries matched by the expansion (see L<Expansion|"Expansion of LDAP DNs and Filters">) using the LDIF format. See also L<cat|cat>. *************** *** 1608,1612 **** B<Synopsis>: C<dump E<lt>expansionE<gt>> ! Dump the entries matched by the expansion (see L<Expansion|expansion>) in a relatively human-readable format. =cut --- 1711,1715 ---- B<Synopsis>: C<dump E<lt>expansionE<gt>> ! Dump the entries matched by the expansion (see L<Expansion|"Expansion of LDAP DNs and Filters">) in a relatively human-readable format. =cut *************** *** 1625,1629 **** B<Synopsis>: C<list ['-a',] ['-dn',] E<lt>expansionE<gt>> ! Display the attribute values of the entries matched by the expansion (see L<Expansion|expansion>) in a list format (easy to parse). Arguments: --- 1728,1732 ---- B<Synopsis>: C<list ['-a',] ['-dn',] E<lt>expansionE<gt>> ! Display the attribute values of the entries matched by the expansion (see L<Expansion|"Expansion of LDAP DNs and Filters">) in a list format (easy to parse). Arguments: *************** *** 1665,1669 **** B<Synopsis>: C<csv [E<lt>optionsE<gt>,] E<lt>expansionE<gt>> ! Display the entries matched by the expansion (see L<Expansion|expansion>) in a CSV format. The first argument can be a list of options to tell how to format the file. If it's given, it's a hash reference. --- 1768,1772 ---- B<Synopsis>: C<csv [E<lt>optionsE<gt>,] E<lt>expansionE<gt>> ! Display the entries matched by the expansion (see L<Expansion|"Expansion of LDAP DNs and Filters">) in a CSV format. The first argument can be a list of options to tell how to format the file. If it's given, it's a hash reference. *************** *** 1723,1727 **** B<Synopsis>: C<ls ['-C',|'-m',] ['-l',] E<lt>expansionE<gt>> ! List the DNs of the entries matched by the expansion (see L<Expansion|expansion>). Entries are displayed in the order received (no sorting is performed), with one entry per line. --- 1826,1830 ---- B<Synopsis>: C<ls ['-C',|'-m',] ['-l',] E<lt>expansionE<gt>> ! List the DNs of the entries matched by the expansion (see L<Expansion|"Expansion of LDAP DNs and Filters">). Entries are displayed in the order received (no sorting is performed), with one entry per line. *************** *** 1826,1830 **** }; ! open $new->{FILEHANDLE}, $out || return $previous; $Output = $new; --- 1929,1939 ---- }; ! if (open($new->{FILEHANDLE}, $out)) { ! print STDERR "Warning: redirection destination did not start with | or >\n" unless $out =~ /^[|>]/; ! } ! else { ! print STDERR "Error: could not change redirection.\n"; ! return $previous; ! } $Output = $new; *************** *** 2092,2096 **** command will prompt you prior to starting and will stop if an error is encountered. You may specify C<-r>, too, as a normal part of expansion (see ! L<Expansion|expansion>). If C<-a> is specified, an attempt will be made to delete leaf entries before their parent entries. Thus, to delete an entire subtree, you might try this: --- 2201,2205 ---- command will prompt you prior to starting and will stop if an error is encountered. You may specify C<-r>, too, as a normal part of expansion (see ! L<Expansion|"Expansion of LDAP DNs and Filters">). If C<-a> is specified, an attempt will be made to delete leaf entries before their parent entries. Thus, to delete an entire subtree, you might try this: *************** *** 2156,2160 **** C<from-expansion> will be expanded in the usual way ! (see L<Expansion|expansion>), with the addition that C<*> corresponds to the filter C<(objectclass=*)>. --- 2265,2269 ---- C<from-expansion> will be expanded in the usual way ! (see L<Expansion|"Expansion of LDAP DNs and Filters">), with the addition that C<*> corresponds to the filter C<(objectclass=*)>. *************** *** 2222,2226 **** C<from-expansion> will be expanded in the usual way ! (see L<Expansion|expansion>), with the addition that C<*> corresponds to the filter C<(objectclass=*)>. --- 2331,2335 ---- C<from-expansion> will be expanded in the usual way ! (see L<Expansion|"Expansion of LDAP DNs and Filters">), with the addition that C<*> corresponds to the filter C<(objectclass=*)>. *************** *** 2290,2294 **** B<Synopsis>: C<vi E<lt>expansionE<gt>> ! Show the entries matched by the expansion (see L<Expansion|expansion>) in a text editor. Entries are saved to a temporary file for editing in the LDIF format. If the temporary file is modified, it will be re-read as an LDIF file and used to modify --- 2399,2403 ---- B<Synopsis>: C<vi E<lt>expansionE<gt>> ! Show the entries matched by the expansion (see L<Expansion|"Expansion of LDAP DNs and Filters">) in a text editor. Entries are saved to a temporary file for editing in the LDIF format. If the temporary file is modified, it will be re-read as an LDIF file and used to modify *************** *** 2521,2525 **** B<Synopsis>: C<changes [$entries]> ! Show the changes done to the entries given in the C<$entries> array ref (or L<$ENTRIES|"$ENTRIES">, if omitted). You can apply some changes to a set of entries using the L<apply|apply> command, and see the changes using the L<changes|changes> command. =cut --- 2630,2634 ---- B<Synopsis>: C<changes [$entries]> ! Show the changes done to the entries given in the C<$entries> array reference (or L<$ENTRIES|"$ENTRIES">, if omitted). You can apply some changes to a set of entries using the L<apply|apply> command, and see the changes using the L<changes|changes> command. =cut *************** *** 2779,2783 **** =head2 $ENTRIES ! The buffer of entries (B<Net::LDAP::Entry>). It's an array ref. Contains the last entries got with the commands L<ls|ls>, L<cat|cat>, L<search|search>... --- 2888,2892 ---- =head2 $ENTRIES ! The buffer of entries (B<Net::LDAP::Entry>). It's an array reference. Contains the last entries got with the commands L<ls|ls>, L<cat|cat>, L<search|search>... *************** *** 2894,2903 **** ! package ldapsh; ! _Init(); $_ = "@ARGV"; --- 3003,3094 ---- + package ldapsh; + _Init(); + if ($PSH_SUPPORT) { + package Psh::Strategy::Ldapsh::Perlfunc; ! use strict; ! use vars qw(@ISA); ! require Psh::Strategy::Perlfunc; ! @ISA=('Psh::Strategy::Perlfunc'); ! ! sub applies { ! my @words= @{$_[2]}; ! if ((Psh::PerlEval::protected_eval("defined(&{'ldapsh::$words[0]'})"))[0]) { ! @{$_[2]}[0] = "ldapsh::@{$_[2]}[0]"; ! } ! else { ! return Psh::Strategy::Perlfunc::applies($_); ! } ! ! } ! ! sub variable_expansion { ! # Adapted from Gregor N. Purdy's Psh::PerlEval.pm ! my ($arref) = @_; ! my @retval = (); ! my $word; ! ! for $word (@{$arref}) { ! if ($word =~ /^\'(.*)\'/) { ! push @retval, $1; ! } ! else { ! no strict qw(vars); ! local $SIG{__WARN__} = sub {}; ! ! my $expr = $word; ! $expr = "\"$expr\"" unless $expr =~ /^[\$"\']/; ! $expr =~ s/\\/\\\\/g; ! ! my $val = eval(eval('$Psh::eval_preamble')." $expr"); ! if ($@) { ! if ($word =~ /^\"(.*)\"/) { ! push @retval, $1; ! } ! else { ! push @retval, $word; ! } ! } ! else { ! push @retval, $val; ! } ! } ! } ! return @retval; ! } ! ! sub execute { ! my @words= @{$_[2]}; ! if ($words[0] =~ "^ldapsh::") { ! # Adapted from Gregor N. Purdy's Psh::Strategy::Built_in.pm ! no strict 'refs'; ! my $coderef = *{$words[0]}; ! shift @words; ! # Should we be using protected_eval? ! @words = variable_expansion(\@words); ! return (1,sub { &{$coderef}(@words); }, [], 0, undef ); ! } ! else { ! return Psh::Strategy::Perlfunc::execute($_); ! } ! } ! ! package Psh::Strategy; ! ! remove("built_in"); ! #remove("executable"); ! #remove("eval"); ! remove("perl"); ! remove("perlfunc"); ! ! my $obj = Psh::Strategy::Ldapsh::Perlfunc->new(); ! add $obj; ! } ! ! package ldapsh; $_ = "@ARGV"; *************** *** 2908,2911 **** --- 3099,3108 ---- while (1) { last unless defined($_); + + if ($PSH_SUPPORT) { + Psh::_evl(eval {Psh::Parser::parse_line($_) }) if $_; + } + else { + s/^\s+//; s/\s+$//; *************** *** 2938,2942 **** # temporary filehandle $Output = $previous if ($previous); ! my $APP = $Globals->{_APPENDRESULTS}{VALUE} ? '** ' : ''; --- 3135,3139 ---- # temporary filehandle $Output = $previous if ($previous); ! } my $APP = $Globals->{_APPENDRESULTS}{VALUE} ? '** ' : ''; |
From: <j-d...@us...> - 2003-12-14 08:48:09
|
Update of /cvsroot/ldapsh/ldapsh In directory sc8-pr-cvs1:/tmp/cvs-serv10064 Modified Files: ldapsh Log Message: * Added 'rename' and 'mv'. * Touch-ups for 'cp'. Index: ldapsh =================================================================== RCS file: /cvsroot/ldapsh/ldapsh/ldapsh,v retrieving revision 1.35 retrieving revision 1.36 diff -C2 -d -r1.35 -r1.36 *** ldapsh 13 Dec 2003 12:39:44 -0000 1.35 --- ldapsh 14 Dec 2003 02:51:59 -0000 1.36 *************** *** 220,224 **** use Data::Dumper qw(Dumper); use Unicode::MapUTF8 qw(to_utf8 from_utf8); ! use subs qw(bind connect delete dump exit mkdir reset); BEGIN { --- 220,224 ---- use Data::Dumper qw(Dumper); use Unicode::MapUTF8 qw(to_utf8 from_utf8); ! use subs qw(bind connect delete dump exit mkdir rename reset); BEGIN { *************** *** 628,632 **** # DN Completion return _cdCommandCompletion(@_); ! } elsif ($cmd =~ /^(cat|vi|ls|list|csv|dump|ldif|search|cp)$/) { # Filter Completion return _filterCommandCompletion(@_); --- 628,632 ---- # DN Completion return _cdCommandCompletion(@_); ! } elsif ($cmd =~ /^(cat|vi|ls|list|csv|dump|ldif|search|cp|mv|rename|remove|rm)$/) { # Filter Completion return _filterCommandCompletion(@_); *************** *** 2094,2098 **** L<Expansion|expansion>). If C<-a> is specified, an attempt will be made to delete leaf entries before their parent entries. Thus, to delete an entire ! subdirectory hierarchy, you might try this: cd 'cn=Old Directory Subtree' --- 2094,2098 ---- L<Expansion|expansion>). If C<-a> is specified, an attempt will be made to delete leaf entries before their parent entries. Thus, to delete an entire ! subtree, you might try this: cd 'cn=Old Directory Subtree' *************** *** 2159,2163 **** the filter C<(objectclass=*)>. ! If C<to> parameter is an RDN, a single object will be copied to a new RDN within the same level of the LDAP tree, and you will get an error if C<from-expansion> expands to more than one object. --- 2159,2163 ---- the filter C<(objectclass=*)>. ! If the C<to> parameter is an RDN, a single object will be copied to a new RDN within the same level of the LDAP tree, and you will get an error if C<from-expansion> expands to more than one object. *************** *** 2174,2178 **** sub cp($$) { my ($from, $to) = @_; ! $from = undef if ($from eq "*"); my $localcopy = (scalar(_splitdn($to,2)) == 1); #I.e $to is an RDN. my $entries = _entriesExpander undef, $from; --- 2174,2178 ---- sub cp($$) { my ($from, $to) = @_; ! $from = "objectclass=*" if ($from eq "*"); my $localcopy = (scalar(_splitdn($to,2)) == 1); #I.e $to is an RDN. my $entries = _entriesExpander undef, $from; *************** *** 2212,2215 **** --- 2212,2284 ---- $Globals->{ENTRIES}{VALUE} = []; } + } + + =head3 rename + + B<Synopsis>: C<rename 'E<lt>from-expansionE<gt>'|'*' 'E<lt>toE<gt>'> + + Rename an entry with a new RDN or move a set of entries to new locations in the + LDAP tree. + + C<from-expansion> will be expanded in the usual way + (see L<Expansion|expansion>), with the addition that C<*> corresponds to + the filter C<(objectclass=*)>. + + If your directory server does not allow subtrees to be moved, you may have to + copy entries to a new location and then remove the old subtree (see L<cp|cp> + and L<remove|remove>). + + =cut + + sub rename($$) { + my ($from, $to) = @_; + $from = "objectclass=*" if ($from eq "*"); + my $entries = _entriesExpander undef, $from; + if (scalar(@$entries) > 1) { + foreach my $entry (@$entries) { + my $rdn = rdn($entry->dn); + my $result = $Globals->{LDAPCONN}{VALUE}->moddn($entry, newrdn => $rdn, newsuperior => $to); + if ($result->is_error) { + printf STDERR qq{LDAP error moving '%s'. Code:%s. Message:%s\n}, + $entry->dn, $result->code, $result->error; + return 0; + } + } + } + elsif (scalar(@$entries) == 1 ) { + my $entry = @$entries[0]; + if (scalar(_splitdn($to, 2)) > 1) { + my $rdn = rdn($entry->dn); + my $result = $Globals->{LDAPCONN}{VALUE}->moddn($entry, newrdn => $rdn, newsuperior => $to); + if ($result->is_error) { + printf STDERR qq{LDAP error moving '%s'. Code:%s. Message:%s\n}, + $entry->dn, $result->code, $result->error; + return 0; + } + } + else { + my $result = $Globals->{LDAPCONN}{VALUE}->moddn($entry, newrdn => $to, deleteoldrdn => 1); + if ($result->is_error) { + printf STDERR qq{LDAP error renaming '%s'. Code:%s. Message:%s\n}, + $entry->dn, $result->code, $result->error; + return 0; + } + } + } + else { + printf STDERR "No entries were renamed or moved.\n"; + return 0; + } + return 1; + } + + =head3 mv + + A synonym for L<rename|rename>. + + =cut + + sub mv($$) { + rename(shift, shift); } |
From: <j-d...@us...> - 2003-12-13 12:39:47
|
Update of /cvsroot/ldapsh/ldapsh In directory sc8-pr-cvs1:/tmp/cvs-serv17973 Modified Files: ldapsh Log Message: * Added 'create' and 'remove' commands. Index: ldapsh =================================================================== RCS file: /cvsroot/ldapsh/ldapsh/ldapsh,v retrieving revision 1.34 retrieving revision 1.35 diff -C2 -d -r1.34 -r1.35 *** ldapsh 13 Dec 2003 10:22:48 -0000 1.34 --- ldapsh 13 Dec 2003 12:39:44 -0000 1.35 *************** *** 220,224 **** use Data::Dumper qw(Dumper); use Unicode::MapUTF8 qw(to_utf8 from_utf8); ! use subs qw(connect bind delete dump exit reset); BEGIN { --- 220,224 ---- use Data::Dumper qw(Dumper); use Unicode::MapUTF8 qw(to_utf8 from_utf8); ! use subs qw(bind connect delete dump exit mkdir reset); BEGIN { *************** *** 1880,1883 **** --- 1880,2220 ---- =head2 Changing entries + =head3 create + + B<Synopsis>: C<create ['-d',|'-k',|'-m',|'-n',|'-q',|'-v',] 'E<lt>RDN|DNE<gt>' [,'E<lt>objectclassE<gt>' ...]> + + Create a new LDIF file based on the specified distinguished named and object + classes. By default, the LDIF file will be populated with attributes to comply + with the schema supplied by the LDAP server. A text editor will then be invoked + on the LDIF file. In the file is subsequently edited, a new LDAP entry will be + created. Upon success, the LDIF file is deleted. Note: you must be sure to + create a valid LDIF file from the template that is provided to you. If you do + not, an entry cannot be created. If this error occurs, your invalid LDIF file + will be preserved for your convenience. + + By default, the LDIF file is populated with all attributes specified in the schema + ('MUST' and 'MAY'). When the C<-m> parameter is given, only 'MUST' attributes + are included. The C<-n> parameter prevents schema-based population. + The C<-q> parameter suppresses informational comments about each attribute + while C<-v> prints verbose information about each attribute. + + The C<-k> parameter prevents deletion of the LDIF file (regardless of success), + while C<-d> forces deletion (regardless of failure). + + =cut + + sub create(@) { + my @entries; + my @successes; + my %localArgs = ('d' => 0, 'k' => 0, 'm' => 0, 'n' => 0, 'q' => 0, 'v' => 0); + + @ARGV = @_; + Getopt::Long::GetOptions(\%localArgs, keys %localArgs); + + my $dn = shift(@ARGV); + unless ($dn) { + print STDERR "A distinguished name is required.\n"; + return undef; + } + + _bindneeded() or return undef; + + # Set up temp file (LDIF) + require Net::LDAP::LDIF; + require File::Temp; + + my ($fh, $tempfile) = File::Temp::tempfile('LDAPShell_vi_XXXXXXXXXX', SUFFIX => '.ldif'); + + # Print DN + my @parts = _splitdn($dn,2); + if (scalar(@parts) == 1) { + print $fh "dn: $dn, $CWD\n"; + } + else { + print $fh "dn: $dn\n"; + } + @parts = split('=',$parts[0]); + # Deal with objectclasses + my %attrs = (); + if (@ARGV > 0) { + $attrs{"objectclass"} = 1; + foreach (@ARGV) { + print $fh "objectclass: $_\n"; # caution: user might have supplied bad data + } + if (!$localArgs{n}) { + my $schema = $Globals->{LDAPCONN}{VALUE}->schema(dn=>"cn=Subschema"); + if ($schema) { + foreach (@ARGV) { + my $objectclass = $_; + my @must = $schema->must($objectclass); + foreach (@must) { + my %attr = %$_; + my $name = lc($attr{name}); + if (!$attrs{$name}) { + if ($localArgs{v}) { + print $fh "# MUST $objectclass \"$attr{desc}\" ($name)\n"; + } + elsif (!$localArgs{q}) { + print $fh "# MUST\n"; + } + if ("$name" eq "$parts[0]") { + print $fh "$name: $parts[1]\n"; + } + else { + print $fh "$name: \n"; + } + $attrs{$name} = 1; + } + } + } + if (!$localArgs{m}) { + foreach (@ARGV) { + my $objectclass = $_; + my @must = $schema->may($objectclass); + foreach (@must) { + my %attr = %$_; + my $name = lc($attr{name}); + if (!$attrs{$name}) { + if ($localArgs{v}) { + print $fh "# MAY $objectclass \"$attr{desc}\" ($name)\n"; + } + elsif (!$localArgs{q}) { + print $fh "# MAY\n"; + } + if ("$name" eq "$parts[0]") { + print $fh "$name: $parts[1]\n"; + } + else { + print $fh "$name: \n"; + } + $attrs{$name} = 1; + } + } + } + } + } + else { + print $fh "# Server did not provide a schema (do you have permission?).\n"; + print $fh "$parts[0]: $parts[1]\n"; + } + } + } + if (!$attrs{$parts[0]}) { + print $fh "$parts[0]: $parts[1]\n"; + } + + close $fh; + my $mtime = (stat($tempfile))[9]; + my $cleanup = 1; # success => unlink $tempfile by default + + system($Globals->{EDITOR}{VALUE}, $tempfile); + if ( (stat($tempfile))[9] > $mtime ) { + my $ldif = Net::LDAP::LDIF->new($tempfile, "r", onerror => undef); + while (not $ldif->eof()) { + my $entry = $ldif->read_entry(); + if ($ldif->error()) { + printf STDERR "Encountered error reading LDIF format: [[%s]]\n", $ldif->error(); + if ($localArgs{d}) { + unlink $tempfile; + print STDERR "\n"; + } + else { + print STDERR "LDIF stored in $tempfile\n\n"; + } + return undef; + } elsif (defined($entry)) { + push(@entries, $entry); + } + } + if (@entries > 0) { + foreach (@entries) { + my $result = $Globals->{LDAPCONN}{VALUE}->add($_); + if ($result->is_error) { + printf STDERR qq{LDAP Error adding entry '%s'. Code:%s. Message:%s\n}, + $_->dn, $result->code, $result->error; + # failure => keep by default + $cleanup = 0; + last; + } + push(@successes, $_); + } + } + } + else { + # no user mods => delete by default + } + + if ($cleanup) { + if ($localArgs{k}) { + print STDERR "LDIF stored in $tempfile\n\n"; + } + else { + unlink $tempfile; + } + } + else { + if ($localArgs{d}) { + unlink $tempfile; + } + else { + print STDERR "LDIF stored in $tempfile\n\n"; + } + } + + return @successes; + } + + =head3 new + + A synonym for L<create|create>. + + =cut + + sub new { + create(@_); + } + + =head3 mkdir + + A synonym for L<create|create>. + + =cut + + sub mkdir { + create(@_); + } + + =head3 remove + + B<Synopsis>: C<remove ['-a',] ['-f',] E<lt>expansionE<gt>> + + Remove entries from the directory. Unless the C<-f> parameter is given, the + command will prompt you prior to starting and will stop if an error is + encountered. You may specify C<-r>, too, as a normal part of expansion (see + L<Expansion|expansion>). If C<-a> is specified, an attempt will be made to + delete leaf entries before their parent entries. Thus, to delete an entire + subdirectory hierarchy, you might try this: + + cd 'cn=Old Directory Subtree' + remove '-ar' + cd '-' + + =cut + + sub remove { + my $localArgs = {}; + my $entries = _entriesExpander [$localArgs, 'a', 'f'], @_; + return 0 unless defined $entries; + if (@$entries < 1) { + printf STDERR "No entries removed.\n"; + return 0; + } + unless ($localArgs->{'f'}) { + return 0 unless _askBool("Delete ".scalar(@$entries)." entries?", 0); + } + if ($localArgs->{'a'}) { # sort + my %hash = map { join(',', reverse(_splitdn($_->dn, -1))) => $_ } @$entries; + foreach my $key (sort {$b cmp $a} keys %hash) { + my $entry = $hash{$key}; + my $result = $Globals->{LDAPCONN}{VALUE}->delete($entry); + if ($result->is_error) { + printf STDERR qq{LDAP error removing entry '%s'. Code:%s. Message:%s\n}, + $entry->dn, $result->code, $result->error; + return 0 unless $localArgs->{'f'}; + } + } + } + else { + foreach my $entry (@$entries) { + my $result = $Globals->{LDAPCONN}{VALUE}->delete($entry); + if ($result->is_error) { + printf STDERR qq{LDAP error removing entry '%s'. Code:%s. Message:%s\n}, + $entry->dn, $result->code, $result->error; + return 0 unless $localArgs->{'f'}; + } + } + } + return 1; + } + + =head3 rm + + A synonym for L<remove|remove>. + + =cut + + sub rm { + remove(@_); + } + + =head3 cp + + B<Synopsis>: C<cp 'E<lt>from-expansionE<gt>'|'*' 'E<lt>toE<gt>'> + + Copy an entry to a new DN or copy a set of entries to new locations in the + LDAP tree. + + C<from-expansion> will be expanded in the usual way + (see L<Expansion|expansion>), with the addition that C<*> corresponds to + the filter C<(objectclass=*)>. + + If C<to> parameter is an RDN, a single object will be copied to a new RDN within + the same level of the LDAP tree, and you will get an error if C<from-expansion> + expands to more than one object. + + If C<to> is a DN, all the objects from C<from-expansion> will be be copied to + the new location, using C<to> as a base DN and retaining their old RDNs. + This makes it convenient to copy many objects. + + B<TODO>: With C<to> being a DN, we may want to copy entire subtrees. + Currently we only copy objects as leaves. + + =cut + + sub cp($$) { + my ($from, $to) = @_; + $from = undef if ($from eq "*"); + my $localcopy = (scalar(_splitdn($to,2)) == 1); #I.e $to is an RDN. + my $entries = _entriesExpander undef, $from; + if (scalar(@$entries) != 1 && $localcopy) { + print STDERR "$from does not exist or is ambiguous.\n"; + return undef; + } + + foreach my $entry (@$entries) { + my ($oldrdn, $oldpath) = _splitdn($entry->dn, 2); + my ($newrdn) = _splitdn($to, 2); + my ($old_rdn_attr, $old_rdn_attr_val) = split("=", $oldrdn, 2); + my ($new_rdn_attr, $new_rdn_attr_val) = split("=", $newrdn, 2); + + my $newdn; + if ($localcopy) { + $newdn = "$newrdn,$oldpath"; + } else { + $newdn = "$oldrdn,$to"; + } + + $entry->dn($newdn); + + if ($localcopy) { + if ($entry->exists($old_rdn_attr)) { + $entry->delete($old_rdn_attr) + } + $entry->add($new_rdn_attr => $new_rdn_attr_val); + } + + my $result = $Globals->{LDAPCONN}{VALUE}->add($entry); + if ($result->is_error) { + printf STDERR qq{LDAP Error updating entry '%s'. Code:%s. Message:%s\n}, + $entry->dn, $result->code, $result->error; + return undef; + } + $Globals->{ENTRIES}{VALUE} = []; + } + } + + + =head2 Changing attributes + =head3 vi *************** *** 2188,2258 **** printf STDERR qq{Changed %s entries of %s. %s errors.\n}, $updcounter, scalar(@$entries), $errcounter; return(not $errcounter); - } - - - =head3 cp - - B<Synopsis>: C<cp 'E<lt>from-expansionE<gt>'|'*' 'E<lt>toE<gt>'> - - Copy an entry to a new DN or copy a set of entries to new locations in the - LDAP tree. - - C<from-expansion> will be expanded in the usual way - (see L<Expansion|expansion>), with the addition that C<*> corresponds to - the filter C<(objectclass=*)>. - - If C<to> parameter is an RDN, a single object will be copied to a new RDN within - the same level of the LDAP tree, and you will get an error if C<from-expansion> - expands to more than one object. - - If C<to> is a DN, all the objects from C<from-expansion> will be be copied to - the new location, using C<to> as a base DN and retaining their old RDNs. - This makes it convenient to copy many objects. - - B<TODO>: With C<to> being a DN, we may want to copy entire subtrees. - Currently we only copy objects as leaves. - - =cut - - sub cp($$) { - my ($from, $to) = @_; - $from = undef if ($from eq "*"); - my $localcopy = (scalar(_splitdn($to,2)) == 1); #I.e $to is an RDN. - my $entries = _entriesExpander undef, $from; - if (scalar(@$entries) != 1 && $localcopy) { - print STDERR "$from does not exist or is ambiguous.\n"; - return undef; - } - - foreach my $entry (@$entries) { - my ($oldrdn, $oldpath) = _splitdn($entry->dn, 2); - my ($newrdn) = _splitdn($to, 2); - my ($old_rdn_attr, $old_rdn_attr_val) = split("=", $oldrdn, 2); - my ($new_rdn_attr, $new_rdn_attr_val) = split("=", $newrdn, 2); - - my $newdn; - if ($localcopy) { - $newdn = "$newrdn,$oldpath"; - } else { - $newdn = "$oldrdn,$to"; - } - - $entry->dn($newdn); - - if ($localcopy) { - if ($entry->exists($old_rdn_attr)) { - $entry->delete($old_rdn_attr) - } - $entry->add($new_rdn_attr => $new_rdn_attr_val); - } - - my $result = $Globals->{LDAPCONN}{VALUE}->add($entry); - if ($result->is_error) { - printf STDERR qq{LDAP Error updating entry '%s'. Code:%s. Message:%s\n}, - $entry->dn, $result->code, $result->error; - return undef; - } - $Globals->{ENTRIES}{VALUE} = []; - } } --- 2525,2528 ---- |
From: <j-d...@us...> - 2003-12-13 10:22:52
|
Update of /cvsroot/ldapsh/ldapsh In directory sc8-pr-cvs1:/tmp/cvs-serv30622 Modified Files: ldapsh Log Message: * Revamped tab-completion for 'cd' commands and "expansion" commands. Improvements include: - 'cd' commands now match only DNs, not attributes. - "expansion" commands can cope with partially-written LDAP filters. * 'redir' and 'sink' now auto-quote their arguments. Index: ldapsh =================================================================== RCS file: /cvsroot/ldapsh/ldapsh/ldapsh,v retrieving revision 1.33 retrieving revision 1.34 diff -C2 -d -r1.33 -r1.34 *** ldapsh 11 Dec 2003 12:41:51 -0000 1.33 --- ldapsh 13 Dec 2003 10:22:48 -0000 1.34 *************** *** 621,692 **** } - ######################################### - if (0) { - ######################################### - ### Variable Completion ### - my $str1 = substr($line, 0, $end); - my $str = reverse($str1); - - my $AccoladeCounter = 0; - my $AccoladeFound = 0; - my $Found = 0; - my $i; - my $word = ''; - my $wordCompleted = 0; - my $beforeWord = ''; - my $beforeWordCompleted = 0; - for ($i = 0; $i < length($str); $i++) { - $_ = substr($str, $i, 1); - last unless /[][{}\$@%\w>-]/; - - unless ($wordCompleted) { - if (/[\w-]/) { - $word = "$_$word"; - } else { - $wordCompleted = 1; - } - } - - if ($wordCompleted) { - unless ($beforeWordCompleted) { - if (/[[{>-]/) { - $beforeWord = "$_$beforeWord"; - } else { - $beforeWordCompleted = 1; - } - } - } - - $AccoladeCounter++, $AccoladeFound = 1, next if /[{[]/; - $AccoladeCounter--, next if /[]}]/; - - if (/[\$%@]/) { - if (($AccoladeFound and $AccoladeCounter == 1) or (not $AccoladeFound and $AccoladeCounter == 0)) { - $Found = 1; - last; - } - } - } - - if ($Found) { - my $FoundStr = substr($str1, length($str1)-$i-1); - my $prefix = substr($FoundStr, 0, length($FoundStr)-length($word)-length($beforeWord)); - _debug("Found: '$FoundStr'", $word, $beforeWord, $prefix); - - if ($beforeWord eq '') { - } - } - - ######################################### - } - ######################################### - ### Parameter Completion ### my $line2 = $line; $line2 =~ s/^\s+//; my ($cmd, $rest) = split(/\s+/, $line2, 2); ! if ($cmd =~ /^(cd|acd|setdn|pushd|cat|vi|ls|list|dump|ldif|search|cp)$/) { # DN Completion return _cdCommandCompletion(@_); } elsif ($cmd =~ /^(help|which)$/) { # Command Completion --- 621,634 ---- } ### Parameter Completion ### my $line2 = $line; $line2 =~ s/^\s+//; my ($cmd, $rest) = split(/\s+/, $line2, 2); ! if ($cmd =~ /^(cd|acd|setdn|pushd)$/) { # DN Completion return _cdCommandCompletion(@_); + } elsif ($cmd =~ /^(cat|vi|ls|list|csv|dump|ldif|search|cp)$/) { + # Filter Completion + return _filterCommandCompletion(@_); } elsif ($cmd =~ /^(help|which)$/) { # Command Completion *************** *** 727,742 **** my @parts2 = reverse(@parts1); ! my $BaseDN = join(',', @parts2, $CWD); ! my $attr; ! $attr = $1 if $partToComplete =~ /^([^=]+)=/; ! ! if (defined $attr) { ! return _entryDNCompletion($prefix, $attr, $partToComplete, $BaseDN); ! } else { return _attributeNamesDNCompletion($prefix, $partToComplete, $BaseDN); } } sub _attributeEditCompletion{ my ($text, $line, $start, $end) = @_; --- 669,754 ---- my @parts2 = reverse(@parts1); ! my $BaseDN = join(',', @parts2, $Globals->{CWD}{VALUE}); ! #$TermAttribs->{completion_append_character} = "\0"; ! if ($partToComplete =~ m/=/) { ! return _RDNCompletion($prefix, $partToComplete, $BaseDN); ! } ! else { return _attributeNamesDNCompletion($prefix, $partToComplete, $BaseDN); } } + sub _attributeNamesDNCompletion($$$) { + my ($prefix, $partToComplete, $BaseDN) = @_; + + my $result = _searchWEC( + base => $BaseDN, + scope => 'one', + attrs => [], + filter => "(objectclass=*)" + ); + return undef unless defined($result); + + if (_isReallyLDAPError($result->code)) { + if ($result->code == Net::LDAP::Constant::LDAP_NO_SUCH_OBJECT()) { + return undef; + } else { + printf STDERR "Cannot search attribute names. LDAP Error no %s (%s)\n", $result->code, $result->error; + return undef; + } + } else { + my @entries = $result->entries; + my @possible_entries = map {my $a = rdn($_->dn); $a =~ s/=.*/=/; $a;} @entries; + @possible_entries = grep {/^$partToComplete/i} @possible_entries; + return undef unless scalar(@possible_entries); + my $common = _maxCommon(@possible_entries); + if ($common eq $possible_entries[0]) { + # move immediately to the RDNs + $partToComplete = $possible_entries[0]; + @possible_entries = map {rdn($_->dn)} @entries; + @possible_entries = grep {/^$partToComplete/i} @possible_entries; + return undef unless scalar(@possible_entries); + } + if ($prefix) { + map {$_ = "${prefix},$_"} @possible_entries; + $common = "${prefix},${common}"; + } + return $common, @possible_entries; + } + } + + sub _RDNCompletion($$$) { + my ($prefix, $partToComplete, $BaseDN) = @_; + + my $result = _searchWEC( + base => $BaseDN, + scope => 'one', + attrs => [], + filter => "$partToComplete*" + ); + return undef unless defined($result); + + if (_isReallyLDAPError($result->code)) { + if ($result->code == Net::LDAP::Constant::LDAP_NO_SUCH_OBJECT()) { + return undef; + } else { + printf STDERR "Cannot search attribute names. LDAP Error no %s (%s)\n", $result->code, $result->error; + return undef; + } + } else { + my @entries = $result->entries; + my @possible_entries = map {rdn($_->dn)} @entries; + @possible_entries = grep {/^$partToComplete/i} @possible_entries; + return undef unless scalar(@possible_entries); + my $common = _maxCommon(@possible_entries); + if ($prefix) { + map {$_ = "${prefix},$_"} @possible_entries; + $common = "${prefix},${common}"; + } + return $common, @possible_entries; + } + } + sub _attributeEditCompletion{ my ($text, $line, $start, $end) = @_; *************** *** 778,815 **** } - sub _attributeNamesDNCompletion($$$) { - my ($prefix, $partToComplete, $BaseDN) = @_; - $TermAttribs->{completion_append_character} = "\0"; - - my $result = _searchWEC( - base => $BaseDN, - scope => 'one', - attrs => [], - filter => "(objectclass=*)" - ); - return unless defined($result); - - if (_isReallyLDAPError($result->code)) { - if ($result->code == Net::LDAP::Constant::LDAP_NO_SUCH_OBJECT()) { - return undef; - } else { - printf STDERR "Cannot search attribute names. LDAP Error no %s (%s)\n", $result->code, $result->error; - return undef; - } - } else { - my @entries = $result->entries; - my @possible_entries = map {my $a = rdn($_->dn); $a =~ s/=.*/=/; $a;} @entries; - @possible_entries = grep {/^$partToComplete/i} @possible_entries; - return undef unless scalar(@possible_entries); - my $common = _maxCommon(@possible_entries); - if ($prefix) { - map {$_ = "${prefix},$_"} @possible_entries; - $common = "${prefix},${common}"; - } - return $common, @possible_entries; - } - } - - sub _maxCommon { return '' unless scalar(@_); --- 790,793 ---- *************** *** 824,838 **** } ! sub _entryDNCompletion($$$$) { ! my ($prefix, $attr, $partToComplete, $BaseDN) = @_; my $result = _searchWEC( ! base => $BaseDN, scope => 'one', attrs => [$attr], ! filter => "$partToComplete*" ); ! return unless defined($result); if (_isReallyLDAPError($result->code)) { --- 802,823 ---- } + sub _filterCommandCompletion($$$$) { + my ($text, $line, $start, $end) = @_; ! _bindneeded() or return undef; ! ! $TermAttribs->{completion_append_character} = '\0'; ! ! # match the 'filtertype' portion of an LDAP filter (RFC 2254 and RFC 2251) ! my ($prefix, $attr, $extra, $partToComplete) = $text =~ m/(^|^.*\()([a-z][a-z0-9-]*)((?:;[a-z0-9-]*)?(?:=|~=|>=|<=))(.*)$/i; ! return undef unless defined($extra); my $result = _searchWEC( ! base => $Globals->{CWD}{VALUE}, scope => 'one', attrs => [$attr], ! filter => "$attr=$partToComplete*" ); ! return undef unless defined($result); if (_isReallyLDAPError($result->code)) { *************** *** 847,856 **** my @entries = $result->entries; return undef unless scalar(@entries); ! my @possible_entries = map {sprintf("%s=%s", $attr, scalar($_->get_value($attr)))} @entries; my $common = _maxCommon(@possible_entries); - if ($prefix) { - map {$_ = "${prefix},$_"} @possible_entries; - $common = "${prefix},${common}"; - } return $common, @possible_entries; } --- 832,837 ---- my @entries = $result->entries; return undef unless scalar(@entries); ! my @possible_entries = map {$prefix.$attr.$extra.scalar($_->get_value($attr))} @entries; # Bug: only uses first attribute value. my $common = _maxCommon(@possible_entries); return $common, @possible_entries; } *************** *** 2599,2603 **** # complaining that "ou=Users" it's an illegal variable set, and # that uses a bareword.... ! s/^(cd|acd|setdn|pushd|lcd|help|which)\s+((?:[^'"].*)?[^'"])$/$1 "$2"/; # The line below will quote some barewords such as "-l", "-a" etc... --- 2580,2584 ---- # complaining that "ou=Users" it's an illegal variable set, and # that uses a bareword.... ! s/^(cd|acd|setdn|pushd|lcd|help|which|redir|sink)\s+((?:[^'"].*)?[^'"])$/$1 "$2"/; # The line below will quote some barewords such as "-l", "-a" etc... |
From: <j-d...@us...> - 2003-12-11 12:41:54
|
Update of /cvsroot/ldapsh/ldapsh In directory sc8-pr-cvs1:/tmp/cvs-serv23478 Modified Files: ldapsh Log Message: * Improved error handling in _bindneeded. Index: ldapsh =================================================================== RCS file: /cvsroot/ldapsh/ldapsh/ldapsh,v retrieving revision 1.32 retrieving revision 1.33 diff -C2 -d -r1.32 -r1.33 *** ldapsh 11 Dec 2003 12:41:07 -0000 1.32 --- ldapsh 11 Dec 2003 12:41:51 -0000 1.33 *************** *** 404,408 **** sub _bindneeded { if ($Globals->{LDAPCONN}{VALUE}) { ! unless($Globals->{LDAPCONN}{VALUE}{net_ldap_socket}->connected()) { print STDERR "\nConnection lost. Trying to reconnect.\n"; undef $Globals->{_EFFECTIVECONNPARAMS}{VALUE}{BINDDN}; --- 404,408 ---- sub _bindneeded { if ($Globals->{LDAPCONN}{VALUE}) { ! unless($Globals->{LDAPCONN}{VALUE}->socket() && $Globals->{LDAPCONN}{VALUE}->socket()->connected()) { print STDERR "\nConnection lost. Trying to reconnect.\n"; undef $Globals->{_EFFECTIVECONNPARAMS}{VALUE}{BINDDN}; |