#!/usr/bin/perl -w

use Getopt::Long;
use Data::Dumper;
$Data::Dumper::Indent = 1;
$Data::Dumper::Sortkeys = 1;
$Data::Dumper::Useqq = 1;
$Data::Dumper::Terse = 1; 

my $help=0;
my $verbose=0;

# Parsen der Optionen
my $testopt=GetOptions(
           "help|h" => \$help,
           "verbose|v+" => \$verbose,
          );

# Prüfen, ob Optionen erkannt wurden, sonst Abbruch
&check_options($testopt);

my $belwue_mailboxes="/var/lib/sophomorix/belwue/belwue.multimailboxes";
my $belwue_maillists="/var/lib/sophomorix/belwue/belwue.maillists";

my $lehrer_file="/etc/sophomorix/user/lehrer.txt";
my $extra_file="/etc/sophomorix/user/extraschueler.txt";
my $aliases_file="/etc/aliases";



############################################################
# configuration, part 1
my $target_dir="/home/teachers/bz/sophomorix-belwue";
my $target_owner="bz.teachers";


# add mailboxes for the users of these groups:
my $valid_groups=();
$valid_groups{'sekretariat'}="ok";
$valid_groups{'haustechnik'}="ok";
$valid_groups{'sozial'}="ok";
$valid_groups{'ehemalige'}="ok";

# maillists that are managed by netzwerker
my @maillists=("kollegium","sozial","sekretariat","ehemalige","netzwerker",
               "solarstrom","bsz-solarstrom","schulleitung","fal",
               "ethik_religion");

my $maildomain="bszleo.de"; # for maillist members

my $type="MultiMailbox";
my $mailquota_default=512;
# end configuration part 1
############################################################



# result
my $result_dir=$target_dir;
my $result_add=$result_dir."/belwue-mailaccounts.txt";
my $result_add_utf8=$result_dir."/belwue-mailaccounts-utf8.txt";
my %aliases=();
my %belwue=();
# result files
system("mkdir -p $result_dir");
open(ADD,">$result_add") || 
          die "Fehler: $result_add could not be created!";


foreach my $listname (@maillists){
    #print "--> $listname\n";
    $belwue{'maillist-checked'}{$listname}="checked";
}

my @passwort_zeichen=&get_passwd_charlist();


# existing accounts
open(BELWUE,"$belwue_mailboxes") || 
          die "Fehler: $belwue_mailboxes not found!";
while(<BELWUE>){
    my $uid=$_;
    chomp($uid);
    $belwue{'uid-seen'}{$uid}="seen";
}
close(BELWUE);

# copy the uid list to delete uids seen at bsz, 
# rest must be deleted at belwue 
my %belwue_uid = %{ $belwue{'uid-seen'} };   



# existing maillists
open(BELWUE,"$belwue_maillists") || 
          die "Fehler: $belwue_maillists not found!";
while(<BELWUE>){
    my $line=$_;
    chomp($line);
    my ($listname,$users)=split(/:/,$line);
    $belwue{'maillist-seen'}{$listname}{'status'}="seen";
    my @users=split(/,/,$users);
    foreach my $user (@users){
        $belwue{'maillist-seen'}{$listname}{'memberlist'}{$user}="seen";
    }
}
close(BELWUE);



# aliases
open(ALIASES,"$aliases_file") || 
          die "Fehler: $lehrer_file not found!";
my $curr_maillist="";
while(<ALIASES>){
    chomp();
    $dot_anzahl=tr/\.//;
    $ddot_anzahl=tr/://;
    my $line=$_;

    # skip empty lines
    $line=~s/\s//g;
    if ($line eq ""){
        #print ">$line<\n";
        next;
    }
    # skip commented lines
    if (m/^#/){
        #print ">$line<\n";
        next;
    }

    # read alias lines
    if ($dot_anzahl==1 and $ddot_anzahl==1){
        #print "$dot_anzahl $ddot_anzahl $_";
        my ($alias,$uid)=split(/:/);
        $uid=&remove_whitespace($uid); 
        $alias=&remove_whitespace($alias);
        #print "<$uid> -> <$alias>\n";
        $aliases{$uid}=$alias; 
    }

    # set current maillist, to know to which maillist 
    # refer the following lines
    if ($ddot_anzahl==1){
        my ($maillist,$nothing)=split(/:/);
        $maillist=&remove_whitespace($maillist); 
        $nothing=&remove_whitespace($nothing);
        $curr_maillist=$maillist;
        if ($nothing eq "" and exists $belwue{'maillist-checked'}{$maillist}){
        #print "$_\n";
        }
    }

    # save maillist memberships in %belwue
    if (exists $belwue{'maillist-checked'}{$curr_maillist}){
        if ($ddot_anzahl==1){
            next;
        } 
        my $user=$_;
        $user=&remove_whitespace($user); 
        $user=~s/,//g;
        if ($user eq "sozialsekretariathaustechnik"){
            next;
        }
        my $member_line=$user."@".$maildomain;
        #print "   <$member_line>    <$user>ist in $curr_maillist\n";
        push @{ $belwue{'maillist'}{$curr_maillist}{'memberlist'} }, $member_line;
        push @{ $belwue{'maillist'}{$curr_maillist}{'memberuser'} }, $user;

    }
}
close(ALIASES);




############################################################
# configuration, part 2

# adding maiilists to maillists manually
# i.e. sozialsekretariathaustechnik skipped above
&add_maillist_to_maillist("sozial","kollegium");
&add_maillist_to_maillist("sekretariat","kollegium");
#&add_maillist_to_maillist("haustechnik","kollegium");

# adding user haustechnik to kollegium
push @{ $belwue{'maillist'}{'kollegium'}{'memberlist'} }, "haustechnik"."@".$maildomain;
push @{ $belwue{'maillist'}{'kollegium'}{'memberuser'} }, "haustechnik";

# end configuration part 2
############################################################




print "##### Do the following on belwue Server: #####\n";
print "########## ADD THE FOLLOWING MAILBOXES/USERS::\n";

print ADD "Name\tRealname\tType\tPassword\tStorage\tAliases\n";


# lehrer
open(LEHRER,"$lehrer_file") || 
          die "Fehler: $lehrer_file not found!";
while(<LEHRER>){
    #print $_;
    chomp();
    my ($group,$last,$sur,$birth,$uid,$pw,$token,$quota,$mailquota)=split(/;/);
    my $alias="xxxxxx";

    $uid=&remove_whitespace($uid); 
    $last=&remove_whitespace($last); 
    $sur=&remove_whitespace($sur); 
    $mailquota=&remove_whitespace($mailquota);
    #if ($mailquota eq "mailquota"){
        $mailquota=$mailquota_default;
    #} 
    if (exists $aliases{$uid}){
        $alias=$aliases{$uid};
    }

    $plain_password=&get_plain_password(@passwort_zeichen);
    if (not exists $belwue{'uid-seen'}{$uid}){
        print ADD "$uid\t$sur $last\t$type\t$plain_password\t${mailquota}M\t$alias\n";
        print "   * ADD USER: $uid\t$sur $last\t$type\t$plain_password\t${mailquota_default}M\t$alias\n";
    } 

    if (exists $belwue_uid{$uid}){
        delete $belwue_uid{$uid}
    }
}
close(LEHRER);



# extraschueler
open(EXTRAS,"$extra_file") || 
          die "Fehler: $extra_file not found!";
while(<EXTRAS>){
    #print $_;

    if(/^\#/){ # # am Anfang bedeutet Kommentarzeile
        next;
    }
    chomp();
    my ($group,$last,$sur,$birth,$uid)=split(/;/);
    my $alias="xxxxxx";

    $uid=&remove_whitespace($uid); 
    $last=&remove_whitespace($last); 
    $sur=&remove_whitespace($sur); 
    if (exists $aliases{$uid}){
        $alias=$aliases{$uid};
    }

    $plain_password=&get_plain_password(@passwort_zeichen);
    if (not exists $belwue{'uid-seen'}{$uid} and exists $valid_groups{$group}){
        print ADD "$uid\t$sur $last\t$type\t$plain_password\t${mailquota_default}M\t$alias\n";
        print "   * ADD USER: $uid\t$sur $last\t$type\t$plain_password\t${mailquota_default}M\t$alias\n";
    }
    if (exists $belwue_uid{$uid} and exists $valid_groups{$group}){
        delete $belwue_uid{$uid}
    }

}
close(EXTRAS);



print "########## REMOVE THE FOLLOWING MAILBOXES/USERS:\n";
foreach my $uid ( keys %belwue_uid ){
    if ($uid eq "admin"){
        # skip the admin account
        next;
    }
    print "   * $uid\n";
}


print "########## NONEXISTING Maillists:\n";
foreach my $list (@maillists){
    if (exists $belwue{'maillist-seen'}{$list}){
        #print "$list exists\n";
    } else {
        print "   * $list nonexisting\n";
    }
}

close(ADD);
print "########## Running iconv:\n";
system("/usr/bin/iconv --verbose -f 8859_1 -t utf-8 $result_add -o $result_add_utf8");



# creating the maillist files
my @to_add=();
my $to_remove=();
print "########## MANAGING Maillists:\n";
foreach my $maillist ( keys %{ $belwue{'maillist'} } ){
    my $file=$result_dir."/maillist-".$maillist.".txt";
    print "   * creating maillist file $file\n";
    open(LISTFILE,">$file") || 
          die "Fehler: $file could not be created!";
    foreach my $member ( @{ $belwue{'maillist'}{$maillist}{'memberlist'} } ){   
        print LISTFILE "$member\n";
    }
    close(LISTFILE);
}

foreach my $maillist (@maillists){
    my @to_add=();     # members to add
    my @to_remove=();  # members to remove
    if (not exists $belwue{'maillist-seen'}{$maillist} ){
        print "########## Maillist $maillist must be created/has no members at belwue\n";
        next;
    } else {
        print "########## Maillist $maillist exists, actions follow:\n";
    }
    my %belwue_members = %{ $belwue{'maillist-seen'}{$maillist}{'memberlist'} };   
    # creating hash of bsz maillist members
    foreach my $member ( @{ $belwue{'maillist'}{$maillist}{'memberlist'} } ){   
        if (exists $belwue_members{$member}){
            delete $belwue_members{$member};
        } else {
            push @to_add, $member;
        }
    }
    foreach my $member ( keys %belwue_members){
        push @to_remove, $member;
    }

    # printout
    print "* Members to add to maillist $maillist:\n";
    foreach my $entry (@to_add){
        print "   * $entry\n";
    }
    print "* Members to delete from maillist $maillist:\n";
    foreach my $entry (@to_remove){
        print "   * $entry\n";
    }
}

system("chown -R $target_owner $target_dir");
print "Result files created in $result_dir\n";


#print Dumper(%belwue);


############################################################
# subs
############################################################
sub add_maillist_to_maillist {
    my ($list,$maillist) = @_;
    #print "   * Adding members of $list to $maillist\n";
    foreach my $member ( @{ $belwue{'maillist'}{$list}{'memberlist'} } ){   
        #print "      * adding $member to $maillist\n";
        my ($user,$string)=split(/@/,$member);
        push @{ $belwue{'maillist'}{$maillist}{'memberlist'} }, $member;
        push @{ $belwue{'maillist'}{$maillist}{'memberuser'} }, $user;
    }


}


sub  check_options{
   my ($parse_ergebnis) = @_;
   if (not $parse_ergebnis==1){
      my @list = split(/\//,$0);
      my $scriptname = pop @list;
      print "\nYou have made a mistake, when specifying options.\n"; 
      print "See error message above. \n\n";
      print "... $scriptname is terminating.\n\n";
      exit;
   } else {
      if($verbose>=3){
         print "All options  were recognized.\n";
      }
   }
}



sub get_passwd_charlist {
   # characters for passwords
   # avoid: 1,i,l,I,L,j
   # avoid: 0,o,O
   # avoid: Capital letters, that can be confused with 
   #        small letters: C,I,J,K,L,O,P,S,U,V,W,X,Y,Z 
   my @zeichen=('a','b','c','d','e','f','g','h','i','j','k',
                'm','n','o','p','q','r','s','t','u','v',
                'w','x','y','z',
                'A','B','D','E','F','G','H','L','M','N','Q','R','T',
                '2','3','4','5','6','7','8','9',
                '!','$','&','(',')','=','?'
       );
   return @zeichen;
}


sub remove_whitespace {
    my ($string)=@_;
    $string=~s/^\s+//g;# remove leading whitespace
    $string=~s/\s+$//g;# remove trailing whitespace
    return $string;    
}



sub get_plain_password {
    my @password_chars=@_;
    my $password="";
    my $i;
    # Teacher
    $password=&create_plain_password(10,@password_chars);
    return $password;
}


sub create_plain_password {
    my ($num)=shift;
    my @password_chars=@_;
    my $password="";
    until ($password=~m/[!,\$,&,\(,\),=,?]/ and 
           $password=~m/[a-z]/ and 
           $password=~m/[A-Z]/ and
           $password=~m/[0-9]/
	){
        $password="";
        for ($i=1;$i<=$num;$i++){
            $password=$password.$password_chars[int (rand $#password_chars)];
        }
	#print "Password to test: $password\n";
    }
    #print "Password OK: $password\n";
    return $password;
}

