> > Maybe it would be reasonable to add register() functionality to > > Net::LDAP::Search > > (like in Net::LDAP::Control), so that one could assign > > a custom response-message processor (decoder) for a particular protocolOp > > for example? > > (IntermediateResponse with responseName = '1.3.6.1.4.1.4203.1.9.1.4' in my > > case) > > > > If you wish I can send a quick-and-dirty patch just to illustrate this > > suggestion. > > Please post your patch to the list so that there is something to discuss > about.
First ASN definition of IntermediateResponse ---------------------------------------------------------------------------- -------------------------------- diff -ru perl-ldap-0.33.orig/lib/Net/LDAP/ASN.pm perl-ldap-0.33/lib/Net/LDAP/ASN.pm --- perl-ldap-0.33.orig/lib/Net/LDAP/ASN.pm 2005-04-26 02:54:40.000000000 +0400 +++ perl-ldap-0.33/lib/Net/LDAP/ASN.pm 2005-10-28 14:43:36.000000000 +0400 @@ -57,7 +57,8 @@ delResponse DelResponse, modDNResponse ModifyDNResponse, compareResponse CompareResponse, - extendedResp ExtendedResponse } + extendedResp ExtendedResponse, + intermediateResponse IntermediateResponse } controls [0] Controls OPTIONAL } MessageID ::= INTEGER -- (0 .. maxInt) @@ -176,6 +177,11 @@ BindResponse ::= [APPLICATION 1] SEQUENCE { COMPONENTS OF LDAPResult, serverSaslCreds [7] OCTET STRING OPTIONAL } + +IntermediateResponse ::= [APPLICATION 25] SEQUENCE { + responseName [0] LDAPOID OPTIONAL, + responseValue [1] OCTET STRING OPTIONAL } + UnbindRequest ::= [APPLICATION 2] NULL ---------------------------------------------------------------------------- -------------------------------- Then add functionality to assign the custom decoder for a specific protocolOp of a response message. ---------------------------------------------------------------------------- -------------------------------- diff -ru perl-ldap-0.33.orig/lib/Net/LDAP/Search.pm perl-ldap-0.33/lib/Net/LDAP/Search.pm --- perl-ldap-0.33.orig/lib/Net/LDAP/Search.pm 2005-04-26 02:54:38.000000000 +0400 +++ perl-ldap-0.33/lib/Net/LDAP/Search.pm 2005-11-14 13:54:12.000000000 +0300 @@ -28,17 +28,54 @@ : 0); } +sub protocolOp_detail { + my $self = shift; + + return undef unless exists $self->{_protocolOp_processor}; + + my $protocolOp_processor = $self->{_protocolOp_processor}; + + my $protocolOp_detail = $protocolOp_processor->new($self->{_protocolOp_asn}); + return $protocolOp_detail; +} + +my %Op2Pkg; + +sub register { + my $protocolOp_pkg = shift; + my $protocolOp = shift; + + push @{$Op2Pkg{$protocolOp}}, $protocolOp_pkg; +} sub decode { my $self = shift; my $result = shift; + delete $self->{_protocolOp_asn}; + delete $self->{_protocolOp_processor}; + return $self->SUPER::decode($result) if exists $result->{protocolOp}{searchResDone}; my $data; @{$self}{qw(controls ctrl_hash)} = ($result->{controls}, undef); + if(exists $Op2Pkg{(keys %{$result->{protocolOp}})[0]}) { + my $protocolOp_pkgs = $Op2Pkg{(keys %{$result->{protocolOp}})[0]}; + foreach my $protocolOp_processor (@$protocolOp_pkgs) { + + if( defined($self->{_protocolOp_asn} = eval "\$self->${protocolOp_processor}::decode(\$result)")) { + $self->{_protocolOp_processor} = $protocolOp_processor; + + $self->{callback}->($self, undef) + if (defined $self->{callback}); + + return $self; + } + } + } + if ($data = delete $result->{protocolOp}{searchResEntry}) { my $entry = Net::LDAP::Entry->new; ---------------------------------------------------------------------------- -------------------------------- Net::LDAP::Search::protocolOp_detail -- returns a wrapper object for accessing custom-decoded message attributes. Net::LDAP::Search::register -- assigns a package for decoding a response message with a specific protocolOp value. Net::LDAP::Search::decode calls assigned custom decoder for a response message according to protocolOp value Wrapper object could be used like this (example for Sync Info IRM): my $custom_mesg = $mesg->protocolOp_detail(); my $sync_info = $custom_mesg if defined $custom_mesg and $custom_mesg->protocolOp() eq 'IntermediateResponse' and $custom_mesg->type() eq LDAP_MESSAGE_IRM_SYNCINFO; $sync_info->newcookie() if defined $sync_info; $sync_info->syncUUIDs() if defined $sync_info; $sync_info->cookie() if defined $sync_info; $sync_info->refreshDone() if defined $sync_info; Decoder (and wrapper) for Sync Info IRM ---------------------------------------------------------------------------- -------------------------------- package Net::LDAP::Message::IRMSyncInfo; use Net::LDAP::Search; Net::LDAP::Search::register(__PACKAGE__, 'intermediateResponse'); use strict; use vars qw(@ISA $VERSION); use constant LDAP_MESSAGE_IRM_SYNCINFO => '1.3.6.1.4.1.4203.1.9.1.4'; require Exporter; @ISA = qw(Exporter); our @EXPORT = qw(LDAP_MESSAGE_IRM_SYNCINFO); $VERSION = "0.01"; my $SyncInfoValue = new Convert::ASN1; $SyncInfoValue->prepare(<<SYNC_INFO_VALUE) or die "Can't prepare SyncInfoValue: " . $SyncInfoValue->error; syncInfoValue ::= CHOICE { newcookie [0] syncCookie, refreshDelete [1] case1, refreshPresent [2] case2, syncIdSet [3] case3 } case1 ::= SEQUENCE { cookie syncCookie OPTIONAL, refreshDone BOOLEAN OPTIONAL } case2 ::= SEQUENCE { cookie syncCookie OPTIONAL, refreshDone BOOLEAN OPTIONAL } case3 ::= SEQUENCE { cookie syncCookie OPTIONAL, refreshDeletes BOOLEAN OPTIONAL, syncUUIDs SET OF syncUUID } syncUUID ::= OCTET STRING syncCookie ::= OCTET STRING SYNC_INFO_VALUE sub new { my $class = shift; my $asn = shift; $class = ref($class) || $class; my $self = {asn => $asn}; return bless $self, $class; } sub decode { my $self = shift; my $result = shift; if(exists $result->{protocolOp}{intermediateResponse} and $result->{protocolOp}{intermediateResponse}{responseName} eq LDAP_MESSAGE_IRM_SYNCINFO) { my $buf = $result->{protocolOp}{intermediateResponse}{responseValue}; return $SyncInfoValue->find('syncInfoValue')->decode($buf); } return undef; } sub protocolOp {'IntermediateResponse'} sub type {LDAP_MESSAGE_IRM_SYNCINFO} sub sub_type { my $self = shift; return (keys %{$self->{asn}})[0]; } # Make access methods for the message attributes. for my $attr (qw(newcookie cookie refreshDone refreshDeletes syncUUIDs)) { no strict 'refs'; *$attr = sub { my $self = shift; return($self->{asn}{newcookie} or '') if $attr eq 'newcookie'; my $attr_val = ${(values %{$self->{asn}})[0]}{$attr}; return $attr_val if defined $attr_val; return '' if $attr eq 'cookie'; return undef if $attr eq 'syncUUIDs'; return $attr eq 'refreshDone' ? 1 : 0; }; } 1; ---------------------------------------------------------------------------- -------------------------------- This package implements Sync Info IRM decoder and generates attribute-access funcions. All necessary detailed explanations can be sent if needed. Best regards, Alexey Kravchuk