#!/usr/bin/perl 

########################################################
#  389 Directory Server Configuration File Parser (dse.ldif)
#
#  dseconv.pl  v1.1 
#
#  Written By:  Mark Reynolds (mreynolds@redhat.com)
#
########################################################

#############
#  Modules  #
#############

use POSIX qw (asctime);
#use MIME::Base64;

##########################
#  Initialize Variables  #
##########################

$version = "1.0";
$| = 1;
$count = "0";
# $outFile = "newDse.ldif";
$outfile = "";
$skipACI = "no";
$outFile = "";
$skipPlugin = "no";
$entries = "0";
$totalentries = 0;
@buff = [];
my $index = {};
$tt = "";
@buf = [];
my $backend = "";
$skipedEntries = "0";
$verbose = "no";
$showPlugin = "no";
$entryCache = "0";
$dbcache = "0";
$progressCount = "0";
$size = "25";


##################################
#  Define default config values  # 
##################################

#  cn=config

@defaultConfig = (
"accesslog-logging-enabled: on",
"accesslog-maxlogsperdir: 10",
"accesslog-maxlogsize: 100",
"accesslog-logrotationtime: 1",
"accesslog-logrotationtimeunit: day",
"accesslog-logrotationsync-enabled: off",
"accesslog-logrotationsynchour: 0",
"accesslog-logrotationsyncmin: 0",
"enquote-sup-oc: off",
"schemacheck: on",
"rewrite-rfc1274: off",
"return-exact-case: on",
"errorlog-logging-enabled: on",
"errorlog-maxlogsperdir: 2",
"errorlog-maxlogsize: 100",
"errorlog-logrotationtime: 1",
"errorlog-logrotationtimeunit: week",
"errorlog-logrotationsync-enabled: off",
"errorlog-logrotationsynchour: 0",
"errorlog-logrotationsyncmin: 0",
"maxdescriptors: 1024", 
"syntaxcheck: on",
"dn-validate-strict: off",
"ssl-check-hostname: on",
"validate-cert: warn",
"allow-unauthenticated-binds: off",
"require-secure-binds: off",
"allow-anonymous-access: on",
"ldapilisten: off",
"max-filter-nest-level: 40",
"minssf: 0"
);


@defaultIndex = (
"aci:  pres",
"entrydn:  eq",
"entrydn:  subtree",
"entryrdn:  subtree",
"entryusn:  eq",
"nscpentrydn:  eq",
"nsds5replconflict:  eq pres",
"nsuniqueid:  eq",
"numsubordinates:  pres",
"objectclass:  eq",
"parentid:  eq"
);

#  Ldbm Config

@defaultLdbmConfig = (

"lookthroughlimit: 5000",
"mode: 600",
"exclude-from-export: entrydn entryid dncomp parentid numSubordinates tombstonenumsubordinates entryusn",
"idlistscanlimit: 4000",
"dbcachesize: 10000000",
"db-durable-transaction: on",
"db-checkpoint-interval: 60",
"db-transaction-batch-val: 0",
"db-logbuf-size: 0",
"db-private-import-mem: on",
"import-cache-autosize: -1",
"import-cachesize: 20000000",
"idl-switch: new",
"search-bypass-filter-test: on",
"search-use-vlv-index: on",
"serial-lock: on",
"subtree-rename-switch: on",
"pagedlookthroughlimit: 0",
"pagedidlistscanlimit: 0"
);


#  Backend Config

@defaultBackendConfig = (

"cachesize: -1",
"cachememsize: 10485760",
"readonly: off",
"dncachememsize: 10485760",
"require-index: off"
);

# default instance config - chaining

@defaultInstanceConfig = (
"nstransmittedcontrols: 2.16.840.1.113730.3.4.2",
"nstransmittedcontrols: 2.16.840.1.113730.3.4.9",
"nstransmittedcontrols: 1.2.840.113556.1.4.473",
"nstransmittedcontrols: 1.3.6.1.4.1.1466.29539.12"
);


################################
#  Grab the command line args  # 
################################

if ($#ARGV < 1){
	&displayUsage;
	exit(1);
}


while ($count <= $#ARGV){
        if ($ARGV[$count] eq "-f"){
                $filename = $ARGV[++$count];
        }
	elsif ($ARGV[$count] eq "-o"){
                $outFile = $ARGV[++$count];
                $usingFile = "1";
                open (OUTFILE,">$outFile") || die "Cannot open $outFile!\n";
                select OUTFILE;
        }
	elsif ($ARGV[$count] eq "-aci"){
		$skipACI = "yes";
	}
	elsif ($ARGV[$count] eq "-p"){
		$showPlugin = "yes";
	}
	elsif ($ARGV[$count] eq "-V"){
		$verbose = "yes";
	}
	elsif ($ARGV[$count] eq "-plugin"){
		$skipPlugin = "yes";
	}
	elsif ($ARGV[$count] eq "-s"){
		$size = $ARGV[++$count];
	}
	else {
                print "Invalid switch " . $ARGV[$count] . "\n";
                &displayUsage;
                exit(1);
        }

        $count++;
}


#
# if a outfile is not provided, then use stdout
#

if ($outFile eq ""){
	open(OUTFILE,">-");  
}


###################
#  Print  Header  #
###################

print OUTFILE "\n389 Configuration File Converter\n";
print OUTFILE "Version $version\n\n";

print OUTFILE "Reading $filename...";


###########################################################
#  Read in and process all the entries in the dse.ldif    #
###########################################################

$start = "0";
$full = "0";

open (LDIF,"$filename") || die "Could not open $filename!\n";

        while (<LDIF>){
		$_ =~ s/\r//g;  # remove control M's if any

                if (/^dn: / && $start > "0"){
                        @fullbuff = @buffer;
                        for ($i = 0; $i <= $#buffer; $i++) {$buffer[$i] = "";}
                        $full = "1";
                        $start = "0";
                        $buffer[$start] = $_;
                        $start++;
                }
                elsif (/^dn: / && $start eq "0"){
                        $buffer[$start] = $_;
                        $start++;       
                }
                else {
                        $buffer[$start] = $_;
                        $start++;
                }

                if ($full eq "1"){
                        $full = "0";
                        &processBuff(@fullbuff);
                }

		$progressCount++;
		if ($progressCount eq "20"){
			print STDOUT  ".";
			$progressCount = "0";
		}
        }

&processBuff(@buffer);
close (LDIF);
print "\n";


########################
#  Display the report  #
########################

print OUTFILE "\n\n";
print OUTFILE "----------------------------------------------------------\n";
print OUTFILE " Config File Processing Statistics\n";
print OUTFILE "----------------------------------------------------------\n";
print OUTFILE "\n";
print OUTFILE "\tTotal Entries:      $totalentries\n";
print OUTFILE "\tSkipped Entries:    $skipedEntries\n";
print OUTFILE "\t------------------------\n";
print OUTFILE "\tProcessed Entries:  $entries\n";


print OUTFILE "\n\n";
print OUTFILE "----------------------------------------------------------\n";
print OUTFILE " Cache Sizes\n";
print OUTFILE "----------------------------------------------------------\n\n";

# calcuate the caches 

$cache = $dbcache / 1024;
$cache =~ s/\..*//;

$kcache = $entryCache / 1024;
$kcache =~ s/\..*//;

$totalCache = $dbcache + $entryCache;
$tcache = $totalCache / 1024;
$tcache =~ s/\..*//;

if ($tcache < 1024){
        $megcache = "0";
} else {
	$megcache = $tcache / 1024;
	$megcache =~ s/\..*//;
}

if ($megcache > 1024){
	$gigcache = $megcache / 1024;
	$gigcache =~ s/\..*//;
#	if($gigcache =~ / *([0-9][0-9][0-9]\.[0-9][0-9])/){
#		$gigcache = $1;
#	}
	$yes_to_gig = 1;
}

print OUTFILE "\tTotal DB Cache:     " . commify($cache) . " Kb  ($dbcache bytes)\n";
print OUTFILE "\tTotal Entry Cache:  " . commify($kcache) . " Kb  ($entryCache bytes)\n";
print OUTFILE "\t--------------------------------------------------\n";
if ($yes_to_gig){
	print OUTFILE "\tTotal Cache Size:   " . commify($gigcache) . " Gb,  " . commify($megcache) . " Mb,  " . commify($tcache) . " Kb,  ($totalCache bytes)\n";  
} else {
	print OUTFILE "\tTotal Cache Size:   " . commify($megcache) . " Mb,  " . commify($tcache) . " Kb,  ($totalCache bytes)\n";
}
print OUTFILE "\n\n\n";


$arg = 0;
print OUTFILE "----------------------------------------------------------\n";
print OUTFILE " Main Configuration\n";
print OUTFILE "----------------------------------------------------------\n\n";

psort ("config");


print OUTFILE "\n\n\n\n----------------------------------------------------------\n";
print OUTFILE " LDBM Database Configuration\n";
print OUTFILE "----------------------------------------------------------\n\n";

$arg = 0;
while($ldbmConfig{"ldbm database"}[$arg] && $ldbmConfig{"ldbm database"}[$arg] ne "\n"){
	if ($ldbmConfig{"ldbm database"}[$arg] =~ m/^-> /){
                print OUTFILE "     " . $ldbmConfig{"ldbm database"}[$arg]  . "\n";
	} else {
		print OUTFILE "\t" . $ldbmConfig{"ldbm database"}[$arg] . "\n";
	}
	$arg++;
}


print OUTFILE "\n\n\n\n----------------------------------------------------------\n";
print OUTFILE " Backends ($backendCount)\n";
print OUTFILE "----------------------------------------------------------\n\n\n";


foreach $bac (sort keys %ldbm){
	$dbac = "[$backendCount] \"$bac\"";
	print OUTFILE "[$backendCount] \"$bac\"\n";
	print OUTFILE "-" x length $dbac;
	print OUTFILE "\n\n";

	$backendCount--;
	$cc = 1;
	while ($ldbm{$bac}[$cc]){
		# grab the suffix name for later use
		if ($ldbm{$bac}[$cc] =~ /suffix: /i){
			$nbac = $ldbm{$bac}[$cc];
			$nbac =~ s/suffix: //i;
			$nbac =~ s/"//;
			$nbac = "cn=" . $nbac;
		}

		if ($ldbm{$bac}[$cc] =~ m/^-> /){
                	print OUTFILE "     " . $ldbm{$bac}[$cc] . "\n";
		} else {
			print OUTFILE "\t$ldbm{$bac}[$cc] \n";
		}
		$cc++;
	}

	$rbac = $nbac;

#
#
#  Don't forget to grab the backend and state from the mapping tree entry!!!!!
#
#

	print OUTFILE "\n\tIndexes: \n";
	foreach $keys (sort keys %index){
		if ($keys eq $bac){
			foreach $indexValue ( sort{ $a cmp $b} keys %{$index{$keys}}){
				print OUTFILE "\t   $indexValue\n";
			}
		}
	}

	# repl config

	$nnbac = $nbac;
	$nbac =~ s/\,.*//; 

	if ($replConfig{$bac} || $replConfig{$nbac} || $replConfig{$nnbac}){
		if ($replConfig{$nbac}{"replType"} ne ""){
			$rType = $replConfig{$nbac}{"replType"};
			delete ($replConfig{$nbac}{"replType"});
		}
		if ($replConfig{$bac}{"replType"} ne ""){      
                        $rType = $replConfig{$bac}{"replType"}; 
                        delete ($replConfig{$bac}{"replType"});        
                }
		if ($replConfig{$rbac}{"replType"} ne ""){
                        $rType = $replConfig{$rbac}{"replType"};
                        delete ($replConfig{$rbac}{"replType"});
                }

			
		print OUTFILE "\n\n\tReplication Configuration: (" . $rType . ")\n";

		foreach $repl (keys %replConfig){
			if ($repl eq $bac || $repl eq $nbac || $repl eq $rbac){
				foreach $replica (sort {$a cmp $b} keys %{$replConfig{$repl}}){
					print OUTFILE "\t   $replica\n";
				}
			}
		}
	}

	# repl agreements

	$rb = "0";
	$ok = "0";
	$rc = "1";

	foreach $replExist (sort keys %replAgr){
		if ($replExist =~ m/^$bac/i || $replExist =~ m/^$nbac/i || $replExist =~ m/^$rbac/i){
			$ok = "1";
			$rb = $replExist;
			break;
		}
	}

	if ($ok eq "1"){
		$ok = "0";
		print OUTFILE "\n\n\tReplication Agreements\n";

		foreach $ragr (keys %replAgr){
			$ndn = $ragr;
			$ndn =~ s/---[0-9]+//;

			if ($ndn =~ /^$bac/i || $ndn =~ /^$nbac/i || $ndn =~ /^$rbac/i ){
				if ($replAgr{$ragr}{"Fractional"} eq "yes"){
					delete ($replAgr{$ragr}{"Fractional"});

					print OUTFILE "\n\t   [$rc] " .$replAgr{$ragr}{"dn"} . " (Fractional Replication Agreement)" . "\n";
					print OUTFILE "\t   -"  .  "-" x length $replAgr{$ragr}{"dn"} . " (Fractional Replication Agreement)" . "--\n";
				} else {
					delete ($replAgr{$ragr}{"Fractional"});
					print OUTFILE "\n\t   [$rc] " .$replAgr{$ragr}{"dn"} . "\n";
                        		print OUTFILE "\t   -"  .  "-" x length $replAgr{$ragr}{"dn"} . "--\n";
				}

				delete ($replAgr{$ragr}{"dn"});
				$rc++;   
				
				foreach $agr ( sort {$a cmp $b}keys %{$replAgr{$ragr}}){
					print OUTFILE "\t   $agr\n";
				}
			}
		}
	} # end of repl stuff
			
	# VLV Stuff
	if ($vlvIndex{$bac} || $vlvIndex{$nbac} || $vlvIndex{$rbac}){
		print OUTFILE "\n\n\tVLV Indexes:\n";

		$vlvRunningCount = "0";
		$vlvRunningCount++;

		foreach $vlvI ( keys %vlvSearch){
			if ($vlvI eq $bac || $vlvI eq $nbac || $vlvI eq $rbac){
				# matched the backend, but which normalization of the backend name...

				if ($vlvI eq $bac){ $vlvBac = $bac;}
				if ($vlvI eq $nbac){ $vlvBac = $nbac;}
				if ($vlvI eq $rbac){ $vlvBac = $rbac;}
				

				foreach $vlvS ( sort {$a cmp $b} keys %{$vlvSearch{$vlvBac}}){

					if ($vlvSearch{$vlvBac}{$vlvS}{"parent"} eq "" ){
						$parentName = $vlvSearch{$vlvBac}{$vlvS}{"name"};

						print OUTFILE "\n\n\n\t   " . "[" . $vlvRunningCount . "]  \"cn=" . $vlvSearch{$vlvBac}{$vlvS}{"name"} . "\"\n";
						$vlvRunningCount++;

						print OUTFILE "\t   " . "-" x length $vlvRunningCount . "]  \"cn=" . $vlvSearch{$vlvBac}{$vlvS}{"name"} . "\"\n";
						print OUTFILE "\n";

						delete ($vlvSearch{$vlvBac}{$vlvS}{"name"});

						foreach $vlvAttr (sort keys %{$vlvSearch{$vlvBac}{$vlvS}}){
							print OUTFILE "\t\t        $vlvAttr\n";
						}

						# print its index/child entry
						foreach $vlvChild ( sort {$a cmp $b} keys %{$vlvIndex{$vlvBac}}){
							if ($vlvIndex{$vlvBac}{$vlvChild}{"parent"} eq $parentName){

                                                		delete ($vlvIndex{$vlvBac}{$vlvChild}{"name"});
								delete ($vlvIndex{$vlvBac}{$vlvChild}{"parent"});

								foreach $vlvAttr (sort keys %{$vlvIndex{$vlvBac}{$vlvChild}}){
                                                        		print OUTFILE "\t\t        $vlvAttr\n";
                                                		}
							}
						}
					}
				} # end of foreach
			} # end of if
		} # end of foreach


	} #end of vlv Stuff

	

	print OUTFILE "\n\n";
} 


if($referOn eq "yes" || $showPlugin eq "yes"){

        print OUTFILE "\n\n\n\n----------------------------------------------------------\n";
        print OUTFILE " Referential Integrity Postoperation Plugin\n";
        print OUTFILE "----------------------------------------------------------\n\n";

	psort ("referint");

}

if ($change5 eq "1"){
	print OUTFILE "\n\n\n\n----------------------------------------------------------\n";
	print OUTFILE " Changelog\n";
	print OUTFILE "----------------------------------------------------------\n\n";

	psort ("changelog");
}

print OUTFILE "\n\n\n\n----------------------------------------------------------\n";
print OUTFILE " Encryption Configuration\n";
print OUTFILE "----------------------------------------------------------\n\n";

psort ("ssl");

if ($dse{"Password Policy"}){
print OUTFILE "\n\n\n\n----------------------------------------------------------\n";
print OUTFILE " Password Policy\n";
print OUTFILE "----------------------------------------------------------\n\n";

	psort ("Password Policy");
}

#
#  Display all the plugins
#

if ($skipPlugin eq "no"){
print OUTFILE "\n\n\n\n----------------------------------------------------------\n";
print OUTFILE " Plugins (" . $totalPlugins . ")\n";
print OUTFILE "----------------------------------------------------------\n\n";

foreach $plug (keys %plugins){
	$dplug = "[$totalPlugins]\"$plug\"";
	print OUTFILE "\t" . "[$totalPlugins] \"" . $plug . "\"" . "\n";
	print OUTFILE "\t" . "-" x length $dplug . "\n";
	$totalPlugins--;

	foreach $plugs ( sort {$a cmp $b} keys %{$plugins{$plug}}){
		print OUTFILE "\t" . $plugs . "\n";
	}
	print OUTFILE "\n\n";
}

}

#
#  Display the rest of the entries - if there are any
#

if ($verbose eq "yes" && $skipPlugin eq "no"){
	print OUTFILE "\n\n\n\n----------------------------------------------------------\n";
	print OUTFILE " Other Config Entries ($otherCount)\n";
	print OUTFILE "----------------------------------------------------------\n\n";

	foreach $ot (keys %other){
		print OUTFILE "\t" . $ot . "\n";
		print OUTFILE "\t" . "-" x length $ot . "\n";
	
		foreach $oth ( sort {$a cmp $b}keys %{$other{$ot}}){
			print OUTFILE "\t" . $oth . "\n";
		}
		print OUTFILE "\n\n"
	}
	
}  


#
#  Diplsay the last 10 modified entries
#

	print OUTFILE "\n\n\n\n----------------------------------------------------------\n";
        print OUTFILE " Last $size Modified Entries\n";
	print OUTFILE "----------------------------------------------------------\n\n";
	
	$lcount = "1";

	foreach $lm ( sort { $lastmod{$b}{"lastmod"}  <=> $lastmod{$a}{"lastmod"}  } keys %lastmod){

		$mlc = "[$lcount]";
		$myTime = $lastmod{$lm}{"lastmod"};
		&getTimestring($myTime);

format OUTFILE = 
@<<<<  @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<   @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
$mlc $convTime                $lm
.
write OUTFILE; 

		$lcount++;
		if ($lcount == $size + 1){
			last;
		}

	}
	

print OUTFILE "\n\n";
print STDOUT "\n";

exit;

#############
#  The End  #
#############




sub processBuff
{
 local @buf = @_;
 local $skipACI = $skipACI;
 &catLines;
 $i = 0;

 $totalentries++;
 $buff[$i] =~ s/, /,/g;

###########################
#  Skip unwanted entries  #
###########################

if ($verbose eq "no"){
	# skip the tasks
	if ($buff[$i] =~ m/cn=tasks,cn=config/){
		$skipedEntries++;
		return;
	}

	# skip the monitor stuff
	if ($buff[$i] =~ m/cn=monitor/){
		$skipedEntries++;
		return;
	}

	# skip the international features
	if ($buff[$i] =~ m/cn=internationalizatio/i && $buff[$i] =~ m/cn=features, cn=config/ ){
		$skipedEntries++;
		return;
	}

	# skip main index entry
	if ($buff[$i] =~ m/^dn: cn=index/i){
		$skipedEntries++;
		return;
	}

	if ($buff[$i] eq "dn: cn=Password Storage Schemes,cn=plugins,cn=config"){
		$skipedEntries++;
                return;
        }
}

	$entries++;


#####################################
# Check and grab the cn=config args #
#####################################

	if ($buff[$i] eq "dn: cn=config"){

		$arg = 0;
		while($buff[$i]){
			$i++;  # move the buffer to the first line in cn=config

			if ($buff[$i] =~ m/^objectClass/i || 
			    $buff[$i] =~ m/^numsubordinates: /i || 
			    $buff[$i] =~ m/^creatorsName/i  ||
			    $buff[$i] =~ m/^modifiersName/i || 
			    $buff[$i] =~ m/^entrydn/i ||
			    $buff[$i] =~ m/^createTimestamp/i || 
		    	    $buff[$i] =~ m/^cn: /i ){

			
			} else {
				
				if ($buff[$i] =~ m/^modifytimestamp/i){
					$buff[$i] =~ s/modifytimestamp: //i;
					$buff =~ s/Z//;
					$lastmod{"cn=config"}{"lastmod"} = $buff[$i];
					next;
				}

				if ($skipACI eq "yes" && $buff[$i] =~ m/^aci: \(/i){  next;  }

				$buff[$i] =~ s/nsslapd-//;

				if ($buff[$i] ne ""){
                                        $result = checkDefault("config", $buff[$i]);

                                        if ($result eq "no"){
                                                $buff[$i] = "-> " . $buff[$i];
                                        }
                                }

				$dse{"config"}[$arg] = $buff[$i];
				$arg++;
			}
		}
		return;
	}

###########################################
#  grab the Referential Integrity Plugin  #
###########################################



	if ($buff[$i] =~ m/^dn: cn=referential integrity postoperation/i){
                $arg = 0;
		$dn = $buff[$i];
                while($buff[$i]){
                        $i++;  # move the buffer to the first line in cn=config

                        if ($buff[$i] =~ m/^objectclass/i ||
			    $buff[$i] =~ m/^numsubordinates/i ||
                            $buff[$i] =~ m/^creatorsName/i ||
                            $buff[$i] =~ m/^cn: /i ||
                            $buff[$i] =~ m/^modifiersName/i ||
                            $buff[$i] =~ m/^createTimestamp/i 
                            ){
                        } else {
                                $buff[$i] =~ s/nsslapd-//;

				if ($buff[$i] =~ m/^modifytimestamp/i){
                                        $buff[$i] = s/modifytimestamp: //i;
					$buff[$i] =~ s/Z//;
					$dn =~ s/^dn: //;
					$lastmod{$dn}{"lastmod"} = $buff[$i];
					next;
				}

                                if ($skipACI eq "yes" && $buff[$i] =~ m/^aci: /i){ next;}
				if ($skipSig eq "yes" && $buff[$i] =~ m/^ds-plugin/i){ next;}
				if ($buff[$i] =~ /pluginEnabled: off/i){
					$referOn = "off";
				}

                                $dse{"referint"}[$arg] = $buff[$i];
                                $arg++;
                        }
                }
                return;
        }


#####################################################################################################
#  We need to grab all the backends and indexes before grabing the other plugins and other entries  #
#####################################################################################################


        if ($buff[$i] eq "dn: cn=config,cn=ldbm database,cn=plugins,cn=config"){
		$arg = 0;
		while($buff[$i]){
                        $i++;  # move the buffer to the first line in cn=config

                        if ($buff[$i] =~ m/^objectclass/i || 
                            $buff[$i] =~ m/^numsubordinates/i || 
                            $buff[$i] =~ m/^creatorsName/i || 
                            $buff[$i] =~ m/^modifiersName/i ||
			    $buff[$i] =~ m/^entrydn/i ||
			    $buff[$i] =~ m/^cn: /i ||
                            $buff[$i] =~ m/^createTimestamp/i 
                            ){
				} else {
				$buff[$i] =~ s/nsslapd-//;

				if ($buff[$i] =~ /dbcachesize: *([0-9]+)/i ){
					$dbcache = $dbcache + $1;
				}

				if ($buff[$i] =~ m/^modifytimestamp/i){
                                        $buff[$i] =~ s/modifytimestamp: //i;
					$buff[$i] =~ s/Z//;
					$lastmod{"cn=config,cn=ldbm database,cn=plugins,cn=config"}{"lastmod"} = $buff[$i];
					next;	
				}

				# check for default value - if different flag attr/value

				if ($buff[$i] ne ""){
					$result = checkDefault("ldbm", $buff[$i]);

					if ($result eq "no"){
						$buff[$i] = "-> " . $buff[$i];
					}
				}


                                $ldbmConfig{"ldbm database"}[$arg] = $buff[$i];
                                $arg++;
                        }
                }
                return;
	}

	$tmp = ",cn=ldbm database,cn=plugins,cn=config";
	@buffOrig = @buff;

	if ($buff[$i] =~ m/$tmp/i ){
		$arg = 0;
		$dn = $buff[$i];
		$buff[$i] =~ s/,cn=ldbm database,cn=plugins,cn=config//;
		$buff[$i] =~ s/^dn: //;
		$entry = $buff[$i];
		if ($entry =~ m/,/ || $entry =~ m/cn=monitor/i){
			
		} else {
		$backendCount++;

		while($buff[$i]){
                        $i++;  # move the buffer to the first line in cn=config

                        if ($buff[$i] =~ m/^objectclass/i || 
                            $buff[$i] =~ m/^numsubordinates/i || 
                            $buff[$i] =~ m/^creatorsName/i ||
                            $buff[$i] =~ m/^modifiersName/i ||
			    $buff[$i] =~ m/^entrydn/i ||
#			    $buff[$i] =~ m/^cn: /i ||
                            $buff[$i] =~ m/^createTimestamp/i 
                            ){
				} else {

				 if ($buff[$i] =~ m/^modifytimestamp/i){
                                        $buff[$i] =~ s/modifytimestamp: //i;
                                        $buff[$i] =~ s/Z//;
					$dn =~ s/^dn: //;
                                        $lastmod{$dn}{"lastmod"} = $buff[$i];
					next;
				}

				if ($buff[$i] =~ /nsslapd-cachememsize: *([0-9]+)/i ){
                                        $entryCache = $entryCache + $1;
                                }

				$buff[$i] =~ s/nsslapd-//;

                                if ($buff[$i] ne ""){
                                        $result = checkDefault("backend", $buff[$i]);

                                        if ($result eq "no"){
                                                $buff[$i] = "-> " . $buff[$i];
                                        }
                                }

				$ldbm{$entry} = $entry;
                                $ldbm{$entry}[$arg] = $buff[$i];
                                $arg++;
                        }
                }
                return;
		}
        }

	
	#  Grab the indexes for each backend
	

	if ($buff[$i] =~ m/,cn=index,/i ){ 
		$systemIndex = "no";
		$arg = 0;
		$dn = $buff[$i];
		# strip out unnecessary dn comps
		$buff[$i] =~ s/,cn=ldbm database,cn=plugins,cn=config//;
		$buff[$i] =~ s/,cn=index//;

		if ($buff[$i] =~ /cn= *([A-Z0-9]+)/i){
			$myindex = $1;
		}

		$buff[$i] =~ s/cn=$myindex,//;
		$backend = $buff[$i];
		$indexBuff = "";
		$indexOtherBuff = "";
		$indexTypeBuff = "";

		while($buff[$i]){
                        $i++; 
			if ($buff[$i] =~ m/^objectclass/i || 
                            $buff[$i] =~ m/^numsubordinates/i || 
                            $buff[$i] =~ m/^creatorsName/i ||
                            $buff[$i] =~ m/^modifiersName/i ||
			    $buff[$i] =~ m/^entrydn/i ||
                            $buff[$i] =~ m/^createTimestamp/i 
                            ){
				} else {
				if ($buff[$i] =~ m/^nsSystemIndex: true/i){
					$systemIndex = "yes";
					next;
				}
				if ($buff[$i] =~ m/^nsSystemIndex: false/i){
                                        next;
                                }

				if ($buff[$i] =~ m/^modifytimestamp/i){
                                        $buff[$i] =~ s/modifytimestamp: //i;
                                        $buff[$i] =~ s/Z//;
					$dn =~ s/^dn: //;
                                        $lastmod{$dn}{"lastmod"} = $buff[$i];
                                        next;
                                }

				if ($buff[$i] =~ m/^cn: /i){
					$buff[$i] =~ s/^cn: //;
					$indexBuff = $indexBuff . "" . $buff[$i] ;
				} elsif ($buff[$i] =~ m/nsindextype: /i){
					if ($buff[$i] =~ /nsIndexType: *([a-z]+)/i){
						$type = $1;
					}
					$indexTypeBuff = $indexTypeBuff . " " .$type;
				} elsif ($buff[$i] ne "") {	
					$indexOtherBuff = $indexOtherBuff  . "\t\t- " . $buff[$i]. "\n";

				}
                        }
                }
		if ($systemIndex eq "yes"){
			$match = "no";
			$match = checkDefault("index",$indexBuff . ": " . $indexTypeBuff);
			if($match eq "yes"){
				$indexBuff = "* " . $indexBuff;
			} else {
				$indexBuff = "! " . $indexBuff;
			}
		} else {
			$indexBuff = "  " . $indexBuff;
		}

		if ($indexOtherBuff ne ""){
			$indexOtherBuff = "\n" . $indexOtherBuff;
		}

		$indexBuff = $indexBuff . ": " . $indexTypeBuff . $indexOtherBuff;

		if ($systemIndex eq "yes" && $match eq "no"){
			$indexBuff = $indexBuff . " --> Not Default Value";   
			$systemIndex = "no";
		}

		$index{$backend}{$indexBuff}++;
                return;
        }

	#
	#  Grab the vlv stuff
	#

@buff = @buffOrig;

	if ($buff[$i] =~ m/,cn=ldbm database,cn=plugins,cn=config/i){
		$vv = "0";
	
		# walk the entry and check for the vlv objectclasses
		
		for ($vv = 0; $buff[$vv] <= $#buff && $buff[$vv] ne ""; $vv++){
			if($buff[$vv] =~ /objectClass: vlvSearch/i || $buff[$vv] =~ /objectClass: vlvIndex/i){
				$vlvCount++;
				$vlvParentName = "";
				$vlvIndexName = "";
				$vlvSrchName = "";
				$dn = $buff[$i];
				$buff[$i] =~ s/,cn=ldbm database,cn=plugins,cn=config//;
				$buff[$i] =~ s/^dn: //;

				# grab the vlv index or search name

				if($buff[$vv] =~ /objectClass: vlvSearch/i){
					if ($buff[$i] =~ /cn= *([A-Z0-9_ ]+)/i){
						$vlvSrchName = $1;
					}
					$buff[$i] =~ s/cn=$vlvSrchName,//i;

					$backend = $buff[$i];	
					$vlvSearch{$backend}{$vlvSrchName}{"name"} = $vlvSrchName;
				} else {
					if ($buff[$i] =~ /cn= *([A-Z0-9 _]+)/i){
                                                $vlvIndexName = $1;
                                        }
                                        $buff[$i] =~ s/cn=$vlvIndexName,//i;     

					if ($buff[$i] =~ /cn= *([A-Z0-9 _]+)/i){
                                                $vlvParentName = $1;
                                        }
					$buff[$i] =~ s/cn=$vlvParentName,//i;

                                        $backend = $buff[$i]; 
					$vlvIndex{$backend}{$vlvIndexName}{"name"} = $vlvIndexName;
				}
	
				# Process the Entry

				while($buff[$i]){
					if ($buff[$i] =~ m/^objectclass/i || 
                            			$buff[$i] =~ m/^numsubordinates/i || 
                           			$buff[$i] =~ m/^creatorsName/i ||
						$buff[$i] =~ m/^cn: /i ||
						$buff[$i] =~ m/^entrydn/i ||
                            			$buff[$i] =~ m/^modifiersName/i ||
                            			$buff[$i] =~ m/^createTimestamp/i )
					{ # do nothing   }
					} else { 
						if ($buff[$i] =~ m/^modifytimestamp/i){
                                        		$buff[$i] =~ s/modifytimestamp: //i;
                                        		$buff[$i] =~ s/Z//;
							$dn =~ s/^dn: //;
                                       			$lastmod{$dn}{"lastmod"} = $buff[$i];
							$i++;
                                        		next;
                                		}

						if ( $vlvIndexName ne "" && $buff[$i] =~ /^vlv/i ){
							$vlvIndex{$backend}{$vlvIndexName}{$buff[$i]}++;
							$vlvIndex{$backend}{$vlvIndexName}{"parent"} = $vlvParentName;
							
						}	

						if ($vlvSrchName ne "" && $buff[$i] =~ /^vlv/i ){
                                                        $vlvSearch{$backend}{$vlvSrchName}{$buff[$i]}++;

                                                }

				
					}  # end of else
					$i++;
				} # end of while
			} # end of vlv entry
		} # end of for
#	return;

	} # end of VLV stuff

	$buff[$i] =~ s/,cn=ldbm database,cn=plugins,cn=config//; # need to strip this to continue processing correctly



################################################
#  Grab the replication config and agreements  #
################################################

	if ($buff[$i] =~ m/^dn: cn=replica,/i ){
		$dn = $buff[$i];
		$buff[$i] =~ s/^dn: cn=replica,//i;
		$buff[$i] =~ s/,cn=mapping tree,cn=config//i;
		$replicaBackend = $buff[$i];

		# recontruct the mapping tree name to match the backend name


		$replicaBackend =~ s/^cn=//;
		$replicaBackend =~ s/\\,.*//i;
                $replicaBackend =~ s/^[a-z]*=//i;
		$replicaBackend =~ s/"//g;
		$replicaBackend = "cn=" . $replicaBackend;


		while($buff[$i]){
                        if ($buff[$i] =~ m/^objectclass/i || 
                            $buff[$i] =~ m/^numsubordinates/i || 
                            $buff[$i] =~ m/^creatorsName/i || 
                            $buff[$i] =~ m/^modifiersName/i || 
			    $buff[$i] =~ m/^entrydn/i ||
                            $buff[$i] =~ m/^createTimestamp/i  
                            ){ } else {

				if ($buff[$i] =~ m/^modifytimestamp/i){
                                        $buff[$i] =~ s/modifytimestamp: //i;
                                        $buff[$i] =~ s/Z//;
					$dn =~ s/^dn: //;
                                        $lastmod{$dn}{"lastmod"} = $buff[$i];
					$i++;
                                        next;
                                }

				$buff[$i] =~ s/nsslapd-//i;
				$buff[$i] =~ s/nsDS5//i;
                                $replConfig{$replicaBackend}{$buff[$i]}++;
			
				#  Grab repl type info

				if ($buff[$i] =~ /Flags/i){
					$buff[$i] =~ s/Flags: //i;
					$flags = $buff[$i];
				}

				if ($buff[$i] =~ /replicaType/i){
					$replType = $buff[$i];
					$replType =~ s/ReplicaType: //i;
				}


                        }
			$i++;
                }

		# set the type:  Master, Hub, Consumer

                if ($flags eq "1" && $replType eq "2"){
                	$replConfig{$replicaBackend}{"replType"} = "Hub";
                } elsif ($replType eq "3"){
                        $replConfig{$replicaBackend}{"replType"} = "Master";
                } elsif ($replType eq "2" && $flags eq "0"){
                        $replConfig{$replicaBackend}{"replType"} = "Consumer";
                } else {
			$replConfig{$replicaBackend}{"replType"} = "Unknown";
		}

                return;
        }

	# replication agreements - don't forget to delete the hash element {}{"dn"} & {}{"count"}
	#                          after printing it in the report

	if ($buff[$i] =~ m/,cn=replica,/i ){
		$dn = $buff[$i];
		if ($buff[$i] =~ /cn= *([a-z0-9\.\:]+)/i){
			$replName = $1;
		}

		$globalReplCount++;

		$buff[$i] =~ s/,cn=mapping tree,cn=config//i;
		$buff[$i] =~ s/dn: cn=$replName,cn=replica,//i;

		# recontruct the mapping tree name to match the backend name	

		$replBackend = $buff[$i];
		$replBackend =~ s/^cn=//;
		$replBackend =~ s/^[a-z]=//i;
		$replBackend =~ s/\\,.*//i;
		$replBackend =~ s/"//g;
		$replBackend =~ s/\\//g;
		$replBackend = "cn=" . $replBackend . "---" . $globalReplCount;

		$replAgr{$replBackend}{"dn"} = $replName;
		$replAgr{$replBackend}{"Fractional"} = "no";

		while($buff[$i]){
                        $i++;
                        if ($buff[$i] =~ m/^objectclass/i ||
                            $buff[$i] =~ m/^numsubordinates/i ||
                            $buff[$i] =~ m/^creatorsName/i ||
			    $buff[$i] =~ m/^cn: /i ||
			    $buff[$i] =~ m/^entrydn/i ||
                            $buff[$i] =~ m/^modifiersName/i ||
                            $buff[$i] =~ m/^createTimestamp/i 
                            ){ } else {

				if ($buff[$i] =~ m/^modifytimestamp/i){
                                        $buff[$i] =~ s/modifytimestamp: //i;
                                        $buff[$i] =~ s/Z//;
					$dn =~ s/^dn: //;
                                        $lastmod{$dn}{"lastmod"} = $buff[$i];
                                        next;
                                }


                                $buff[$i] =~ s/nsslapd-//;
				$buff[$i] =~ s/nsDS5//;
                                $replAgr{$replBackend}{$buff[$i]}++;

				if ($buff[$i] =~ m/ds5PartialReplConfiguration/i){
					$replAgr{$replBackend}{"Fractional"} = "yes";
				}	
                        }
                }
                return;

	} 



#######################
#  Get the changelog  #
#######################

	if ($buff[$i] =~ m/dn: cn=changelog5,/i){
		$dn = $buff[$i];
		$arg = 0;
		$change5 = "1";
                while($buff[$i]){
                        $i++;  # move the buffer to the first line in cn=config

                        if ($buff[$i] =~ m/^objectclass/i ||
                            $buff[$i] =~ m/^numsubordinates/i ||
                            $buff[$i] =~ m/^creatorsName/i ||
			    $buff[$i] =~ m/^entrydn/i ||
                            $buff[$i] =~ m/^modifiersName/i ||
                            $buff[$i] =~ m/^cn: /i ||
                            $buff[$i] =~ m/^createTimestamp/i 
                            ){
                                } else {

				if ($buff[$i] =~ m/^modifytimestamp/i){
                                        $buff[$i] =~ s/modifytimestamp: //i;
                                        $buff[$i] =~ s/Z//;
                                        $lastmod{"cn=changelog5"}{"lastmod"} = $buff[$i];
                                        next;
                                }

                                $buff[$i] =~ s/nsslapd-//;
                                $dse{"changelog"}[$arg] = $buff[$i];
                                $arg++;
                        }
                }
                return;
        }


#####################
#  Grab the plugins #
#####################
if ($skipPlugin eq "no"){
	if ($buff[$i] =~ m/,cn=plugins,cn=config/i){
		$dn = $buff[$i];
		$entry = $buff[$i];
		$dEntry = $entry ; $dEntry =~ s/^dn: //;
		$enabled = "on";
	
		# strip the DN down to the rdn
		$entry =~ s/,cn=plugins,cn=config//;
		$entry =~ s/^dn: //;

                while($buff[$i]){
                        $i++;  # move the buffer to the first line in cn=config

                        if ($buff[$i] =~ m/^objectclass/i  || 
                            $buff[$i] =~ m/^numsubordinates/i || 
			    $buff[$i] =~ m/^cn: /i ||
			    $buff[$i] =~ m/^entrydn/i ||
                            $buff[$i] =~ m/^creatorsName/i || 
                            $buff[$i] =~ m/^modifiersName/i ||
                            $buff[$i] =~ m/^createTimestamp/i 
                            ){ } else {

				if ($buff[$i] =~ m/^modifytimestamp/i){
                                        $buff[$i] =~ s/modifytimestamp: //i;
                                        $buff[$i] =~ s/Z//;
					$dn =~ s/^dn: //;
                                        $lastmod{$dn}{"lastmod"} = $buff[$i];
                                        next;
                                }

				$buff[$i] =~ s/nsslapd-//;
                                if ($skipACI = "yes" && $buff[$i] =~ m/^aci: /i){ next};
				if ($skipSig eq "yes" && $buff[$i] =~ m/^ds-plugin/i){ next;}

				if ($buff[$i] =~ m/pluginEnabled: off/i){
                                        $enabled = "off";
                                } else {
					$enabled = "on";
				}	

                                $plugins{$entry}{$buff[$i]}++;
			}
		}

		# check for non default config - on or off
                if ($defaultPlugin{$dEntry}){
                        if ($defaultPlugin{$dEntry} ne $enabled){
                                $nonDefault{$dEntry}++;
				$nonDefault{$dEntry}{"option"} = $enabled;
                        }
                } else {
			$nonDefault{$dEntry}++;
                        $nonDefault{$dEntry}{"option"} = $enabled;
		}

		if ($enabled eq "off" && $showPlugin eq "no"){
                         delete ($plugins{$entry});
		} else {
			$totalPlugins++;
		}
		return;
	}

############################
#  Grab the other entries  # 
############################

	if ($buff[$i] =~ m/^dn: /i  && $buff[$i] =~ m/,cn=config/i ){
		$dn = $buff[$i];
		if ($buff[$i] =~ /^dn: /i ){
			$entry = $buff[$i];
			$entry =~ s/^dn: //i;	
		}

                while($buff[$i]){
                        $i++;  # move the buffer to the first line in cn=config

                        if ($buff[$i] =~ m/^objectclass/i || 
                            $buff[$i] =~ m/^numsubordinates/i || 
                            $buff[$i] =~ m/^creatorsName/i ||
			    $buff[$i] =~ m/^cn: /i ||
			    $buff[$i] =~ m/^entrydn/i ||
                            $buff[$i] =~ m/^modifiersName/i ||
                            $buff[$i] =~ m/^createTimestamp/i 
                            ){ } else {

				if ($buff[$i] =~ m/^modifytimestamp/i){
                                        $buff[$i] =~ s/modifytimestamp: //i;
                                        $buff[$i] =~ s/Z//;
					$dn =~ s/^dn: //;
                                        $lastmod{$dn}{"lastmod"} = $buff[$i];
                                        next;
                                }

				$buff[$i] =~ s/nsslapd-//;
                                if ($skipACI = "yes" && $buff[$i] =~ m/^aci: /i){ next; } 

                                $other{$entry}{$buff[$i]}++;
			}
		}
		$otherCount++;
		return;
	}
} # end of skipPlugins

} # end of process buff


#
#
#

sub catLines
{
 $catStart = "yes";
 $catCount = "0";

 for ($c = 0; $c <= $#buf; $c++){
  chomp($buf[$c]);
  if ($buf[$c] =~ m/^ / ){
        $buf[$c] =~ s/^ //;
        $base = $base . $buf[$c];
  } else {
        if ($catStart eq "yes"){
                $base = $buf[$c];
                $catStart = "no";

        } else {
                $buff[$catCount] = $base;
                $catCount++;
                $base = $buf[$c];
        }
  }
 }
 chomp($base);
 $buff[$catCount] = $base;
}


sub displayUsage {
	print  "dseconv.pl Usage:\n\n";
	print  "./dseconv.pl -f <dse.ldif> -o <new converted report> [-aci][-sig][-V] \n";
	print  "\n  -aci  -   Skip ACIs in report.\n";
	print  "  -plugin  -  Skips the plugin and misc entries.\n";
	print  "  -p  -  Displays all plugins - regardless if they are enabled.\n";
	print  "  -V  -  verbose - prints all entries\n";
	print  "  -s  -  size limit\n";
}


sub getTimestring {
	$year = substr($myTime,0,4);
	$mon = substr($myTime,4,2);
	$day = substr($myTime,6,2);
	$hour = substr($myTime,8,2);
	$min = substr($myTime,10,2);
	$sec = substr($myTime,12,2);

	$year -= 1900;
	$mon--;

	$convTime = asctime($sec,$min,$hour,$day,$mon,$year,0,0,0);
	$convTime =~ s/\n//;
}


sub commify {
        my $input = shift;
        $input = reverse $input;
        $input =~ s<(\d\d\d)(?=\d)(?!\d*\.)><$1,>g;
        return reverse $input;
}

sub checkDefault
{
	($section, $confValue) = @_;
	
	if ($section eq "index"){
		for ($ii = 0; $ii <= $#defaultIndex; $ii++){
			if (lc($confValue) eq $defaultIndex[$ii]){
				return "yes";
			}
		}
	}

	if ($section eq "config"){
		for ($ii = 0; $ii <= $#defaultConfig; $ii++){

			# also check for system specific attr/value and return match
			if ($confValue =~ m/^accesslog: /i ||
			    $confValue =~ m/^localhost: /i ||	
			    $confValue =~ m/^port: /i ||
			    $confValue =~ m/auditlog/i ||
			    $confValue =~ m/mode: 600/i ||
			    $confValue =~ m/dir: /i ||
			    $confValue =~ m/path: /i ||
			    $confValue =~ m/^errorlog: /i ||
			    $confValue =~ m/^auditlog: /i ||
			    $confValue =~ m/^aci: /i ||
			    $confValue =~ m/^rootdn: /i ||
			    $confValue =~ m/^localuser: /i ||
			    $confValue =~ m/localssf: /i ||
			    $confValue =~ m/^rootpw: /i ||
			    $confValue eq $defaultConfig[$ii] ||             #  this is the actaul match we want 
			    $confValue =~ m/^auditlog-logging-enabled: /i ){

				return "yes";
			}
		}
	}

	if ($section eq "ldbm"){
		for ($ii = 0; $ii <= $#defaultLdbmConfig; $ii++){
			
			# also check for system specific attr/value and return match
			if ($confValue =~ m/^directory: /i ||
			    $confValue =~ m/^db-logdirectory: /i ||
			    $confValue =~ m/^db-home-directory: /i ||
			    $confValue eq $defaultLdbmConfig[$ii] ){

				return "yes";
			}
                }

	}

	if ($section eq "backend"){
		for ($ii = 0; $ii <= $#defaultBackendConfig; $ii++){
                        if ($confValue eq $defaultBackendConfig[$ii] ||
			  	$confValue =~ m/^suffix: /i ||
				$confValue =~ m/^directory: /i){

                                return "yes";
                        }
                }

	}

	return "no";
}


sub Hashvalue {
@{$dse{$a}} <=> @{$dse{$b}};
} #hashvalue


sub psort {
	my @a;
	$attrib=pop(@_);
	$arg=0;
	while ($dse{$attrib}[$arg] && $dse{$attrib}[$arg] ne "\n"){
		@a[$arg]=$dse{$attrib}[$arg];
		$arg++;
	}

	# sort and put back into hash
	@a=sort {$a cmp $b}(@a);
	$arg=0;
	while ($dse{$attrib}[$arg] && $dse{$attrib}[$arg] ne "\n"){
		$dse{$attrib}[$arg] = @a[$arg] ;
		$arg++;
	}

	# print array
	$arg=0;
	while ($dse{$attrib}[$arg] && $dse{$attrib}[$arg] ne "\n"){
		if ($dse{$attrib}[$arg] =~ m/^-> /){
			print OUTFILE "     " . $dse{$attrib}[$arg]  . "\n";
        	} else {
			print OUTFILE "\t" . $dse{$attrib}[$arg] ."\n" ;
		}
		$arg++;
	}
}


