#!/usr/bin/perl
##
## Sort entires in LDIF by DN (no Net::LDAP::LDIF version)
## Copyright (c) 2007,2018 SATOH Fumiyasu @ OSS Technology, Inc.
##               <https://www.OSSTech.co.jp/>
##
## License: GNU General Public License version 2 or later
##

use strict;
use warnings;
use MIME::Base64;

my $entries_by_dn = {};
$/ = '';
while (defined(my $entry = <>)) {
  chomp($entry);
  $entry =~ s/\n[ \t]//g;

  my ($b64, $dn) = $entry =~ /^dn:(:)?\s*(.*)$/im;
  next unless (defined($dn));

  chomp($dn);
  $dn = MIME::Base64::decode_base64($dn) if (defined($b64));
  $dn =~ s/\s*,\s*/,/g;
  my $dn_lc = lc($dn);
  warn "$0: WARNING: Duplicate DN: $dn\n" if (exists($entries_by_dn->{$dn_lc}));
  $entries_by_dn->{$dn_lc} = $entry;
}

my @dn_list =
  map { $_->[0] }
  sort {
    my $x;
    for (1..$#$a) {
      defined($a->[$_]) || return -1;
      defined($b->[$_]) || return +1;
      $x = $a->[$_] cmp $b->[$_] and return $x;
    }
    return -1;
  }
  map { [$_, reverse(split(/,/, $_))] }
  keys %$entries_by_dn;

for my $dn (@dn_list) {
  print $entries_by_dn->{$dn}, "\n\n";
}

exit(0);

