#!/usr/bin/perl -w

$OUTPUT = "HTML"; # HTML for HTML, anything else for TAB separated values

my $inacl = 0;
my $thisacl = "";
@ACL = ();
@DN = ();
@FILTER=();
@ATTRS = ();
$aclindex = 0;	# Index into ACL, DN,  FILTER, and ATTRS
%ATTR = ();
@WHO = ();
$whoindex = 0;

LOOP:
while ( <STDIN> ) {
    chomp();
    my $line = lc($_);
    if ( $inacl ) {
	if ( $line =~ m/^\s/ ) {
	    $thisacl .= $line;
	    next LOOP;
	} else {
#print "thisacl='$thisacl'\n";
	    &processACL($thisacl);
#print "ACL[$aclindex]='$ACL[$aclindex]'\n";
	    $inacl = 0;
	}
    } 
    if ( $line =~ m/^access to/io ) {
	$thisacl = $line;
	$inacl = 1;
    }
}
if ( $inacl ) {
    &processACL($thisacl);
#print "ACL[$aclindex]='$ACL[$aclindex]'\n";
}

#print "aclindex = $aclindex\n";
#print "ACL=",join('$',@ACL),"\n";
#print "whoindex = $whoindex\n";
#print "WHO=",join('$',@WHO),"\n";
#foreach my $a (sort keys %ATTR) {
#    print "$a: $ATTR{$a}\n";
#}

&dumpTable();

exit 0;

sub processACL() {
    my $thisacl = $_[0];
    $aclindex++;
#    printf("%4d: %s\n", $aclindex, $thisacl);
    $ACL[$aclindex]="";
    $DN[$aclindex]="";
    $FILTER[$aclindex]="";
    $ATTRS[$aclindex]="";
    $thisacl =~ s/^access to\s*//;
    (my $what = $thisacl) =~ s/\s+by\s.*//;
    my $len = length($what);
    my $by = substr($thisacl,$len);

    # Process the "WHAT" part of the ACL
    $what =~ s/^\s+//;
    if ( $what =~ m/^dn/i ) {
	# strip out the dn....
	my $dn = $what;
	$dn =~ s/\s+filter=.*//i;
	$dn =~ s/\s+attrs=.*//i;
	$DN[$aclindex]=$dn;
	$what = substr($what,length($dn));
	$what =~ s/^\s*//;
    }
    if ( $what =~ m/^filter=/i ) {
	# strip out the filter....
	my $thing = $what;
	$thing =~ s/\s+attrs=.*//i;
	$FILTER[$aclindex]=$thing;
	$what = substr($what,length($thing));
	$what =~ s/^\s*//;
    }
    if ( $what =~ m/^attrs=/i ) {
	# Process the attributes...
	$ATTRS[$aclindex]=$what;
	$what =~ s/^attrs=//i;
	my @attributes = split(',',$what);
	foreach my $a (@attributes) {
	    if ( defined $ATTR{$a} ) {
		$ATTR{$a} = $ATTR{$a} . ":" . $aclindex;
	    } else {
		$ATTR{$a} = $aclindex;
	    }
	}
	$what = "";
    }	
    if ( $what ne "" ) {
	if ( $what ne "*" ) {
	    print "FUBAR!";
	    print "\n";
	    exit 1;
	}
	if ( $ATTRS[$aclindex] eq "" ) {
	    $ATTRS[$aclindex] = $what;
	}
	if ( defined $ATTR{$what} ) {
	    $ATTR{$what} = $ATTR{$what} . ":" . $aclindex;
	} else {
	    $ATTR{$what} = $aclindex;
	}
    }
# DEBUG
#    print "DN: $DN[$aclindex]\n";
#    print "FILTER: $FILTER[$aclindex]\n";
#    foreach my $a (sort keys %ATTR) {
#	print "$a: $ATTR{$a}\n";
#    }

    # Process the BY WHO ACCESS CONTROL sets
    $by =~ s/^\s*//;
    while ( $by ne "" ) {
	if ( $by =~ m/^by/i ) {
	    $by =~ s/^by\s*//i;
	    # $thing is just this one who/access/control triplet
	    (my $thing = $by) =~ s/\s+by\s.*//i;
#print "$thing\n";
	    $by = substr($by,length($thing));
	    $by =~ s/^\s*//;
	    my @trip = split(' ', $thing);
	    my $who = "";
	    my $access = "";
	    my $control = "";
	    if ( scalar @trip == 2 ) {
		$who = $trip[0];
		$access = $trip[1];
	    } elsif ( scalar @trip == 3 ) {
		$who = $trip[0];
		$access = $trip[1];
		$control = $trip[2];
	    } elsif ( scalar @trip > 3 ) {
		my $fubar = scalar @trip;
		$fubar--;
		$control = $trip[$fubar--];
		$access = $trip[$fubar--];
		$who = $trip[0];
	        for(my $i=1; $i<$fubar; $i++) {
		    $who = $who . " " . $trip[$i];
		}
	    } else {
		print "FUBAR2\n";
		exit 1;
	    }

	    # Now make sure it's all correct...
	    if ( &isAccess($control) ) {
		# Oops... a space problem...
		$who = "$who $access";
		$access = $control;
		$control = "";
	    }
	    if ( not &isAccess($access) and not &isControl($access) ) {
		print "FUBAR3\n";
		exit 1;
	    }
	    if ( $control ne "" ) {
		$access = "$access $control";
	    }

	    # Now see if we can find this "who" in the array....
	    my $i = 0;
	    SRCH:
	    for ($i=0; $i<$whoindex; $i++) {
		last if $WHO[$i] eq $who; 
	    }
	    if ( $i >= $whoindex ) {
#print "Adding WHO '$who' at $whoindex\n";
		$WHO[$whoindex] = $who;
		$i = $whoindex++;
	    }

	    $ACL[$aclindex] .= ":$i;$access";
#print "ACL[$aclindex]='$ACL[$aclindex]'\n";

	} else {
	    print "FUBAR1\n";
	    exit 1;
	}
    }
}

sub isAccess() {
    my $test = $_[0];
    if ( $test eq "none" or
	  $test eq "auth" or
	  $test eq "compare" or
	  $test eq "search" or
	  $test eq "read" or
	  $test eq "write" ) { return 1 };
    return 0;
}

sub isControl() {
    my $test = $_[0];
    if ( $test eq "stop" or
	  $test eq "continue" or
	  $test eq "break" ) { return 1 };
    return 0;
}

sub dumpTable() {
    # Print out HTML table of what we did....
    my $i = 0;
    if ( $OUTPUT eq "HTML" ) {
	print "<html><head><title>OpenLDAP ACL Table</title></head><body>\n";
	print "<table border=1>\n";
	print "<tr>\n";
	print "  <th>Attribute</th>\n";
	print "  <th>ACL #</th>\n";
	print "  <th>DN</th>\n";
	print "  <th>FILTER</th>\n";
    } else {
	print "OpenLDAP ACL Table\n";
	print "Attribute\tACL #\tDN\tFILTER";
    }
    for ($i=0; $i<$whoindex; $i++) {
 	if ( $OUTPUT eq "HTML" ) {
	    print "  <th>$WHO[$i]</th>\n";
	} else {
	    print "\t$WHO[$i]";
	}
    }
    if ( $OUTPUT eq "HTML" ) {
	print "</tr>\n";
    } else {
	print "\n";
    }

    # Now generate a couple of constants....
    my $cols = 4 + $whoindex;

    # Print out each attribute and all it's info...
    foreach my $a (sort keys %ATTR) {
	my @acls = split(':', $ATTR{$a});
	my $rows = scalar @acls;
	if ( $OUTPUT eq "HTML" ) {
	    print "<tr>\n";
 	    print "  <td rowspan=$rows valign=middle>$a</td>\n";
	} else {
	    print "$a";
	}
	foreach my $b (@acls) {
	    if ( $OUTPUT eq "HTML" ) {
	        print "  <td>$b</td>\n";
	    } else {
		print "\t$b";
	    }
	    if ( $DN[$b] ne "" ) {
		if ( $OUTPUT eq "HTML" ) {
		    print "  <td>$DN[$b]</td>\n";
		} else {
		    print "\t$DN[$b]";
		}
	    } else {
		if ( $OUTPUT eq "HTML" ) {
		    print "  <td>&nbsp;</td>\n";
		} else {
		    print "\t";
		}
	    }
	    if ( $FILTER[$b] ne "" ) {
		if ( $OUTPUT eq "HTML" ) {
		    print "  <td>$FILTER[$b]</td>\n";
		} else {
		    print "\t$FILTER[$b]";
		}
	    } else {
		if ( $OUTPUT eq "HTML" ) {
		    print "  <td>&nbsp;</td>\n";
		} else {
		    print "\t";
		}
	    }
	    my @access = ();
	    for ($i=0; $i<$whoindex; $i++) {
		$access[$i] = "";
	    }
	    foreach my $c ( split(':',$ACL[$b]) ) {
		if ( $c ne "" ) {
		    my ( $idx, $acs ) = split(';', $c);
		    $access[$idx] = $acs;
		}
	    }
#print join(':',@access),"\n";
	    for ($i=0; $i<$whoindex; $i++) {
		if ($access[$i] ne "" ) {
		    if ( $OUTPUT eq "HTML" ) {
		        print "  <td>$access[$i]</td>\n";
		    } else {
			print "\t$access[$i]";
		    }
		} else {
		    if ( $OUTPUT eq "HTML" ) {
		        print "  <td>&nbsp;</td>\n";
		    } else {
			print "\t";
		    }
		}
	    }
	    if ( $OUTPUT eq "HTML" ) {
	        print "</tr>\n<tr>\n";
	    } else {
		print "\n";
	    }
	}
	if ( $OUTPUT eq "HTML" ) {
	    print "  <td colspan=$cols>&nbsp;</td>\n";
	    print "</tr>\n";
	} else {
	    my $sep = "\t" x $cols;
	    print "$sep\n";
	}
    }

    if ( $OUTPUT eq "HTML" ) {
	print "</table>\n";
    }

    # Now output the actual ACL's
    if ( $OUTPUT eq "HTML" ) {
	print "<h2>ACL List</h2>\n<ol>\n";
    } else {
	print "ACL List\n";
    }
    for ( $i=1; $i<=$aclindex; $i++ ) {
	if ( $OUTPUT eq "HTML" ) {
	    print "<li>access to\n<dl>\n";
	} else {
	    print "$i: access to\n";
	}
	if ( $DN[$i] ne "" ) {
	    if ( $OUTPUT eq "HTML" ) {
		print "<dd>$DN[$i]</dd>\n";
	    } else {
		print "\t$DN[$i]\n";
	    }
	}
	if ( $FILTER[$i] ne "" ) {
	    if ( $OUTPUT eq "HTML" ) {
		print "<dd>$FILTER[$i]</dd>\n";
	    } else {
		print "\t$FILTER[$i]\n";
	    }
	}
	if ( $ATTRS[$i] ne "" ) {
	    if ( $OUTPUT eq "HTML" ) {
		print "<dd>$ATTRS[$i]</dd>\n";
	    } else {
		print "\t$ATTRS[$i]\n";
	    }
	}
	foreach $c ( split(':',$ACL[$i]) ) {
	    if ( $c ne "" ) {
		my ($idx, $acs) = split(';',$c);
		if ( $OUTPUT eq "HTML" ) {
		    print "<dd>by $WHO[$idx] $acs</dd>\n";
		} else {
		    print "\tby $WHO[$idx] $acs\n";
		}
	    }
	}
	if ( $OUTPUT eq "HTML" ) {
	    print "</dl><br>\n";
	} else {
	    print "\n";
	}
    }
    if ( $OUTPUT eq "HTML" ) {
	print "</ol>\n";
    }

    if ( $OUTPUT eq "HTML" ) {
	print "</body>\n</html>\n";
    }

}
