#!/usr/bin/perl
use Net::LDAP::LDIF;
use Getopt::Long;
use MIME::Base64;

my $opts_good = GetOptions(
  'h|help' => \$help,
  'b|base=s' => \$base,
  'f|file=s' => \$file,
);

if (!$opts_good) {
        print STDERR "\n";
        usage();
}

if ($help) {
  usage(0);
}

if (!($base)) {
  usage(0);
}

if (!($file)) {
  usage(0);
}

my $ldifin = Net::LDAP::LDIF->new( "$file", "r", onerror => 'undef', encode=>'base64' );
while( not $ldifin->eof()) {
  my $entry = $ldifin->read_entry ( );
  if ( $ldifin->error ( ) ) {
    print "Error msg: ", $ldifin->error ( ), "\n";
    print "Error lines:\n", $ldifin->error_lines ( ), "\n";
    } elsif ( $entry ) {
      if ($entry->dn() eq $base) {
        next;
      }
      my $addPrev="";
      my $replacePrev="";
      my $delPrev="";
      my $result = $entry->get_value('reqResult');
      if ($result == 0) {
        my $type = $entry->get_value('reqType');
        my $mdn = $entry->get_value('reqDN');
        if ($type eq "modify") {
          print "dn: $mdn\n";
          print "changetype: modify\n";
          my $mod = $entry->get_value('reqMod', asref => 1);
          foreach my $attrline (@$mod) {
            my ($attr, $change) = split /:/, $attrline, 2;
            if ($attr eq "entryCSN") {
              next;
            }
            if ($attr eq "modifiersName") {
              next;
            }
            if ($attr eq "modifyTimestamp") {
              next;
            }
            my $ctype = substr $change, 0, 1, "";
            substr $change, 0, 1, "";
            my $mchange=MIME::Base64::encode($change,"");
            chomp($mchange);
            if ($ctype eq "=") {
              if ($replacePrev ne $attr && $replacePrev ne "") {
                print "-\n";
              }
              if ($replacePrev ne $attr) {
                print "replace: $attr\n";
                $replacePrev=$attr;
              }
              if ($change ne "") {
                print "$attr"."::"."$mchange\n";
              }
              $delPrev=".x.";
              $addPrev=".x.";
            } elsif ($ctype eq "-") {
              if ($delPrev ne "" and $delPrev ne $attr) {
                print "-\n";
              }
              if ($delPrev ne $attr) {
                print "delete: $attr\n";
                $delPrev=$attr;
	      }
              if ($change ne "") {
                print "$attr"."::"."$mchange\n";
              }
              $addPrev=".x.";
              $replacePrev=".x.";
            } elsif ($ctype eq "+") {
              if ($addPrev ne "" and $addPrev ne $attr) {
                print "-\n";
              }
              if ($addPrev ne $attr) {
                print "add: $attr\n";
                $addPrev = $attr;
              }
              print "$attr"."::"."$mchange\n";
              $delPrev=".x.";
              $replacePrev=".x.";
            }
          }
          print "-\n\n";
        } elsif ($type eq "delete") {
          print "dn: $mdn\n";
          print "changetype: delete\n";
          print "\n";
        } elsif ($type eq "add") {
          print "dn: $mdn\n";
          print "changetype: add\n";
          my $add = $entry->get_value('reqMod', asref => 1);
          foreach my $attrline (@$add) {
            my ($attr, $change) = split /:/, $attrline, 2;
            if ($attr eq "structuralObjectClass") {
              next;
            }
            if ($attr eq "entryUUID") {
              next;
            }
            if ($attr eq "creatorsName") {
              next;
            }
            if ($attr eq "createTimestamp") {
              next;
            }
            if ($attr eq "entryCSN") {
              next;
            }
            if ($attr eq "modifiersName") {
              next;
            }
            if ($attr eq "modifyTimestamp") {
              next;
            }
            my $ctype = substr $change, 0, 1, "";
            substr $change, 0, 1, "";
            my $mchange=MIME::Base64::encode($change,"");
            chomp($mchange);
            if ($change ne "") {
              print "$attr"."::"."$mchange\n";
            }
          }
          print "\n";
        } elsif ($type eq "modrdn") {
          print "dn: $mdn\n";
          print "changetype: modrdn\n";
          my $newDN = $entry->get_value('reqNewRDN');
          print "newrdn: $newDN\n";
          my $deleteDN = $entry ->get_value('reqDeleteOldRDN');
          if ($deleteDN eq "TRUE") {
            print "deleteoldrdn: 1\n";
          } else {
            print "deleteoldrdn: 0\n";
          }
          print "\n";
        }
      } else {
        next;
      }
    }
}

sub usage() {
  print STDERR <<USAGE;
  accesslog-to-ldif -b "accesslog base" -f "inputfile"

USAGE
  exit(1);
}

