package CGI::Kwiki::Plugin::LDAP;

$VERSION='0.3';
use strict;
use CGI::Kwiki qw( 0.18 );
use Net::LDAP;

use base qw( CGI::Kwiki::Plugin );

sub methods { qw( show_value show_card ) }

my (@display_order) = qw(title mail pager telephoneNumber mobile homePhone);
my (%display_names) = (
  'title'           => 'Title',
  'mail'            => 'Email',
  'telephoneNumber' => 'DDI',
  'pager'           => 'Extension',
  'mobile'          => 'Mobile Phone',
  'homePhone'       => 'Home Phone'
);

my ($ldap_dn)       = '';
my ($ldap_password) = '';
my ($ldap_base)     = 'ou=People,dc=actrix,dc=co,dc=nz';

# __NICK__ here is replaced by whatever is passed is from the calling
# Wiki page.
my ($ldap_filter)   = "(uid=__NICK__)";

my ($ldap_hostname) = 'localhost';

# Connect to the LDAP server.
sub connect {
  my ($self) = shift;

  $self->{'_ldap'} = Net::LDAP->new($ldap_hostname)
    || die $@;

  # Just in case we have to bind as a specific user.
  $self->{'_ldap'}->bind(dn => $ldap_dn, password => $ldap_password)
    || die $@;
}

# Disconnect from the LDAP server.
sub disconnect {
  my ($self) = shift;

  $self->{'_ldap'}->unbind;
}

# Perform a query based on one variable and fetch back a selection of
# attributes as specified by $attrs.
sub fetch {
  my ($self)  = shift;
  my ($nick)  = shift;
  my ($attrs) = shift;

  $self->connect;

  # Build the filter we're going to use.
  (my $filter = $ldap_filter) =~ s/__NICK__/$nick/g;

  my $mesg = $self->{'_ldap'}->search (
    base   => $ldap_base,
    filter => $filter,
    attrs  => $attrs
  );

  $mesg->code && die "filter: $filter\nmsg: $mesg->error\n";

  return $mesg;
}

# Return the value associated with only one attribute in LDAP for $nick.
sub show_value {
  my ($self) = shift;
  my ($nick) = shift;
  my ($key)  = shift;
  my ($txt)  = undef;

  # We just want to fetch $key.
  my ($mesg) = $self->fetch($nick, [ $key ]);

  my $entry_count = $mesg->count;

  # We start out by doing a little sanity checking.
  if ($entry_count > 1) {
    $txt = "That's strange, more than one LDAP entry with '$nick' was found.\n";
  } elsif ($entry_count < 1) {
    $txt = "No details found for '$nick'."


  } else {
    my $entry = $mesg->entry(0);

    # If there isn't actually anything in that attribute let the user know.
    # Otherwise return the goodness.
    if (defined $entry->get_value($key)) {
      $txt = $entry->get_value($key);
    } else {
      $txt = "No value found for nick '$nick' with key '$key'.";
    }
  }

  # We're finished with the connection, take down the session.
  $self->disconnect;

  # We'd better process it.
  $txt = $self->driver->formatter->process($txt);
  $txt =~ s/^<p>//;
  $txt =~ s/<\/p>$//;

  return $txt;
}

# Produce a business card type of affair.  Produces it as a Wiki Table.
sub show_card {
  my ($self) = shift;
  my ($nick) = shift || $self->cgi->page_id;
  my ($txt)  = "";

  # We just want to fetch all attributes they want displayed.
  my ($mesg) = $self->fetch($nick, \@display_order);

  my $entry_count = $mesg->count;

  # We start out by doing a little sanity checking.
  if ($entry_count > 1) {
    $txt = "That's strange, more than one LDAP entry with '$nick' was found.\n";
  } elsif ($entry_count < 1) {
    $txt = "No details found for '$nick'."
  } else {

    my $entry = $mesg->entry(0);
    foreach my $key (@display_order) {
	  $txt .= "| "
	        . (defined $display_names{$key} ? $display_names{$key} : $key)
	        . " | "
		. ($entry->get_value($key) ne '' ? $entry->get_value($key) : '-')
		. " |\n";
    }
  }

  # We're finished with the connection, take down the session.
  $self->disconnect;

  # We'd better process it.
  $txt = $self->driver->formatter->process($txt);
  $txt =~ s/^<p>//;
  $txt =~ s/<\/p>$//;

  return $txt;
}

=head1 NAME 

CGI::Kwiki::Plugin::LDAP - An LDAP query plugin for CGI::Kwiki

=head1 DESCRIPTION

This plugin allows business cards to be displayed from LDAP with in Kwiki
pages.   Another feature is to show just one field associated with an
entry in LDAP.  This allows titles to be placed at the top of users
pages for example.

=head1 USAGE

Drop this file into CGI/Kwiki/Plugin and edit the LDAP settings at the top
of the file.  Then in your Wiki pages put in:

  [% LDAP.show_card(puck) %]

And puck's business card will be displayed.  If no parameter is passed then
the page name is used for performing the lookup.

Or try:

  [% LDAP.show_value(puck cn) %]

Will display puck's common name (in my case "Andrew Ruthven" would be
displated).

In all cases if no data is found a suitable error message is returned.

=head1 ISSUES

The problem with using the [% ... %] notation is the HTML returned by
the plugin call is visibile in the edit page, this can lead to confusion
and possible over writing of the plugin call.

Geoff Hubbard has come up with a work around.  Create a Kwiki formatter
module (see http://www.kwiki.org/index.cgi?KwikiFormatterModule) using
a function like:

  sub plugins {
    my ( $self, $text ) = @_;
    $text =~ s#\[plugin: ([^\]]*)]#[% $1 %]#g;
    return $text;
  }

Then using:

  [plugin: LDAP.show_card(puck)]

Will do the right thing.

=head1 SEE ALS0

C<CGI::Kwiki>

=head1 AUTHOR

Andrew Ruthven <andrew@etc.gen.nz>

=head1 COPYRIGHT

Copyright (c) 2004. Andrew Ruthven. All rights reserved.

This program is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.

See http://www.perl.com/perl/misc/Artistic.html

=cut


1;
