Hi,

I have implemented LDAP Content Synchronization Operation (rfc4533) in
perl-ldap (See the attached patch). This is used by the OpenLDAP
server and provide features similar to Persistent Searches in a more
consistent way.

This is my first try in this code, any feedback is welcome.
I don't know how to handle the Sync Info Message which is an LDAP
Intermediate Response Message (see 2.5 in RFC). perl-ldap doesn't
seems to support intermediate responses in response to LDAP::Search.
What is the way to correct this ?

thanks

Mathieu Parent
diff -urN --exclude=blib --exclude=debian --exclude '*~' libnet-ldap-perl-0.36-old/lib/Net/LDAP/ASN.pm libnet-ldap-perl-0.36/lib/Net/LDAP/ASN.pm
--- libnet-ldap-perl-0.36-old/lib/Net/LDAP/ASN.pm	2008-04-21 17:11:06.000000000 +0200
+++ libnet-ldap-perl-0.36/lib/Net/LDAP/ASN.pm	2008-06-14 14:33:55.000000000 +0200
@@ -1,7 +1,7 @@
 
 package Net::LDAP::ASN;
 
-$VERSION = "0.06";
+$VERSION = "0.07";
 
 use Convert::ASN1;
 
@@ -440,6 +440,56 @@
 	objectName      LDAPDN,
 	attributes      PartialAttributeList }
     
+    -- RFC-4533 LDAP Content Synchronization Operation
+
+    syncUUID ::= OCTET STRING -- (SIZE(16))
+
+    syncCookie ::= OCTET STRING
+
+    syncRequestValue ::= SEQUENCE {
+        mode ENUMERATED {
+            -- 0 unused
+            refreshOnly       (1),
+            -- 2 reserved
+            refreshAndPersist (3)
+        }
+        cookie     syncCookie OPTIONAL,
+        reloadHint BOOLEAN -- DEFAULT FALSE
+    }
+
+    syncStateValue ::= SEQUENCE {
+        state ENUMERATED {
+            present (0),
+            add (1),
+            modify (2),
+            delete (3)
+        }
+        entryUUID syncUUID,
+        cookie    syncCookie OPTIONAL
+    }
+
+    syncDoneValue ::= SEQUENCE {
+        cookie          syncCookie OPTIONAL,
+        refreshDeletes  BOOLEAN -- DEFAULT FALSE
+    }
+
+    syncInfoValue ::= CHOICE {
+          newcookie      [0] syncCookie,
+          refreshDelete  [1] SEQUENCE {
+              refreshDeleteCookie         syncCookie OPTIONAL,
+              refreshDeleteDone    BOOLEAN -- DEFAULT TRUE
+          }
+          refreshPresent [2] SEQUENCE {
+              refreshDeletecookie         syncCookie OPTIONAL,
+              refreshDeleteDone    BOOLEAN -- DEFAULT TRUE
+          }
+          syncIdSet      [3] SEQUENCE {
+              cookie         syncCookie OPTIONAL,
+              refreshDeletes BOOLEAN, -- DEFAULT FALSE
+              syncUUIDs      SET OF syncUUID
+          }
+    }
+
 LDAP_ASN
 
 1;
diff -urN --exclude=blib --exclude=debian --exclude '*~' libnet-ldap-perl-0.36-old/lib/Net/LDAP/Constant.pm libnet-ldap-perl-0.36/lib/Net/LDAP/Constant.pm
--- libnet-ldap-perl-0.36-old/lib/Net/LDAP/Constant.pm	2008-04-21 17:11:06.000000000 +0200
+++ libnet-ldap-perl-0.36/lib/Net/LDAP/Constant.pm	2008-06-14 15:57:15.000000000 +0200
@@ -4,7 +4,7 @@
 
 package Net::LDAP::Constant;
 
-$VERSION = "0.06";
+$VERSION = "0.07";
 
 use Carp;
 
@@ -481,6 +481,14 @@
 
 =item LDAP_CONTROL_ASSERTION (1.3.6.1.1.12)
 
+=item LDAP_CONTROL_SYNC (1.3.6.1.4.1.4203.1.9.1.1)
+
+=item LDAP_CONTROL_SYNC_STATE (1.3.6.1.4.1.4203.1.9.1.2)
+
+=item LDAP_CONTROL_SYNC_DONE (1.3.6.1.4.1.4203.1.9.1.3)
+
+=item LDAP_SYNC_INFO (1.3.6.1.4.1.4203.1.9.1.4)
+
 =back
 
 =head2 Control constants
@@ -523,6 +531,42 @@
 
 The new password was used too recently.
 
+=item LDAP_SYNC_NONE (0) [LDAP_CONTROL_SYNC]
+
+=item LDAP_SYNC_REFRESH_ONLY (1) [LDAP_CONTROL_SYNC]
+
+=item LDAP_SYNC_RESERVED (2) [LDAP_CONTROL_SYNC]
+
+=item LDAP_SYNC_REFRESH_AND_PERSIST (3) [LDAP_CONTROL_SYNC]
+
+=item LDAP_SYNC_REFRESH_PRESENTS (0) [LDAP_SYNC_INFO]
+
+=item LDAP_SYNC_REFRESH_DELETES (1) [LDAP_SYNC_INFO]
+
+=item LDAP_TAG_SYNC_NEW_COOKIE (0x80) [LDAP_SYNC_INFO]
+
+=item LDAP_TAG_SYNC_REFRESH_DELETE (0xa1) [LDAP_SYNC_INFO]
+
+=item LDAP_TAG_SYNC_REFRESH_PRESENT (0xa2) [LDAP_SYNC_INFO]
+
+=item LDAP_TAG_SYNC_ID_SET (0xa3) [LDAP_SYNC_INFO]
+
+=item LDAP_TAG_SYNC_COOKIE (0x04) [LDAP_SYNC_INFO]
+
+=item LDAP_TAG_REFRESHDELETES (0x01) [LDAP_SYNC_INFO]
+
+=item LDAP_TAG_REFRESHDONE (0x01) [LDAP_SYNC_INFO]
+
+=item LDAP_TAG_RELOAD_HINT (0x01) [LDAP_CONTROL_SYNC]
+
+=item LDAP_SYNC_PRESENT (0) [LDAP_CONTROL_SYNC_STATE]
+
+=item LDAP_SYNC_ADD (1) [LDAP_CONTROL_SYNC_STATE]
+
+=item LDAP_SYNC_MODIFY (2) [LDAP_CONTROL_SYNC_STATE]
+
+=item LDAP_SYNC_DELETE (3) [LDAP_CONTROL_SYNC_STATE]
+
 =back
 
 =head2 Extension OIDs
diff -urN --exclude=blib --exclude=debian --exclude '*~' libnet-ldap-perl-0.36-old/lib/Net/LDAP/Control/SyncDone.pm libnet-ldap-perl-0.36/lib/Net/LDAP/Control/SyncDone.pm
--- libnet-ldap-perl-0.36-old/lib/Net/LDAP/Control/SyncDone.pm	1970-01-01 01:00:00.000000000 +0100
+++ libnet-ldap-perl-0.36/lib/Net/LDAP/Control/SyncDone.pm	2008-06-14 17:50:59.000000000 +0200
@@ -0,0 +1,152 @@
+# Copyright (c) 2008 Mathieu Parent <[EMAIL PROTECTED]>. All rights reserved.
+# This program is free software; you can redistribute it and/or
+# modify it under the same terms as Perl itself.
+
+package Net::LDAP::Control::SyncDone;
+
+use vars qw(@ISA $VERSION);
+use Net::LDAP::Control;
+
[EMAIL PROTECTED] = qw(Net::LDAP::Control);
+$VERSION = "0.01";
+
+use Net::LDAP::ASN qw(syncDoneValue);
+use strict;
+
+# use some kind of hack here:
+# - calling the control without args means: response,
+# - giving an argument: means: request
+sub init {
+  my($self) = @_;
+
+  delete $self->{asn};
+
+  unless (exists $self->{value}) {
+    $self->{asn} = {
+      cookie => $self->{cookie} || '',
+      refreshDeletes   => $self->{refreshDeletes} || '0',
+    };
+  }
+
+  $self;
+}
+
+sub cookie {
+  my $self = shift;
+  $self->{asn} ||= $syncDoneValue->decode($self->{value});
+  if (@_) {
+    delete $self->{value};
+    return $self->{asn}{cookie} = shift || 0;
+  }
+  $self->{asn}{cookie};
+}
+
+sub refreshDeletes {
+  my $self = shift;
+  $self->{asn} ||= $syncDoneValue->decode($self->{value});
+  if (@_) {
+    delete $self->{value};
+    return $self->{asn}{refreshDeletes} = shift || 0;
+  }
+  $self->{asn}{refreshDeletes};
+}
+
+sub value {
+  my $self = shift;
+
+  exists $self->{value}
+    ? $self->{value}
+    : $self->{value} = $syncDoneValue->encode($self->{asn});
+}
+
+1;
+
+
+__END__
+
+=head1 NAME
+
+Net::LDAP::Control::SyncDone - LDAPv3 Sync Done control object
+
+=head1 SYNOPSIS
+
+ use Net::LDAP;
+ use Net::LDAP::Control::SyncRequest;
+ use Net::LDAP::Constant qw(
+  LDAP_SYNC_REFRESH_ONLY
+  LDAP_SYNC_REFRESH_AND_PERSIST
+  LDAP_SUCCESS );
+
+ $ldap = Net::LDAP->new( "ldap.mydomain.eg" );
+
+ $req = Net::LDAP::Control::SyncRequest->new( mode => LDAP_SYNC_REFRESH_ONLY );
+ my $mesg = $ldap->search(base=> 'dc=mydomain,dc='eg',
+                          scope    => 'sub',
+                          control  => [ $req ],
+                          callback => \&searchCallback, # call for each entry
+                          filter   => "(objectClass=*)",
+                          attrs    => [ '*']);
+ sub searchCallback {
+   my $message = shift;
+   my $entry = shift;
+   my @controls = $message->control;
+
+   if($controls[0]->isa('Net::LDAP::Control::SyncState')) {
+     print "Received Sync State Control\n";
+     print $entry->dn()."\n";
+     print 'State: '.$controls[0]->state."\n".', entryUUID: '.$controls[0]->entryUUID.', cookie: '.$controls[0]->cookie;
+   } elsif($controls[0]->isa('Net::LDAP::Control::SyncDone')) {
+     print "Received Sync Done Control\n";
+     print 'Cookie: '.$controls[0]->cookie.', refreshDeletes: '.$controls[0]->refreshDeletes;
+   }
+ }
+
+=head1 DESCRIPTION
+
+C<Net::LDAP::Control::SyncDone> provides an interface for the creation and
+manipulation of objects that represent the C<Sync Request Control> as described
+by RFC 4533.
+
+=head1 CONSTRUCTOR ARGUMENTS
+
+In addition to the constructor arguments described in
+L<Net::LDAP::Control> the following are provided.
+
+=over 4
+
+=item cookie
+
+=item refreshDeletes
+
+=back
+
+=head1 METHODS
+
+As with L<Net::LDAP::Control> each constructor argument
+described above is also avaliable as a method on the object which will
+return the current value for the attribute if called without an argument,
+and set a new value for the attribute if called with an argument.
+
+=head1 SEE ALSO
+
+L<Net::LDAP>,
+L<Net::LDAP::Control>,
+L<Net::LDAP::Control::SyncRequest>,
+L<Net::LDAP::Control::SyncState>,
+http://www.ietf.org/rfc/rfc4533.txt
+
+=head1 AUTHOR
+
+Mathieu Parent E<lt>[EMAIL PROTECTED]<gt>
+
+Please report any bugs, or post any suggestions, to the perl-ldap mailing list
+E<lt>[EMAIL PROTECTED]<gt>
+
+=head1 COPYRIGHT
+
+Copyright (c) 2008 Mathieu Parent. All rights reserved. This program is
+free software; you can redistribute it and/or modify it under the same
+terms as Perl itself.
+
+=cut
+
diff -urN --exclude=blib --exclude=debian --exclude '*~' libnet-ldap-perl-0.36-old/lib/Net/LDAP/Control/SyncRequest.pm libnet-ldap-perl-0.36/lib/Net/LDAP/Control/SyncRequest.pm
--- libnet-ldap-perl-0.36-old/lib/Net/LDAP/Control/SyncRequest.pm	1970-01-01 01:00:00.000000000 +0100
+++ libnet-ldap-perl-0.36/lib/Net/LDAP/Control/SyncRequest.pm	2008-06-14 17:50:52.000000000 +0200
@@ -0,0 +1,165 @@
+# Copyright (c) 2008 Mathieu Parent <[EMAIL PROTECTED]>. All rights reserved.
+# This program is free software; you can redistribute it and/or
+# modify it under the same terms as Perl itself.
+
+package Net::LDAP::Control::SyncRequest;
+
+use vars qw(@ISA $VERSION);
+use Net::LDAP::Control;
+
[EMAIL PROTECTED] = qw(Net::LDAP::Control);
+$VERSION = "0.01";
+
+use Net::LDAP::ASN qw(syncRequestValue);
+use strict;
+
+# use some kind of hack here:
+# - calling the control without args means: response,
+# - giving an argument: means: request
+sub init {
+  my($self) = @_;
+
+  delete $self->{asn};
+
+  unless (exists $self->{value}) {
+    $self->{asn} = {
+      mode => $self->{mode} || '1',
+      cookie => $self->{cookie} || '',
+      reloadHint   => $self->{reloadHint} || '0',
+    };
+  }
+
+  $self;
+}
+
+sub mode {
+  my $self = shift;
+  $self->{asn} ||= $syncRequestValue->decode($self->{value});
+  if (@_) {
+    delete $self->{value};
+    return $self->{asn}{mode} = shift || 0;
+  }
+  $self->{asn}{mode};
+}
+
+sub cookie {
+  my $self = shift;
+  $self->{asn} ||= $syncRequestValue->decode($self->{value});
+  if (@_) {
+    delete $self->{value};
+    return $self->{asn}{cookie} = shift || 0;
+  }
+  $self->{asn}{cookie};
+}
+
+sub reloadHint {
+  my $self = shift;
+  $self->{asn} ||= $syncRequestValue->decode($self->{value});
+  if (@_) {
+    delete $self->{value};
+    return $self->{asn}{reloadHint} = shift || 0;
+  }
+  $self->{asn}{reloadHint};
+}
+
+sub value {
+  my $self = shift;
+
+  exists $self->{value}
+    ? $self->{value}
+    : $self->{value} = $syncRequestValue->encode($self->{asn});
+}
+
+1;
+
+
+__END__
+
+=head1 NAME
+
+Net::LDAP::Control::SyncRequest - LDAPv3 Sync Request control object
+
+=head1 SYNOPSIS
+
+ use Net::LDAP;
+ use Net::LDAP::Control::SyncRequest;
+ use Net::LDAP::Constant qw(
+  LDAP_SYNC_REFRESH_ONLY
+  LDAP_SYNC_REFRESH_AND_PERSIST
+  LDAP_SUCCESS );
+
+ $ldap = Net::LDAP->new( "ldap.mydomain.eg" );
+
+ $req = Net::LDAP::Control::SyncRequest->new( mode => LDAP_SYNC_REFRESH_ONLY );
+ my $mesg = $ldap->search(base=> 'dc=mydomain,dc='eg',
+                          scope    => 'sub',
+                          control  => [ $req ],
+                          callback => \&searchCallback, # call for each entry
+                          filter   => "(objectClass=*)",
+                          attrs    => [ '*']);
+ sub searchCallback {
+   my $message = shift;
+   my $entry = shift;
+   my @controls = $message->control;
+
+   if($controls[0]->isa('Net::LDAP::Control::SyncState')) {
+     print "Received Sync State Control\n";
+     print $entry->dn()."\n";
+     print 'State: '.$controls[0]->state."\n".', entryUUID: '.$controls[0]->entryUUID.', cookie: '.$controls[0]->cookie;
+   } elsif($controls[0]->isa('Net::LDAP::Control::SyncDone')) {
+     print "Received Sync Done Control\n";
+     print 'Cookie: '.$controls[0]->cookie.', refreshDeletes: '.$controls[0]->refreshDeletes;
+   }
+ }
+
+=head1 DESCRIPTION
+
+C<Net::LDAP::Control::SyncRequest> provides an interface for the creation and
+manipulation of objects that represent the C<Sync Request Control> as described
+by RFC 4533.
+
+=head1 CONSTRUCTOR ARGUMENTS
+
+In addition to the constructor arguments described in
+L<Net::LDAP::Control> the following are provided.
+
+=over 4
+
+=item mode
+
+=item cookie
+
+=item reloadHint
+
+=back
+
+=head1 METHODS
+
+As with L<Net::LDAP::Control> each constructor argument
+described above is also avaliable as a method on the object which will
+return the current value for the attribute if called without an argument,
+and set a new value for the attribute if called with an argument.
+
+=head1 SEE ALSO
+
+L<Net::LDAP>,
+L<Net::LDAP::Control>,
+L<Net::LDAP::Control::SyncState>,
+L<Net::LDAP::Control::SyncDone>,
+http://www.ietf.org/rfc/rfc4533.txt
+
+=head1 AUTHOR
+
+Mathieu Parent E<lt>[EMAIL PROTECTED]<gt>
+
+Please report any bugs, or post any suggestions, to the perl-ldap mailing list
+E<lt>[EMAIL PROTECTED]<gt>
+
+=head1 COPYRIGHT
+
+Copyright (c) 2008 Mathieu Parent. All rights reserved. This program is
+free software; you can redistribute it and/or modify it under the same
+terms as Perl itself.
+
+=cut
+
diff -urN --exclude=blib --exclude=debian --exclude '*~' libnet-ldap-perl-0.36-old/lib/Net/LDAP/Control/SyncState.pm libnet-ldap-perl-0.36/lib/Net/LDAP/Control/SyncState.pm
--- libnet-ldap-perl-0.36-old/lib/Net/LDAP/Control/SyncState.pm	1970-01-01 01:00:00.000000000 +0100
+++ libnet-ldap-perl-0.36/lib/Net/LDAP/Control/SyncState.pm	2008-06-14 17:50:49.000000000 +0200
@@ -0,0 +1,165 @@
+# Copyright (c) 2008 Mathieu Parent <[EMAIL PROTECTED]>. All rights reserved.
+# This program is free software; you can redistribute it and/or
+# modify it under the same terms as Perl itself.
+
+package Net::LDAP::Control::SyncState;
+
+use vars qw(@ISA $VERSION);
+use Net::LDAP::Control;
+
[EMAIL PROTECTED] = qw(Net::LDAP::Control);
+$VERSION = "0.01";
+
+use Net::LDAP::ASN qw(syncStateValue);
+use strict;
+
+# use some kind of hack here:
+# - calling the control without args means: response,
+# - giving an argument: means: request
+sub init {
+  my($self) = @_;
+
+  delete $self->{asn};
+
+  unless (exists $self->{value}) {
+    $self->{asn} = {
+      state => $self->{state} || '',
+      entryUUID => $self->{entryUUID} || '',
+      cookie   => $self->{cookie} || '',
+    };
+  }
+
+  $self;
+}
+
+sub state {
+  my $self = shift;
+  $self->{asn} ||= $syncStateValue->decode($self->{value});
+  if (@_) {
+    delete $self->{value};
+    return $self->{asn}{state} = shift || 0;
+  }
+  $self->{asn}{state};
+}
+
+sub entryUUID {
+  my $self = shift;
+  $self->{asn} ||= $syncStateValue->decode($self->{value});
+  if (@_) {
+    delete $self->{value};
+    return $self->{asn}{entryUUID} = shift || 0;
+  }
+  $self->{asn}{entryUUID};
+}
+
+sub cookie {
+  my $self = shift;
+  $self->{asn} ||= $syncStateValue->decode($self->{value});
+  if (@_) {
+    delete $self->{value};
+    return $self->{asn}{cookie} = shift || 0;
+  }
+  $self->{asn}{cookie};
+}
+
+sub value {
+  my $self = shift;
+
+  exists $self->{value}
+    ? $self->{value}
+    : $self->{value} = $syncStateValue->encode($self->{asn});
+}
+
+1;
+
+
+__END__
+
+=head1 NAME
+
+Net::LDAP::Control::SyncState - LDAPv3 Sync State control object
+
+=head1 SYNOPSIS
+
+ use Net::LDAP;
+ use Net::LDAP::Control::SyncRequest;
+ use Net::LDAP::Constant qw(
+  LDAP_SYNC_REFRESH_ONLY
+  LDAP_SYNC_REFRESH_AND_PERSIST
+  LDAP_SUCCESS );
+
+ $ldap = Net::LDAP->new( "ldap.mydomain.eg" );
+
+ $req = Net::LDAP::Control::SyncRequest->new( mode => LDAP_SYNC_REFRESH_ONLY );
+ my $mesg = $ldap->search(base=> 'dc=mydomain,dc='eg',
+                          scope    => 'sub',
+                          control  => [ $req ],
+                          callback => \&searchCallback, # call for each entry
+                          filter   => "(objectClass=*)",
+                          attrs    => [ '*']);
+ sub searchCallback {
+   my $message = shift;
+   my $entry = shift;
+   my @controls = $message->control;
+
+   if($controls[0]->isa('Net::LDAP::Control::SyncState')) {
+     print "Received Sync State Control\n";
+     print $entry->dn()."\n";
+     print 'State: '.$controls[0]->state."\n".', entryUUID: '.$controls[0]->entryUUID.', cookie: '.$controls[0]->cookie;
+   } elsif($controls[0]->isa('Net::LDAP::Control::SyncDone')) {
+     print "Received Sync Done Control\n";
+     print 'Cookie: '.$controls[0]->cookie.', refreshDeletes: '.$controls[0]->refreshDeletes;
+   }
+ }
+
+=head1 DESCRIPTION
+
+C<Net::LDAP::Control::SyncState> provides an interface for the creation and
+manipulation of objects that represent the C<Sync State Control> as described
+by RFC 4533.
+
+=head1 CONSTRUCTOR ARGUMENTS
+
+In addition to the constructor arguments described in
+L<Net::LDAP::Control> the following are provided.
+
+=over 4
+
+=item state
+
+=item entryUIID
+
+=item cookie
+
+=back
+
+=head1 METHODS
+
+As with L<Net::LDAP::Control> each constructor argument
+described above is also avaliable as a method on the object which will
+return the current value for the attribute if called without an argument,
+and set a new value for the attribute if called with an argument.
+
+=head1 SEE ALSO
+
+L<Net::LDAP>,
+L<Net::LDAP::Control>,
+L<Net::LDAP::Control::SyncRequest>,
+L<Net::LDAP::Control::SyncDone>,
+http://www.ietf.org/rfc/rfc4533.txt
+
+=head1 AUTHOR
+
+Mathieu Parent E<lt>[EMAIL PROTECTED]<gt>
+
+Please report any bugs, or post any suggestions, to the perl-ldap mailing list
+E<lt>[EMAIL PROTECTED]<gt>
+
+=head1 COPYRIGHT
+
+Copyright (c) 2008 Mathieu Parent. All rights reserved. This program is
+free software; you can redistribute it and/or modify it under the same
+terms as Perl itself.
+
+=cut
+
diff -urN --exclude=blib --exclude=debian --exclude '*~' libnet-ldap-perl-0.36-old/lib/Net/LDAP/Control.pm libnet-ldap-perl-0.36/lib/Net/LDAP/Control.pm
--- libnet-ldap-perl-0.36-old/lib/Net/LDAP/Control.pm	2008-04-21 17:11:06.000000000 +0200
+++ libnet-ldap-perl-0.36/lib/Net/LDAP/Control.pm	2008-06-14 17:32:30.000000000 +0200
@@ -21,9 +21,12 @@
   LDAP_CONTROL_PASSWORDPOLICY
   LDAP_CONTROL_PREREAD
   LDAP_CONTROL_POSTREAD
+  LDAP_CONTROL_SYNC
+  LDAP_CONTROL_SYNC_STATE
+  LDAP_CONTROL_SYNC_DONE
 );
 
-$VERSION = "0.08";
+$VERSION = "0.09";
 
 my %Pkg2Type = (
 
@@ -49,6 +52,10 @@
   'Net::LDAP::Control::PreRead'		=> LDAP_CONTROL_PREREAD,
 
   'Net::LDAP::Control::PostRead'	=> LDAP_CONTROL_POSTREAD,
+
+  'Net::LDAP::Control::SyncRequest'	=> LDAP_CONTROL_SYNC,
+  'Net::LDAP::Control::SyncState'	=> LDAP_CONTROL_SYNC_STATE,
+  'Net::LDAP::Control::SyncDone'	=> LDAP_CONTROL_SYNC_DONE,
   #
   #LDAP_CONTROL_PWEXPIRED
   #LDAP_CONTROL_PWEXPIRING
diff -urN --exclude=blib --exclude=debian --exclude '*~' libnet-ldap-perl-0.36-old/lib/Net/LDAP/Search.pm libnet-ldap-perl-0.36/lib/Net/LDAP/Search.pm
--- libnet-ldap-perl-0.36-old/lib/Net/LDAP/Search.pm	2008-04-21 17:11:06.000000000 +0200
+++ libnet-ldap-perl-0.36/lib/Net/LDAP/Search.pm	2008-06-14 20:09:52.000000000 +0200
@@ -12,7 +12,7 @@
 use Net::LDAP::Constant qw(LDAP_SUCCESS LDAP_DECODING_ERROR);
 
 @ISA = qw(Net::LDAP::Message);
-$VERSION = "0.11";
+$VERSION = "0.12";
 
 
 sub first_entry { # compat
@@ -36,6 +36,9 @@
   return $self->SUPER::decode($result)
     if exists $result->{protocolOp}{searchResDone};
 
+  return $self->SUPER::decode($result)
+    if exists $result->{protocolOp}{intermediateResponse};
+
   my $data;
   @{$self}{qw(controls ctrl_hash)} = ($result->{controls}, undef);
 
diff -urN --exclude=blib --exclude=debian --exclude '*~' libnet-ldap-perl-0.36-old/Makefile libnet-ldap-perl-0.36/Makefile
--- libnet-ldap-perl-0.36-old/Makefile	2008-06-14 14:01:18.000000000 +0200
+++ libnet-ldap-perl-0.36/Makefile	2008-06-14 20:13:27.000000000 +0200
@@ -177,6 +177,9 @@
 	lib/Net/LDAP/Control/ProxyAuth.pm \
 	lib/Net/LDAP/Control/Sort.pm \
 	lib/Net/LDAP/Control/SortResult.pm \
+	lib/Net/LDAP/Control/SyncDone.pm \
+	lib/Net/LDAP/Control/SyncRequest.pm \
+	lib/Net/LDAP/Control/SyncState.pm \
 	lib/Net/LDAP/Control/VLV.pm \
 	lib/Net/LDAP/Control/VLVResponse.pm \
 	lib/Net/LDAP/DSML.pm \
@@ -238,6 +241,9 @@
 	lib/Net/LDAP/Control/ProxyAuth.pm \
 	lib/Net/LDAP/Control/Sort.pm \
 	lib/Net/LDAP/Control/SortResult.pm \
+	lib/Net/LDAP/Control/SyncDone.pm \
+	lib/Net/LDAP/Control/SyncRequest.pm \
+	lib/Net/LDAP/Control/SyncState.pm \
 	lib/Net/LDAP/Control/VLV.pm \
 	lib/Net/LDAP/Control/VLVResponse.pm \
 	lib/Net/LDAP/DSML.pm \
@@ -274,6 +280,8 @@
 	blib/lib/Net/LDAP/Entry.pod \
 	lib/Net/LDAP/FilterMatch.pm \
 	blib/lib/Net/LDAP/FilterMatch.pm \
+	lib/Net/LDAP/Control/SyncDone.pm \
+	blib/lib/Net/LDAP/Control/SyncDone.pm \
 	lib/Net/LDAP/Message.pod \
 	blib/lib/Net/LDAP/Message.pod \
 	lib/Net/LDAP/Util.pm \
@@ -304,6 +312,8 @@
 	blib/lib/Net/LDAP/Control/Sort.pm \
 	lib/Net/LDAPS.pm \
 	blib/lib/Net/LDAPS.pm \
+	lib/Net/LDAP/Control/SyncRequest.pm \
+	blib/lib/Net/LDAP/Control/SyncRequest.pm \
 	lib/Net/LDAP/Message.pm \
 	blib/lib/Net/LDAP/Message.pm \
 	lib/Net/LDAP/FAQ.pod \
@@ -352,6 +362,8 @@
 	blib/lib/Net/LDAP/Extension/SetPassword.pm \
 	lib/Net/LDAP.pm \
 	blib/lib/Net/LDAP.pm \
+	lib/Net/LDAP/Control/SyncState.pm \
+	blib/lib/Net/LDAP/Control/SyncState.pm \
 	lib/Net/LDAP/Extension.pm \
 	blib/lib/Net/LDAP/Extension.pm \
 	lib/Net/LDAP/Reference.pod \
@@ -584,6 +596,7 @@
 	lib/Net/LDAP/Control/PostRead.pm \
 	lib/Net/LDAP/Entry.pod \
 	lib/Net/LDAP/FilterMatch.pm \
+	lib/Net/LDAP/Control/SyncDone.pm \
 	lib/Net/LDAP/Message.pod \
 	lib/Net/LDAP/Util.pm \
 	lib/Net/LDAP/Extension/WhoAmI.pm \
@@ -598,6 +611,7 @@
 	lib/Net/LDAPI.pm \
 	lib/Net/LDAP/Control/Sort.pm \
 	lib/Net/LDAPS.pm \
+	lib/Net/LDAP/Control/SyncRequest.pm \
 	lib/Net/LDAP/FAQ.pod \
 	lib/Net/LDAP/RootDSE.pm \
 	lib/Bundle/Net/LDAP.pm \
@@ -613,6 +627,7 @@
 	lib/Net/LDAP/Examples.pod \
 	lib/Net/LDAP/RFC.pod \
 	lib/Net/LDAP/Extension/SetPassword.pm \
+	lib/Net/LDAP/Control/SyncState.pm \
 	lib/Net/LDAP/Reference.pod \
 	lib/Net/LDAP.pod \
 	lib/Net/LDAP/Constant.pm \
@@ -621,6 +636,7 @@
 	  lib/Net/LDAP/Control/PostRead.pm $(INST_MAN3DIR)/Net::LDAP::Control::PostRead.$(MAN3EXT) \
 	  lib/Net/LDAP/Entry.pod $(INST_MAN3DIR)/Net::LDAP::Entry.$(MAN3EXT) \
 	  lib/Net/LDAP/FilterMatch.pm $(INST_MAN3DIR)/Net::LDAP::FilterMatch.$(MAN3EXT) \
+	  lib/Net/LDAP/Control/SyncDone.pm $(INST_MAN3DIR)/Net::LDAP::Control::SyncDone.$(MAN3EXT) \
 	  lib/Net/LDAP/Message.pod $(INST_MAN3DIR)/Net::LDAP::Message.$(MAN3EXT) \
 	  lib/Net/LDAP/Util.pm $(INST_MAN3DIR)/Net::LDAP::Util.$(MAN3EXT) \
 	  lib/Net/LDAP/Extension/WhoAmI.pm $(INST_MAN3DIR)/Net::LDAP::Extension::WhoAmI.$(MAN3EXT) \
@@ -635,6 +651,7 @@
 	  lib/Net/LDAPI.pm $(INST_MAN3DIR)/Net::LDAPI.$(MAN3EXT) \
 	  lib/Net/LDAP/Control/Sort.pm $(INST_MAN3DIR)/Net::LDAP::Control::Sort.$(MAN3EXT) \
 	  lib/Net/LDAPS.pm $(INST_MAN3DIR)/Net::LDAPS.$(MAN3EXT) \
+	  lib/Net/LDAP/Control/SyncRequest.pm $(INST_MAN3DIR)/Net::LDAP::Control::SyncRequest.$(MAN3EXT) \
 	  lib/Net/LDAP/FAQ.pod $(INST_MAN3DIR)/Net::LDAP::FAQ.$(MAN3EXT) \
 	  lib/Net/LDAP/RootDSE.pm $(INST_MAN3DIR)/Net::LDAP::RootDSE.$(MAN3EXT) \
 	  lib/Bundle/Net/LDAP.pm $(INST_MAN3DIR)/Bundle::Net::LDAP.$(MAN3EXT) \
@@ -650,6 +667,7 @@
 	  lib/Net/LDAP/Examples.pod $(INST_MAN3DIR)/Net::LDAP::Examples.$(MAN3EXT) \
 	  lib/Net/LDAP/RFC.pod $(INST_MAN3DIR)/Net::LDAP::RFC.$(MAN3EXT) \
 	  lib/Net/LDAP/Extension/SetPassword.pm $(INST_MAN3DIR)/Net::LDAP::Extension::SetPassword.$(MAN3EXT) \
+	  lib/Net/LDAP/Control/SyncState.pm $(INST_MAN3DIR)/Net::LDAP::Control::SyncState.$(MAN3EXT) \
 	  lib/Net/LDAP/Reference.pod $(INST_MAN3DIR)/Net::LDAP::Reference.$(MAN3EXT) \
 	  lib/Net/LDAP.pod $(INST_MAN3DIR)/Net::LDAP.$(MAN3EXT) \
 	  lib/Net/LDAP/Constant.pm $(INST_MAN3DIR)/Net::LDAP::Constant.$(MAN3EXT) \
@@ -1005,6 +1023,7 @@
 	  lib/Net/LDAP/Control/PostRead.pm blib/lib/Net/LDAP/Control/PostRead.pm \
 	  lib/Net/LDAP/Entry.pod blib/lib/Net/LDAP/Entry.pod \
 	  lib/Net/LDAP/FilterMatch.pm blib/lib/Net/LDAP/FilterMatch.pm \
+	  lib/Net/LDAP/Control/SyncDone.pm blib/lib/Net/LDAP/Control/SyncDone.pm \
 	  lib/Net/LDAP/Message.pod blib/lib/Net/LDAP/Message.pod \
 	  lib/Net/LDAP/Util.pm blib/lib/Net/LDAP/Util.pm \
 	  lib/Net/LDAP/Extension/WhoAmI.pm blib/lib/Net/LDAP/Extension/WhoAmI.pm \
@@ -1020,6 +1039,7 @@
 	  lib/Net/LDAPI.pm blib/lib/Net/LDAPI.pm \
 	  lib/Net/LDAP/Control/Sort.pm blib/lib/Net/LDAP/Control/Sort.pm \
 	  lib/Net/LDAPS.pm blib/lib/Net/LDAPS.pm \
+	  lib/Net/LDAP/Control/SyncRequest.pm blib/lib/Net/LDAP/Control/SyncRequest.pm \
 	  lib/Net/LDAP/Message.pm blib/lib/Net/LDAP/Message.pm \
 	  lib/Net/LDAP/FAQ.pod blib/lib/Net/LDAP/FAQ.pod \
 	  lib/Net/LDAP/Search.pm blib/lib/Net/LDAP/Search.pm \
@@ -1044,6 +1064,7 @@
 	  lib/Net/LDAP/RFC.pod blib/lib/Net/LDAP/RFC.pod \
 	  lib/Net/LDAP/Extension/SetPassword.pm blib/lib/Net/LDAP/Extension/SetPassword.pm \
 	  lib/Net/LDAP.pm blib/lib/Net/LDAP.pm \
+	  lib/Net/LDAP/Control/SyncState.pm blib/lib/Net/LDAP/Control/SyncState.pm \
 	  lib/Net/LDAP/Extension.pm blib/lib/Net/LDAP/Extension.pm \
 	  lib/Net/LDAP/Reference.pod blib/lib/Net/LDAP/Reference.pod \
 	  lib/Net/LDAP.pod blib/lib/Net/LDAP.pod \

Reply via email to