Good day everyone.

I was wondering if it would make sense to have a DN comparison function
part of Net::LDAP? Whilst in most cases a simple string comparison could
make it, there are always cases where this is not so easy, particularly
when comparison functions are not identical.

See code below for a proposal on how to do this (this does not integrate
yet "as is" in perl-ldap). One design question I would have is: should
this be part of Net::LDAP::Schema as a metho or Net::LDAP::Util, with the
schema as a provided parameter?

I welcome any thoughts on this and anyone feel free to use the code if
it helps you.

-- 
Christophe Wolfhugel -+- ch...@wolfhugel.eu

## $SCHEMA is a global to the selected schema we use.

## Compares 2 DNs for either equality or the first being
## part (or equal to) of a subtree represented by the
## second argument. Third argument if set tells a subtree
## comparison should be done. Returns true if identical or
## in the tree, 0 otherwise, undef if not enough arguments.
sub compare_dn { 
   return unless (@_ >= 2);
   return 1 if ($_[0] eq $_[1]);
   my $a = ldap_explode_dn($_[0]);
   my $b = ldap_explode_dn($_[1]);
   my $s = @_ == 3 ? $_[2] : 0;

   if ($s) {
      return 0 if ($#{$a} < $#${b});
      splice(@{$a}, 0, $#{$a} -  $#${b});
   } elsif ($#{$a} != $#${b}) {
      return 0;
   }
   foreach my $rdn_a (@{$a}) {
      my $rdn_b = shift(@{$b});
      return 0 if (join(',', sort keys %{$rdn_a}) ne join(',', sort keys 
%{$rdn_b}));
      while (my($attr, $v_a) = each %{$rdn_a}) {
         if (defined(my $v_b = delete($rdn_b->{$attr}))) {
            ## LDAPmatchingrule_for_attribute is my wrapper around 
matchingrule_for_attribute.
            my $mr = defined($SCHEMA) ? LDAPmatchingrule_for_attribute($SCHEMA, 
$attr, 'equality') : undef;
            $mr = defined($mr) && exists($cmpsubs{$mr}) ? $cmpsubs{$mr} : 
$cmpsubs{'*'};
            return 0 unless (&{$mr}($v_a, $v_b));
         } else {
            return 0;
         }
      }
   }
   return 1;
}

my %cmpsubs = (
   '*'                  =>      sub { return $_[0] eq $_[1]; },
   'integerMatch'       =>      sub { return $_[0] == $_[1]; },
   'caseIgnoreIA5Match' =>      sub { return lc($_[0]) eq lc($_[1]); },
   'caseIgnoreMatch'    =>      sub {
                                        my @a = @_;
                                        utf8::decode($a[0]) if 
(utf8::valid($a[0]) && utf8::is_utf8($a[0]) == 0);
                                        utf8::decode($a[1]) if 
(utf8::valid($a[1]) && utf8::is_utf8($a[1]) == 0);
                                        return lc($a[0]) eq lc($a[1]);
                                }
);

Reply via email to