File Coverage

blib/lib/Net/LDAP/Express.pm
Criterion Covered Total %
statement 29 176 16.4
branch 1 76 1.3
condition 1 11 9.0
subroutine 9 22 40.9
pod 9 9 100.0
total 49 294 16.6


line stmt bran cond sub pod time code
1             package Net::LDAP::Express;
2              
3 2     2   111771 use 5.006;
  2         7  
  2         84  
4 2     2   13 use strict;
  2         4  
  2         67  
5 2     2   11 use warnings;
  2         16  
  2         110  
6              
7             our $VERSION = '0.12';
8              
9 2     2   10 use Carp ;
  2         3  
  2         220  
10              
11 2     2   10 use base 'Net::LDAP' ;
  2         3  
  2         2307  
12 2     2   640786 use constant DEBUG => 0 ;
  2         6  
  2         7618  
13              
14             # Preloaded methods go here.
15             sub new {
16 0     0 1 0 my $class = shift ;
17 0         0 my %args = @_ ;
18              
19 0 0       0 croak "Not an object method" if ref $class ;
20              
21 0         0 my %myParms = _new_parms() ;
22 0         0 my @myParmNames = keys %myParms ;
23 0         0 foreach my $parm (grep $myParms{$_} eq 'req',@myParmNames) {
24 0 0       0 croak "$parm parameter is required" unless $args{$parm} ;
25             }
26              
27 0         0 my $host = $args{host} ;
28              
29             # Keep parameters that are local to this class, and pass to
30             # Net::LDAP::new all the rest
31 0         0 my %localparms ;
32 0         0 @localparms{@myParmNames} =
33             delete @args{@myParmNames} ;
34              
35             # Test for onlyattrs not overlapping with searchextras; in
36             # case they do, warn
37 0 0 0     0 if (defined $localparms{onlyattrs} and
38             defined $localparms{searchextras}) {
39 0 0       0 carp "Useless use of parameter onlyattrs with searchextras" if $^W ;
40             }
41              
42             # try connection
43 0         0 my $ldap = $class->SUPER::new($host,%args) ;
44 0 0       0 croak "Cannot connect to $host: $@" if $@ ;
45              
46             # bind if necessary
47 0 0       0 if ($localparms{bindDN}) {
48 0         0 my @bindArgs = ($localparms{bindDN}) ;
49 0 0       0 push @bindArgs,('password',$localparms{bindpw})
50             if defined $localparms{bindpw} ;
51 0         0 my $msg = $ldap->bind(@bindArgs) ;
52 0 0       0 if ($msg->is_error) {
53 0         0 $ldap->_seterr($msg) ;
54 0         0 croak "Cannot bind: ".$msg->error ;
55             }
56             }
57              
58             # Prepare object and return
59             ##! I should use accessors here... maybe building a code string
60             ##! and then passing it to eval.
61 0         0 while (my ($parm,$value) = each %localparms) {
62 0         0 $ldap->{"net_ldap_express_$parm"} = $value ;
63             }
64 0         0 return $ldap ;
65             }
66              
67             {
68             my @lasterr = (0,'') ;
69             my %errcache = @lasterr ;
70 0     0 1 0 sub error { return $lasterr[1] }
71 0     0 1 0 sub errcode { return $lasterr[0] }
72             sub _seterr {
73 0     0   0 my $ldap = shift ;
74             # _seterr sets error code an name in the error cache
75             # If it is passed one argument, then it should be an object in the
76             # Net::LDAP::Message class
77             # If it is passed two arguments, then they are an error code and
78             # an error name respectively
79              
80             # Redefine @_ if $_[0] is a Net::LDAP::Message
81 0 0       0 if (ref $_[0]) {
82 0         0 my $msg = shift ;
83 0         0 @_ = ($msg->code,$msg->error) ;
84             }
85             # Get error code
86 0         0 $lasterr[0] = shift ;
87              
88             # Update cache, if needed
89 0 0       0 $errcache{$lasterr[0]} = shift unless exists $errcache{$lasterr[0]} ;
90              
91             # Get error message from cache
92 0         0 $lasterr[1] = $errcache{$lasterr[0]} ;
93              
94 0 0       0 carp "LDAP ERROR @lasterr" if $^W;
95              
96 0         0 return @lasterr ;
97             }
98             }
99              
100             sub add_many {
101 0     0 1 0 my $ldap = shift ;
102 0         0 my @parms = @_ ;
103 0         0 my $msg ;
104              
105             # Iterate over the entries, return those that succeeded
106             my @success ;
107 0         0 while (my $e = shift @parms) {
108 0         0 eval { $e->isa('Net::LDAP::Entry') } ;
  0         0  
109 0 0       0 if ($@) {
110 0 0       0 carp "Invalid input: $@" if $^W ;
111 0         0 $ldap->_seterr(-1,'Invalid input') ;
112 0         0 return \@success ;
113             }
114              
115 0         0 $msg = $ldap->SUPER::add($e) ;
116 0 0       0 if ($msg->is_error) {
117 0         0 $ldap->_seterr($msg) ;
118 0         0 return \@success ;
119             }
120 0         0 push @success,$e ;
121             }
122              
123 0         0 $ldap->_seterr(0) ;
124 0         0 return \@success ;
125             }
126              
127             sub delete_many {
128 0     0 1 0 my $ldap = shift ;
129 0         0 my @parms = @_ ;
130 0         0 my $msg ;
131              
132             my @success ;
133 0         0 while (my $e = shift @parms) {
134 0         0 eval { $e->isa('Net::LDAP::Entry') } ;
  0         0  
135 0 0       0 if ($@) {
136 0 0       0 carp "Invalid input: $@" if $^W ;
137 0         0 $ldap->_seterr(-1,'Invalid input') ;
138 0         0 return \@success ;
139             }
140              
141 0         0 $msg = $ldap->SUPER::delete($e) ;
142 0 0       0 if ($msg->is_error) {
143 0         0 $ldap->_seterr($msg) ;
144 0         0 return \@success ;
145             }
146              
147 0         0 push @success,$e ;
148             }
149              
150 0         0 $ldap->_seterr(0) ;
151 0         0 return \@success ;
152             }
153              
154             sub search {
155 0     0 1 0 my $ldap = shift ;
156 0         0 my $query ;
157              
158             # If search is passed an odd number of parameters, we assume that
159             # the first is a query string; anyway, we'll override it if a
160             # "filter" parameter is specified
161 0 0       0 if (@_%2) {
162 0         0 $query = shift ;
163             }
164              
165             # Load defaults from _makesearchparms, override them with the values
166             # in @_.
167 0         0 my %parms = ($ldap->_makesearchparms,@_) ;
168              
169             # What about filters?
170 0   0     0 $parms{filter} ||= $ldap->_makefilter($query) ;
171              
172 0         0 return $ldap->SUPER::search(%parms) ;
173             }
174              
175             sub simplesearch {
176 0     0 1 0 my $ldap = shift ;
177 0         0 my ($query) = @_ ;
178 0         0 my %parms = $ldap->_makesearchparms;
179              
180             # Set filter
181 0         0 $parms{filter} = $ldap->_makefilter($query) ;
182              
183 0         0 my $msg = $ldap->SUPER::search(%parms) ;
184 0 0       0 if ($msg->is_error) {
185 0         0 $ldap->_seterr($msg) ;
186 0         0 return undef ;
187             }
188              
189 0         0 $ldap->_seterr(0) ;
190              
191 0         0 return $ldap->_sort_by ?
192 0 0       0 [$msg->sorted(@{$ldap->_sort_by})] :
193             [$msg->entries] ;
194             }
195              
196              
197             sub rename {
198 0     0 1 0 my $ldap = shift ;
199 0         0 my ($e,$rdn) = @_ ;
200              
201 0         0 my $msg = $ldap->moddn($e,
202             newrdn => $rdn,
203             deleteoldrdn => 'yes') ;
204 0 0       0 if ($msg->is_error) {
205 0         0 $ldap->_seterr($msg) ;
206 0         0 return undef ;
207             }
208              
209 0         0 return $ldap->_seterr(0) ;
210 0         0 return $e ;
211             }
212              
213              
214             sub update {
215 0     0 1 0 my $ldap = shift ;
216 0         0 my @parms = @_ ;
217 0         0 my @success ;
218             my $msg ;
219              
220 0         0 while (my $e = shift @parms) {
221 0         0 eval { $e->isa('Net::LDAP::Entry') } ;
  0         0  
222 0 0       0 if ($@) {
223 0 0       0 carp "Invalid input: $@" if $^W ;
224 0         0 $ldap->_seterr(-1,'Invalid input') ;
225 0         0 return \@success ;
226             }
227              
228 0         0 $msg = $e->update($ldap) ;
229              
230 0 0       0 if ($msg->is_error) {
231             # Don't complain if error code is 82
232             # (that means: the entry hasn't been modified)
233 0 0       0 unless ($msg->code == 82) {
234 0         0 $ldap->_seterr($msg) ;
235 0         0 return \@success ;
236             }
237             }
238              
239 0         0 push @success,$e ;
240             }
241              
242 0         0 $ldap->_seterr(0) ;
243 0         0 return \@success ;
244             }
245              
246              
247             ########################################################################
248             # These methods should be considered PRIVATE!
249             BEGIN {
250             sub _new_parms {
251             return (
252 2     2   29 host => 'req',
253             base => 'req',
254             searchattrs => 'req',
255             bindDN => 'opt',
256             bindpw => 'opt',
257             searchbool => 'opt',
258             searchmatch => 'opt',
259             searchextras => 'opt',
260             onlyattrs => 'opt',
261             sort_by => 'opt',
262             )
263             }
264              
265 2 50 50 2   19 carp __PACKAGE__.": Dynamically building accessors at compile time"
266             if $^W and DEBUG ;
267              
268             {
269 2     2   360 no strict 'refs' ;
  2         5  
  2         299  
  2         4  
270 2         7 my %myParms = _new_parms() ;
271 2         11 foreach my $attr (keys %myParms) {
272 20         42 my $subname = "_$attr" ;
273 20         53 my $parm = "net_ldap_express_$attr" ;
274             *$subname = sub {
275 0     0   0 my $ldap = shift ;
276 0 0       0 return $ldap->{$parm} if @_ == 0 ;
277 0         0 return $ldap->{$parm} = shift ;
278 20         1535 } ;
279             }
280             }
281             }
282              
283             sub _makefilter {
284 0     0     my $ldap = shift ;
285 0           my ($query) = @_ ;
286              
287 0 0         my $bool = $ldap->_searchbool ? $ldap->_searchbool : '|' ;
288 0           my $match = $ldap->_searchmatch ;
289              
290 0           my $op = '~=' ;
291              
292 0 0         if ($match) {
293 0 0 0       $op = '=' if $match eq 'substr' or $match eq 'exact' ;
294 0 0         $query = qq/*$query*/ if $match eq 'substr';
295             }
296              
297 0           my @attrs = @{$ldap->_searchattrs} ;
  0            
298              
299 0           my $filter ;
300 0 0         if (@attrs == 1) {
301 0           $filter = qq/($attrs[0]$op$query)/ ;
302             } else {
303 0           $filter = "($bool".
304             join("",map("($_$op$query)",@attrs)).
305             ")" ;
306             }
307              
308             #carp "Search filter is $filter" if DEBUG ;
309 0           return $filter ;
310             }
311              
312             sub _makesearchparms {
313 0     0     my $ldap = shift ;
314              
315 0 0         unless (exists $ldap->{net_ldap_express_searchparms}) {
316 0           my %parms ;
317              
318             # Set search base
319 0           $parms{base} = $ldap->_base ;
320              
321             # Retrieve onlyattrs, or all; add searchextras if needed
322 0 0         my $attrs = $ldap->_onlyattrs ? $ldap->_onlyattrs : ['*'] ;
323              
324 0 0         if (my $extras = $ldap->_searchextras) {
325 0           push @$attrs,@$extras ;
326             }
327              
328             # Now what if one specifies also sort_by, and the attributes are not
329             # in $attrs? The sorting would fail... First, let's see if the
330             # first element of @$attrs is a '*', in that case just skip
331 0 0         if (my $sortattrs = $ldap->_sort_by) {
332 0 0         unless ($attrs->[0] eq '*') {
333             # We have to compare each @$sortattrs element with the elements
334             # of @$attrs; better to have some precompiled patterns handy.
335 0           my @qrattrs = map qr/^$_$/i,@$attrs ;
336 0           foreach my $attr (@$sortattrs) {
337 0 0         push @$attrs,$attr unless grep $attr =~ $_ ,@qrattrs ;
338             }
339             }
340             }
341              
342             # Now we can assign the resulting $attrs to $parms{attrs}...
343 0           $parms{attrs} = $attrs ;
344              
345 0           $ldap->{net_ldap_express_searchparms} = \%parms ;
346             }
347              
348 0           return %{$ldap->{net_ldap_express_searchparms}} ;
  0            
349             }
350              
351              
352             1;
353             __END__