package ISPMan::LDAP;

use strict;
use Net::LDAP;
use Net::LDAP::Entry;
use Net::LDAP::LDIF;
use IO::ScalarPatched;

use Net::LDAP::Util qw(ldap_error_name ldap_error_text) ;
use vars qw($VERSION @ISA @EXPORT @EXPORT_OK $LDAP $Config);
use ISPMan::Utils;


require Exporter;

@ISA = qw(Exporter AutoLoader);
@EXPORT = qw(
addDomain
);
$VERSION = '0.01';

use ISPMan::Config;
$Config=ISPMan::Config->new();
use ISPMan::Log;


sub new {
   my $proto = shift;
   my $class = ref($proto) || $proto;   
   my $self;
   ($self->{'basedn'}, $self->{'host'},  $self->{'user'}, $self->{'pass'})=@_;
   return bless $self, $class;
}

sub connect{
   my $self=shift;
   if ($LDAP) {
      log_event("LDAP connection already exists\n");
      return;
   }
   $LDAP=Net::LDAP->new($self->{'host'});
   try($LDAP->bind(dn => $self->{'user'}, password => $self->{'pass'}));
   $self->{'connected'}++;
   log_event("Connected to LDAP Server $self->{'host'}");
}


sub connected {
   my $self=shift;
   return $self->{'connected'};
}



sub entries2HashRef {
   my $self=shift;
   my $entry=shift;
   my $temphash={};
   my @vals;

   for my $attr($entry->attributes()) {
      @vals=();
      undef @vals;
      @vals= $entry->get_value($attr);

      if (scalar(@vals)>1) {
         $temphash->{$attr}=[@vals];
      } else {
         $temphash->{$attr}=$vals[0];
      }
   }
   
   return $temphash;
}
   

sub getEntriesAsHashRef {
   my $self=shift;
   my @entries=$self->getEntries(@_);
   my $dn;
   my $hashref;
   my $temphash;

   my @vals;

   for (@entries) {
      $hashref->{$_->dn()}=$self->entries2HashRef($_);
   }
   return $hashref;
}


sub getEntries {
   my $self=shift;
   my ($base, $filter, $attr)=@_;
   $filter||="objectclass=*";
   
   my $mesg= $LDAP->search(base => $base, filter => "($filter)", "attrs" => $attr);
   my @entries= $mesg->entries;
   return @entries;
}

sub getEntry {
   my $self=shift;
   my $dn=shift;
   my $attrs=shift || [];

   my $mesg= $LDAP->search(base => $dn, filter => "(objectclass=*)", "attrs" => $attrs);
   my ($entry)= $mesg->entry(0);
   return $entry;
}



sub getEntryAsHashRef {
   my $self=shift;
   return $self->entries2HashRef($self->getEntry(@_));
}


sub try {
   my $result=shift;
   if ( $result->code ) {
      LDAPerror("Searching",$result);
      return 0;
   } else {
      return 1;
   }
}

sub LDAPerror{
   my ($from,$mesg) = @_;
   print "<pre>\n";
   print "\nReturn code: ",$mesg->code ;
   print "\nMessage: ", ldap_error_name($mesg->code);
   print " \n",        ldap_error_text($mesg->code);
   print " \nMessageID: ",$mesg->mesg_id;
   print "\nDN: ",$mesg->dn;
   print "\n</pre>\n";
}


sub delTree {
   my $self=shift;
   my $dn=shift;
   my $mesg= $LDAP->search(base => $dn, filter => "(objectclass=*)", "attrs" => []);
   my @entries= $mesg->entries;
   for (reverse  @entries){;
      $self->deleteEntry($_->dn());
   }
}



sub updateEntryWithData {
   my $self=shift;
   my $dn=shift;
   my $data=shift;
   
   my $entry=$self->getEntry($dn);
   
   for (keys %$data) {
      $entry->replace($_, $data->{$_});
   }
   try ($entry->update($LDAP));
}


sub addData2Entry {
   my $self=shift;
   my $dn=shift;
   my $data=shift;
   
   my $entry=$self->getEntry($dn);
   
   for (keys %$data) {
      $entry->add($_, $data->{$_});
   }
   try ($entry->update($LDAP));
}




sub dumpEntry {
   my $self=shift;
   my $entry=shift;
   print "<pre>\n";
   $entry->dump();
   print "\n</pre>\n";
}

sub updateEntry {
   my $self=shift;
   my $r=shift;
   
   my $entry=$self->getEntry($r->param("dn"));
   for ($entry->attributes) {
      log_event("Attribute $_");
      if ($r->param($_)) {
         log_event( "Replacing $_ with " , $r->param($_));

         $entry->replace($_, $r->param($_));
      }
   }
   try ($entry->update($LDAP));
}



sub addEntry {
   my $self=shift;
   my $r=shift;
   
   my $entry=$self->getEntry($r->param("dn"));
   $entry->add("record", $r->param("record"));
   try($entry->update($LDAP));
}

sub AddUser {
   my $self=shift;
   my $r=shift;
   my $entry=Net::LDAP::Entry->new();
   $entry->changetype("add");
   $entry->dn($r->param("dn"));
   
   log_event("Adding user with dn ", $r->param("dn"));


   $entry->add(
            "uid" =>  $r->param("uid"),
            domain => $r->param("domain"),
            userid => $r->param("userid"),
            cn => $r->param("userid"),
            maildrophost => $r->param("maildrophost") || "",
            userpassword => $r->param("userpassword") || "noEntry",
            givenname => $r->param("givenname"),
            sn => $r->param("sn"),
            objectclass => ["top", "person", "organizationPerson", "inetOrgPerson"]
   );
   
   $entry->add(mail => join '@', ($r->param("userid"), $r->param("domain")));
   $entry->add(mailacceptinggeneralid => join '@', ($r->param("userid"), $r->param("domain")));
   
   if ($r->param("maildrophost")){
      $entry->add(maildrop => join '@', ($r->param("uid"), $r->param("maildrophost")));
   } else {
      $entry->add(maildrop => "");
	}

   if (try($entry->update($LDAP))){
      log_event("User Added in LDAP");
      return 1;
      } else {
         return 0;
      }
}



sub AddVhost {
   my $self=shift;
   my $r=shift;
   my $entry=Net::LDAP::Entry->new();
   $entry->changetype("add");
   $entry->dn($r->param("dn"));
   
   log_event("Adding vhost  with dn ", $r->param("dn"));


   $entry->add(
            "cn" =>  $r->param("cn"),
            domain => $r->param("domain"),
            documentroot => (join '/', ($r->param("cn"), "htdocs")),
            scriptdir => (join '/', ($r->param("cn"), "cgi-bin")),
            extraconf => "",
            serveralias => "",
            objectclass => ["top", "httpdata", "virtualHost"],
   );
   
   if (try($entry->update($LDAP))){
      log_event("Vhost  Added in LDAP");
      return 1;
      } else {
         return 0;
      }
}


sub DeleteUser {
   my $self=shift;
   my $dn=shift;
   my $entry=Net::LDAP::Entry->new();
   $entry->changetype("delete");
   $entry->dn($dn);
   log_event("Trying to delete   $dn from LDAP");

   $entry->delete();
   if (try($entry->update($LDAP))){
      log_event("User deleted from LDAP");
      return 1;
   }

}


sub deleteVhost {
   my $self=shift;
   my $r=shift;
   my $entry=Net::LDAP::Entry->new();
   $entry->changetype("delete");
   $entry->dn($r->param("dn"));
   log_event("Trying to delete ", $r->param("dn") , "from LDAP");

   $entry->delete();
   if (try($entry->update($LDAP))){
      log_event("User deleted from LDAP");
      return 1;
   }
}

sub deleteEntry {
   my $self=shift;
   my $dn=shift;
   my $entry=Net::LDAP::Entry->new();
   $entry->changetype("delete");
   $entry->dn($dn);
   log_event("Trying to delete ", $dn , "from LDAP");

   $entry->delete();
   if (try($entry->update($LDAP))){
      log_event("Entry deleted from LDAP");
      return 1;
   }
}



sub deleteDomain {
   my $self=shift;
   my $r=shift;
   my $domain=$r->param("domain");
}




sub addDomain {
   my $self=shift;
   my $r=shift;
   $ISPMan::domain=$r->param("domain");
   my $domain=$ISPMan::domain;

   my $template=$self->getTemplate("/usr/pkg/etc/ispman/templates/domain.ldif.template");
   my $text= $template->fill_in(PACKAGE => "ISPMan");
   tie *OUT, 'IO::Scalar', \$text;
   my $ldif = Net::LDAP::LDIF->new(\*OUT,"r");
   
   while( my $entry = $ldif->read() ) {
         $entry->changetype("add");
         $entry->update($LDAP);
   }

   $ldif->done();
   
   $r->param("dn", "cn=www, ou=httpdata, domain=$domain, $Config->{'ldapBaseDN'}");
   $r->param("cn", "www");
   $self->AddVhost($r);
}

1;
__END__

