Peter, I've created a 0.14 (see attached patch ;-)) which contains more matching rules and some other small fixes. However to post patches, it would be very convenient to have *readonly* svn access. I tried using tortoise SVN but I get a forbidden. Am I doing something wrong ? Using the web interface is rather cumbersome if I want to keep up with the patches as I seem to be unable to get the files apart from copy/paste from the webpage. Any hints would be appreciated ;-) I removed the "use Net::LDAP::Filter" & "use Net::LDAP::Schema" as it does not seem to harm code execution. The module seems to be strict, however the &$match is not allowed when strict is active (thats why my initial version used the eval ) Regarding the approx, we could use Text::Soundex or String::Approx and conditionally load that if present on the system, "just" a regexp would be perfect, but I haven't come across one yet ;-) Cheers, Hans Peter Marschall schreef: Hi Hans, On Saturday, 14. January 2006 21:00, [EMAIL PROTECTED] wrote:I've added schema awareness. You can now do $filter->match($entry,$schema) and it will filter based on schema, however currently I only included caseIgnore matching. I couldn't get the function prototyping to work with the substrings match in combination with schema lookup while it works with $schema=undef (I'm running Active State 5.8.7).I have made a few slight changes to the file and added it to the perl-ldap SVNYou may grab it from the perl-ldap SVN at http://svn.mutatus.co.uk/wsvn/perl-ldap/trunk/ Now that we have something in public to compare to, may I asky you to post patches instead of the full file for future updates. BTW do you need the function call filterMatch() exported ? I'd like to get rid of it as $filter->match() is IMHO much nicer/cleaner.At the end is a small extension to Net::LDAP::Schema, which probably does not belong here ;-)As Chris already added it (slightly modified) to Net::LDAP::Schema I removed that part and adapted the method calls to the Schema accordingly. Please test if my changes were correct ;-) Peter |
*** /trunk/lib/Net/LDAP/FilterMatch.pm 2006-01-15 20:27:05.787625600 +0100 --- FilterMatch.pm 2006-01-15 21:34:40.457955200 +0100 *************** *** 10,37 **** # See below for documentation. # - use Net::LDAP::Filter; - use Net::LDAP::Schema; - package Net::LDAP::Filter; ! use strict; ! use vars qw(@ISA @EXPORT_OK); ! ! require Exporter; ! @ISA = qw(Exporter); ! @EXPORT_OK = qw(filterMatch); ! $VERSION = '0.13'; sub filterMatch($@); sub _cis_equalityMatch($@); sub _cis_greaterOrEqual($@); sub _cis_lessOrEqual($@); sub _cis_approxMatch($@); ! sub _cis_substrings; ! sub _caseIgnoreMatch { return _cis_equalityMatch(@_)}; ! sub _caseIgnoreSubstringsMatch { return _cis_substrings(@_) }; sub match { --- 10,66 ---- # See below for documentation. # package Net::LDAP::Filter; ! $VERSION = '0.14'; sub filterMatch($@); + sub _cis_equalityMatch($@); + sub _exact_equalityMatch($@); + sub _numeric_equalityMatch($@); + sub _cis_orderingMatch($@); + sub _numeric_orderingMatch($@); sub _cis_greaterOrEqual($@); sub _cis_lessOrEqual($@); sub _cis_approxMatch($@); ! sub _cis_substrings($@); ! sub _exact_substrings($@); ! # all known matches from the OL 2.2 schema, ! *_bitStringMatch = \&_exact_equalityMatch; ! *_booleanMatch = \&_cis_equalityMatch; # this might need to be reworked ! *_caseExactIA5Match = \&_exact_equalityMatch; ! *_caseExactIA5SubstringsMatch = \&_exact_substrings; ! *_caseExactMatch = \&_exact_equalityMatch; ! *_caseExactOrderingMatch = \&_exact_orderingMatch; ! *_caseExactSubstringsMatch = \&_exact_substrings; ! *_caseIgnoreIA5Match = \&_cis_equalityMatch; ! *_caseIgnoreIA5SubstringsMatch = \&_cis_substrings; ! *_caseIgnoreMatch = \&_cis_equalityMatch; ! *_caseIgnoreOrderingMatch = \&_cis_orderingMatch; ! *_caseIgnoreSubstringsMatch = \&_cis_substrings; ! *_certificateExactMatch = \&_exact_equalityMatch; ! *_certificateMatch = \&_exact_equalityMatch; ! *_distinguishedNameMatch = \&_exact_equalityMatch; ! *_generalizedTimeMatch = \&_exact_equalityMatch; ! *_generalizedTimeOrderingMatch = \&_exact_orderingMatch; ! *_integerBitAndMatch = \&_exact_equalityMatch; # this needs to be reworked ! *_integerBitOrMatch = \&_exact_equalityMatch; # this needs to be reworked ! *_integerFirstComponentMatch = \&_exact_equalityMatch; ! *_integerMatch = \&_numeric_equalityMatch; ! *_integerOrderingMatch = \&_numeric_orderingMatch; ! *_numericStringMatch = \&_numeric_equalityMatch; ! *_numericStringOrderingMatch = \&_numeric_orderingMatch; ! *_numericStringSubstringsMatch = \&_numeric_substrings; ! *_objectIdentifierFirstComponentMatch = \&_exact_equalityMatch; # this needs to be reworked ! *_objectIdentifierMatch = \&_exact_equalityMatch; ! *_octetStringMatch = \&_exact_equalityMatch; ! *_octetStringOrderingMatch = \&_exact_orderingMatch; ! *_octetStringSubstringsMatch = \&_exact_substrings; ! *_telephoneNumberMatch = \&_exact_equalityMatch; ! *_telephoneNumberSubstringsMatch = \&_exact_substrings; ! *_uniqueMemberMatch = \&_cis_equalityMatch; # this needs to be reworked sub match { *************** sub match *** 41,54 **** return filterMatch($self, $entry, $schema); } - # map Ops to schema matches my %op2schema = qw( ! equalityMatch equality ! greaterOrEqual equality ! lessOrEqual ordering ! approxMatch ordering ! substrings substr ); sub filterMatch($@) --- 70,82 ---- return filterMatch($self, $entry, $schema); } # map Ops to schema matches my %op2schema = qw( ! equalityMatch equality ! greaterOrEqual ordering ! lessOrEqual ordering ! approxMatch approx ! substrings substr ); sub filterMatch($@) *************** sub filterMatch($@) *** 57,62 **** --- 85,91 ---- my $entry = shift; my $schema = shift; + keys(%{$filter}); # re-initialize each() operator my ($op, $args) = each(%{$filter}); *************** sub filterMatch($@) *** 83,103 **** # handle basic filters if ($op =~ /^(equalityMatch|greaterOrEqual|lessOrEqual|approxMatch|substrings)/o) { ! my $attr=($op eq 'substrings') ? $args->{'type'} : $args->{'attributeDesc'} ; ! my @values = $entry->get_value($attr); my $match; # approx match is not standardized in schema if ($schema and ($op ne 'approxMatch') ){ ! # get matchingrule from schema, be sure that matching subs exist for every MR in your schema ! $match='_' . $schema->matchingrule_for_attribute( $attr, $op2schema{$op}) or return undef; } else{ # fall back on build-in logic $match='_cis_' . $op; } ! ! return &$match($args, @values); } return undef; # all other filters => fail with error --- 112,147 ---- # handle basic filters if ($op =~ /^(equalityMatch|greaterOrEqual|lessOrEqual|approxMatch|substrings)/o) { ! my $attr; ! my $assertion; my $match; + if ($op eq 'substrings'){ + $attr = $args->{'type'}; + # build a regexp as assertion value + $assertion = join('.*', map { "\Q$_\E" } map { values %$_ } @{$args->{'substrings'}}); + $assertion = '^'. $assertion if (exists $args->{'substrings'}[0]{'initial'}); + $assertion .= '$' if (exists $args->{'substrings'}[-1]{'final'}); + } + else{ + $attr = $args->{'attributeDesc'}; + $assertion = $args->{'assertionValue'} + } + + + my @values = $entry->get_value($attr); + # approx match is not standardized in schema if ($schema and ($op ne 'approxMatch') ){ ! # get matchingrule from schema, be sure that matching subs exist for every MR in your schema ! $match='_' . $schema->matchingrule_for_attribute( $attr, $op2schema{$op}) or return undef; } else{ # fall back on build-in logic $match='_cis_' . $op; } ! print $attr,'##',$assertion, '##', $op,'##', $op2schema{$op},'##',$match,'##'; ! return &$match($assertion,$op,@values); } return undef; # all other filters => fail with error *************** sub filterMatch($@) *** 105,149 **** sub _cis_equalityMatch($@) { ! my $args=shift; ! my $assertion = $args->{'assertionValue'}; return grep(/^\Q$assertion\E$/i, @_) ? 1 : 0; } ! sub _cis_greaterOrEqual($@) { ! my $args=shift; ! my $assertion = $args->{'assertionValue'}; ! if (grep(!/^-?\d+$/o, $assertion, @_)) { # numerical values only => compare numerically return (grep { $_ ge $assertion } @_) ? 1 : 0; } else { ! return (grep { lc($_) >= lc($assertion) } @_) ? 1 : 0; ! } } ! sub _cis_lessOrEqual($@) { ! my $args=shift; ! my $assertion = $args->{'assertionValue'}; if (grep(!/^-?\d+$/o, $assertion, @_)) { # numerical values only => compare numerically ! return (grep { $_ le $assertion } @_) ? 1 : 0; } else { ! return (grep { lc($_) <= lc($assertion) } @_) ? 1 : 0; } } sub _cis_approxMatch($@) { ! my $args=shift; ! my $assertion = $args->{'assertionValue'}; # kludge: treat assertion as regex $assertion =~ s/\./\\./go; --- 149,257 ---- sub _cis_equalityMatch($@) { ! my $assertion = shift; ! my $op = shift; return grep(/^\Q$assertion\E$/i, @_) ? 1 : 0; } + sub _exact_equalityMatch($@) + { + my $assertion = shift; + my $op = shift; ! return grep(/^\Q$assertion\E$/, @_) ? 1 : 0; ! } ! ! sub _numeric_equalityMatch($@) { ! my $assertion = shift; ! my $op = shift; ! return grep(/^\Q$assertion\E$/, @_) ? 1 : 0; ! } ! ! sub _cis_orderingMatch($@) ! { ! my $assertion = shift; ! my $op = shift; ! ! if ($op eq 'greaterOrEqual') { ! return (grep { lc($_) ge lc($assertion) } @_) ? 1 : 0; ! } ! elsif ($op eq 'lessOrEqual') { ! return (grep { lc($_) le lc($assertion) } @_) ? 1 : 0; ! } ! else { ! return undef; #something went wrong ! }; ! } ! ! sub _exact_orderingMatch($@) ! { ! my $assertion = shift; ! my $op = shift; ! ! if ($op eq 'greaterOrEqual') { return (grep { $_ ge $assertion } @_) ? 1 : 0; } + elsif ($op eq 'lessOrEqual') { + return (grep { $_ le $assertion } @_) ? 1 : 0; + } else { ! return undef; #something went wrong ! }; ! } ! ! sub _numeric_orderingMatch($@) ! { ! my $assertion = shift; ! my $op = shift; ! ! if ($op eq 'greaterOrEqual') { ! return (grep { $_ >= $assertion } @_) ? 1 : 0; ! } ! elsif ($op eq 'lessOrEqual') { ! return (grep { $_ <= $assertion } @_) ? 1 : 0; ! } ! else { ! return undef; #something went wrong ! }; ! } ! ! sub _cis_substrings($@) ! { ! my $regex=shift; ! return grep(/$regex/i, @_) ? 1 : 0; } + sub _exact_substrings($@) + { + my $regex=shift; + return grep(/$regex/, @_) ? 1 : 0; + } ! # this one is here in case we don't use schema ! ! sub _cis_greaterOrEqual($@) { ! my $assertion=shift; ! my $op=shift; if (grep(!/^-?\d+$/o, $assertion, @_)) { # numerical values only => compare numerically ! return _cis_orderingMatch($assertion,$op,@_); } else { ! return _numeric_orderingMatch($assertion,$op,@_); } } + *_cis_lessOrEqual = \&_cis_greaterOrEqual; sub _cis_approxMatch($@) { ! my $assertion=shift; ! my $op=shift; # kludge: treat assertion as regex $assertion =~ s/\./\\./go; *************** my $assertion = $args->{'assertionValue' *** 154,173 **** # better: by use String::Approx or similar } - - sub _cis_substrings - { - my $args=shift; - my $regex = join('.*', map { "\Q$_\E" } map { values %$_ } @{$args->{'substrings'}}); - - $regex = '^'.$regex if (exists $args->{'substrings'}[0]{initial}); - $regex .= '$' if (exists $args->{'substrings'}[-1]{final}); - - #print "RegEx: ".$regex."\n"; - - return grep(/$regex/i, @_) ? 1 : 0; - } - 1; --- 262,267 ---- *************** Peter Marschall E<lt>[EMAIL PROTECTED]<gt> *** 239,242 **** =cut ! # EOF \ No newline at end of file --- 333,336 ---- =cut ! # EOF