AddressBook::DB::LDIF - Backend for AddressBook to use LDIF files.


AddressBook documentation Contained in the AddressBook distribution.

Index


Code Index:

NAME

Top

AddressBook::DB::LDIF - Backend for AddressBook to use LDIF files.

SYNOPSIS

Top

  use AddressBook;
  $a = AddressBook->new(source => "LDIF",
			filename => "/tmp/ldif")

DESCRIPTION

Top

AddressBook::DB::LDIF supports sequential backend database methods.

AddressBook::DB::LDIF behavior can be modified using the following options:

key_fields

A list of LDIF attribute names (not cannonical names) which can be used to uniquely identify an entry.

base

The LDAP base for all entries

objectclass

The LDAP objectclass for entries

dn_calculate

A perl expression which, when eval'd returns a valid LDAP "dn" (omitting the "base" part of the dn). Other attributes may be referenced as "$<attr>".

For example, if LDIF entries have a dn like: "cn=John Doe,mail=jdoe@mail.com", then use the following:

  dn_calculate="'cn=' . $cn . ',mail=' . $mail"

Any of these options can be specified in the constructor, or in the configuration file.

new

The LDIF file is specified using the "filename" parameter:

  $a = AddressBook->new(source => "LDIF",
			filename => "/tmp/ldif")

The filename may also be specified in the configuration file.

Timestamps

For syncronization purposes, all records are timestamped with the modification date of the LDIF file.

AUTHOR

Top

David L. Leigh, <dleigh@sameasiteverwas.net>

SEE ALSO

Top

AddressBook, AddressBook::Config, AddressBook::Entry.

Net::LDAP


AddressBook documentation Contained in the AddressBook distribution.
package AddressBook::DB::LDIF;

use strict;
use AddressBook;
use Carp;
use Net::LDAP::LDIF;
use Net::LDAP::Entry;
use IO::File;
use Date::Manip;

use vars qw($VERSION @ISA);

$VERSION = '0.13';

@ISA = qw(AddressBook);

sub new {
  my $class = shift;
  my $self = {};
  bless ($self,$class);
  my %args = @_;
  foreach (keys %args) {
    $self->{$_} = $args{$_};
  }
  $self->{mode} = "";
  if (defined $self->{filename}) {
    $self->{fh} = IO::File->new($self->{filename},O_RDWR | O_CREAT)
	|| croak "Couldn't open `" . $self->{filename} . "': $@";
    $self->{ldif} = Net::LDAP::LDIF->new($self->{fh});
  }
  return $self;
}

sub DESTROY {$_[0]->fh->close}

sub reset {
  my $self = shift;
  my $class = ref $self || croak "Not a method call.";
  $self->{fh}->seek(0,0);
  $self->{mode} = "";
}

sub truncate {
  my $self = shift;
  my $class = ref $self || croak "Not a method call.";
  $self->{fh}->truncate(0);
}

sub read {
  my $self = shift;
  my $class = ref $self || croak "Not a method call.";
  if ($self->{mode} eq "w") {
    croak "Error:  After writing, do a reset before reading";
  }
  $self->{mode} = "r";
  if (my $ldap_entry = $self->{ldif}->read) {
    my $ret = AddressBook::Entry->new(config=>$self->{config});
    foreach ($ldap_entry->attributes) {
      if (exists $self->{config}->{db2generic}->{$self->{db_name}}->{$_}) {
	$ret->add(db=>$self->{db_name},attr=>{$_=>[$ldap_entry->get_value($_)]});
      }
    }
    $ret->{timestamp} = $self->_get_timestamp;
    return $ret;
  } else {
    return undef;
  }
}

sub write {
  my $self = shift;
  my $class = ref $self || croak "Not a method call";
  $self->{fh}->seek(0,2); # jump to the end of the file
  $self->{mode} = "w";
  my $entry = shift;
  $entry->calculate;
  my $dn = $self->_dn_from_entry($entry);
  my %attr = %{$entry->get(db=>$self->{db_name},values_only=>'1')};
  $attr{objectclass} = [$self->{objectclass}];
  my $ldap_entry = Net::LDAP::Entry->new();
  $ldap_entry->dn($dn);
  $ldap_entry->add(%attr);
  $self->{ldif}->write($ldap_entry);
}

sub _dn_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 $@;
  $dn .= "," . $self->{base};
  return $dn;
}

sub _get_timestamp {
  my $self = shift;
  my $class = ref $self || croak "Not a method call";
  my @stat = stat($self->{filename});
  return ParseDateString("epoch $stat[9]");
}

1;