AddressBook

 view release on metacpan or  search on metacpan

lib/AddressBook/DB/LDAP.pm  view on Meta::CPAN


sub search {
  my $self = shift;
  my $class = ref $self || croak "Not a method call.";
  my @ret;
  my %arg = @_;
  my $max_size = $arg{entries} || 0;
  my $max_time = $arg{time} || 0;
  my $fuzzy = $arg{fuzzy} || 0;
  if (exists $arg{strict}) {
    warn "The 'strict' parameter to LDAP backend searches has been removed";
  } 
  delete $arg{entries};
  delete $arg{time};

  if(defined $arg{filter}) {
    # We have stuff to look for;
    if (ref($arg{filter}) ne "ARRAY") {$arg{filter} = [$arg{filter}]}
    my $evalstring = "=";
    my ($entry,$filter,$filter_element,$subfilter,$value);
    foreach $filter_element (@{$arg{filter}}) {
      $entry = AddressBook::Entry->new(attr=>$filter_element,
				       config => $self->{config},
				       );
      #$entry->calculate;
      $entry = $entry->get(db=>$self->{db_name},values_only=>'1');
      $subfilter="";
      foreach (keys %{$entry}) { 
	$value = $entry->{$_}->[0];
	$value =~ s/\(/\\(/g;
	$value =~ s/\)/\\)/g;
        if ($fuzzy) {
	  $value = "*" . $value . "*";
	}
	$subfilter .= "(" . $_ . $evalstring . $value . ")";
      }
      $filter .= "(& $subfilter)";
    }
    $filter = "(| $filter)";
    $self->{so} = $self->{ldap}->search(base => $self->{base} || '',
				      async => 1,
				      sizelimit => $max_size,
				      timelimit => $max_time,
				      filter => "(&(objectclass=" .
				      $self->{objectclass} .')' .
				      $filter . ')');
    if ($self->{so}->code) {
      $self->{code} = ldap_error_text($self->{so}->code); 
      return 0;
    }
  } else {
    # We need to return everything;
    $self->{so} = $self->{ldap}->search(base => $self->{base} || '',
				      async => 1,
				      filter => "objectclass=" . $self->{objectclass});
    if ($self->{so}->code) {
      $self->{code} = ldap_error_text($self->{so}->code) ;
      return 0;
    }
  }
  undef $self->{code};
  return $self->{so}->count;
}

sub read {
  my $self = shift;
  my $class = ref $self || croak "Not a method call";
  if (! defined $self->{so}) {
    $self->reset;  
  } 
  if (defined (my $entry = $self->{so}->shift_entry)) {
    my $attr;
    my $ret = AddressBook::Entry->new(config=>$self->{config});
    foreach $attr ($entry->attributes) {
      if (exists $self->{config}->{db2generic}->{$self->{db_name}}->{$attr}) {
	$ret->add(db=>$self->{db_name},attr=>{$attr=>[$entry->get_value($attr)]});
      }
    }
    $ret->{timestamp} = _get_timestamp($entry);
    undef $self->{code};
    return $ret;
  } else {
    $self->{code} = ldap_error_text($self->{so}->code) ;
    return undef;
  }
}

sub _get_timestamp {
  my $entry=shift;
  my $timestamp;
  if ($entry->exists("modifytimestamp")) {
    ($timestamp) = $entry->get_value("modifytimestamp");
  } elsif ($entry->exists("createtimestamp")) {
    ($timestamp) =  $entry->get_value("createtimestamp");
  } else {
    $timestamp="today";
  }
  return ParseDate($timestamp);
}

sub reset {
  my $self = shift;
  my $class = ref $self || croak "Not a method call";
  $self->search;
}

sub update {
  my $self = shift;
  my $class = ref $self || croak "Not a method call";
  my %args = @_;
  my $count = $self->search(filter=>$args{filter});
  if ($count == 0){
    $self->{code} = "Update Error: filter did not match any entries";
    return 0;
  } elsif ($count > 1) {
    $self->{code} = "Update Error: filter matched multiple entries";
    return 0;
  }
  my $entry = $args{entry};
  $entry->calculate;
  my $old_entry=$self->read;
  my $rdn = $self->_rdn_from_entry($entry);
  my $old_rdn = $self->_rdn_from_entry($old_entry);
  my $result;
  if ($rdn ne $old_rdn) {
    $result=$self->{ldap}->moddn("$old_rdn," . $self->{base},deleteoldrdn=>1,newrdn=>$rdn);
    if ($result->code) {
      $self->{code} =  ldap_error_text($result->code) ;
      return 0;
    }
  }
  my %attr = %{$entry->get(db=>$self->{db_name},values_only=>'1')};
  $result=$self->{ldap}->modify("$rdn," . $self->{base},replace=>[%attr]);
  if ($result->code) {
    $self->{code} =  ldap_error_text($result->code) ;
    return 0;
  }
  undef $self->{code};
  return 1;
}

sub add {
  my $self = shift;
  my $class = ref $self || croak "Not a method call";
  my $entry = shift;
  $entry->calculate;
  my $dn = $self->_rdn_from_entry($entry) . "," . $self->{base};
  my %attr = %{$entry->get(db=>$self->{db_name},values_only=>'1')};
  $attr{objectclass} = [$self->{objectclass}];
  my $result = $self->{ldap}->add($dn, attrs => [%attr]);
  if ($result->code) {
    $self->{code} =  ldap_error_text($result->code) ;
    return 0;
  }
  undef $self->{code};
  return 1;
}

sub write {
  my $self = shift;
  my $class = ref $self || croak "Not a method call";
  return $self->add(@_);
}

sub delete {
  my $self = shift;
  my $class = ref $self || croak "Not a method call.";
  my $entry=shift;
  $entry->calculate;
  my $dn = $self->_rdn_from_entry($entry) . "," . $self->{base};
  my $result = $self->{ldap}->delete($dn);
  if ($result->code) {
    $self->{code} = ldap_error_text($result->code) ;
    return 0;
  }
  undef $self->{code};
  return 1;
}

sub code {
  my $self = shift;
  my $class = ref $self || croak "Not a method call.";
  return $self->{code};
}

sub _rdn_from_entry {
  my $self = shift;
  my $class = ref $self || croak "Not a method call";
  my $entry = shift || croak "Need an entry";
  my ($dn,$dn_calculate);
  my %attr = %{$entry->get(db=>$self->{db_name},values_only=>'1')};
  ($dn_calculate=$self->{dn_calculate}) =~ s/\$(\w*)/\$attr{$1}->[0]/g;
  eval qq{\$dn = $dn_calculate}; warn "Syntax error in dn_calculate: $@" if $@;
  return $dn;
}

1;
__END__

=head2 Timestamps

For syncronization purposes, all records are timestamped using the "modifytimestamp"
LDAP attribute.  If the record has no "modifytimestamp", "createtimestamp" is used.
If there is no "createtimestamp", the current time is used.

=head1 AUTHOR

Mark A. Hershberger, <mah@everybody.org>
David L. Leigh, <dleigh@sameasiteverwas.net>

=head1 SEE ALSO

L<AddressBook>,
L<AddressBook::Config>,
L<AddressBook::Entry>.

Net::LDAP

=cut



( run in 1.314 second using v1.01-cache-2.11-cpan-d80b1682f3f )