#!/usr/bin/perl -w
#
# Author: Rune Nordbøe Skillingstad <runesk@linpro.no>
#
# $Id$

use strict;

use Text::Unaccent;
use Net::LDAP;
use Data::Dumper;
use Unicode::String qw (utf8 latin1);

# This is not working right :)
my $ldapserver   = "localhost";
my $basedn       = "o=stfk,c=no";
my $ldapadmindn  = "cn=admin,o=stfk,c=no";
my $ldappassword = "foofoo";
my $maildomain   = "elev.stfk.no";
my $maildir      = "/var/mail/Maildir/";
my $homedir      = "/var/mail/Maildir/";

my %usernames;

srand (time ^ $$ ^ unpack "%L*", `/bin/ps axww | /bin/gzip`);

my $ldap = Net::LDAP->new($ldapserver, version => 3) or die "$@";
$ldap->bind($ldapadmindn, password => $ldappassword);

sub genusername {
    my($fname, $lname, $mname) = @_;
    my $i = 2;
    my $j = 1;

    # This wont work for ø and æ unless you use the UnicodeData-patch
    $fname = lc(unac_string("LATIN1", $fname));
    $lname = lc(unac_string("LATIN1", $lname));
    if($mname) {
	$mname =~ s/ /\./;
	$mname = lc(unac_string("LATIN1", $mname));
    }
    my $username = $fname.".".$lname;
    while($usernames{$username}) {
	if(!$mname) {
	    $username = $fname.$i++.".".$lname;
	} else {
	    if(length($mname) < $j) {
		$username = $fname.$i++.".".$mname.".".$lname;
	    } else {
		$username = $fname.".".substr($mname, 0, $j++).".".$lname;
	    }
	}
    }
    $usernames{$username} = 1;
    return $username;

}

sub loadusernames {
    my $mesg = $ldap->search(base   => "ou=people,domain=$maildomain,ou=Domains,".$basedn,
			     filter => "objectclass=mailaccount",
			     scope  => "one",
			     attrs   => ['uid']
			     );
    $mesg->code && die $mesg->error;
    my @allentries = $mesg->all_entries;
    foreach my $entry (@allentries){
	my $uid = $entry->get_value('uid');
	$uid =~ s,/+$,,;
	$usernames{"$uid"} = "1";
    }
}

sub next_char {
    my $password = lc(shift(@_));
    my $vowels = "aeiouy";
    my $consonants = "bdfghjklmnoprstuv";
    my $doubles = "bdfgjklmnopst";
    my $range;
    my $n = 0;
    if(!$password) {
	$range = $vowels . $consonants;
    } elsif($password =~ /[$vowels]$/) {
	$range = $consonants;
    } elsif($password =~ /[$consonants]{2}$/) {
	$range = $vowels;
    } elsif($password =~ /[$consonants]$/) {
	if($password =~ /(\s)(\s)$/) {
	    if ($1 = $2) {
		$range = $vowels;
	    } else {
		$range = $vowels.$doubles;
	    }
	} else {
	    $range = $vowels.$doubles;
	}
    } else {
	$range = $vowels.$consonants;
    }
#    $range = "123456789" if(!int(rand(20)));
    my $char = substr($range, rand(length($range)), 1);
    $char = uc($char) unless rand(10) % 9;
    return $char;
}
	

sub genpasswd {
    my $password;
    my $min = 6;
    my $max = 8;
    my $length = $min + int(rand($max - $min + 1));
    for(my $i = 0; $i < $length; $i++) {
	$password .= &next_char($password);
    }
    return $password;
} 

sub output {
    my ($username, $fullname, $password, @rest) = @_;
    &adduser($ldap, $username, $fullname, $password, 
	     $maildomain, $maildir, $homedir);
    print STDOUT "$maildomain;$username;$fullname;$password;" . 
      join(";",@rest) . "\n";
}

sub adduser {
    my ($ldap, $username, $fullname, $passwd, $domain, $maildir, $homedir) = @_;
    if ($maildir !~ /\/$/) {
        $maildir .= "/";
    }
    
    if ($homedir !~ /\/$/) {
        $homedir .= "/";
    }
	
    my %data = (
		attrs => [
                          'uid'   => $username,
                          'cn' => latin1($fullname)->utf8,
                          'domain' => $domain,
                          'homeDirectory' => $homedir . $domain ."/".$username."/",
                          'mailDir' => $maildir . $domain ."/".$username."/",
                          'mail' => $username . '@' . $domain,
                          'mailAddr' => $username . '@' . $domain,
                          'userPassword' => $passwd, 
                          'objectclass' => ['mailaccount','limacuteConfig'],]);
    
    my $dn = "uid=$username,ou=people,domain=$domain,ou=Domains,$basedn";
    
    $ldap->add($dn, %data);
}
    
if($#ARGV < 0) {
    print STDERR "Usage: $0 <infile>\n";
    exit;
}

&loadusernames;

open(IN, "<$ARGV[0]") || die "Can't open infile $ARGV[0]";

while(<IN>) {
    chomp;
    my ($tname, $lname, @rest) = split(";");
    # This might be cleaner
    my ($fname, @mname) = split(" ", $tname);
    $lname =~ s/ /\./g;
    my $mname = join(" ", @mname);
    my $username = &genusername($fname, $lname, $mname);
    my $password = &genpasswd;
    if($mname) {
	&output($username, "$fname $mname $lname", $password, @rest);
    } else {
	&output($username, "$fname $lname", $password, @rest);
    }
}
close(IN);
