#!/usr/bin/perl -w
# This script (sophomorix-mail) is maintained by Rüdiger Beck
# It is Free Software (License GPLv3)
# If you find errors, contact the author
# jeffbeck@web.de  or  jeffbeck@linuxmuster.net

# modules
use strict;
use Getopt::Long;
Getopt::Long::Configure ("bundling");
use Sophomorix::SophomorixConfig;
use List::MoreUtils qw(uniq);
use HTML::TableExtract;
use Data::Dumper;
$Data::Dumper::Indent = 1;
$Data::Dumper::Sortkeys = 1;
$Data::Dumper::Useqq = 1;
$Data::Dumper::Terse = 1; 
use Net::LDAP;
use JSON;
use Sophomorix::SophomorixBase qw(
                                 print_line
                                 print_title
                                 unlock_sophomorix
                                 lock_sophomorix
                                 log_script_start
                                 log_script_end
                                 log_script_exit
                                 backup_auk_file
                                 get_passwd_charlist
                                 get_plain_password
                                 check_options
                                 config_sophomorix_read
                                 result_sophomorix_init
                                 result_sophomorix_add
                                 result_sophomorix_add_summary
                                 result_sophomorix_check_exit
                                 result_sophomorix_print
                                 remove_from_list    
                                 console_print_mail_user
                                 console_print_mailquota_user
                                 json_dump
                                 );
use Sophomorix::SophomorixSambaAD qw(
                                 AD_school_create
                                 AD_bind_admin
                                 AD_dns_get
                                 AD_get_user
                                 AD_get_quota
                                 AD_user_kill
                                 AD_unbind_admin
                                 AD_object_search
                                 AD_user_create
                                 AD_user_update
                                 AD_user_setquota
                                 AD_group_create
                                 AD_group_kill
                                 AD_group_addmember
                                 AD_get_schoolname
                                 AD_get_name_tokened
                                 AD_group_update
                                 AD_project_sync_members
                                 AD_dn_fetch_multivalue
                                 AD_get_passwd
                                    );
my @arguments = @ARGV;

# option vars
$Conf::log_level=1;

my $help=0;
my $info=0;
my $belwue_info=0;

my $json=0;
my $config=0;
my $school="";
my $user="";
$Conf::log_level=1;

# belwue options
my $download_belwue_data=0;
my $analyze_belwue_data=0;

# Parsen der Optionen
my $testopt=GetOptions(
           "help|h" => \$help,
           "info|i" => \$info,
           "belwue-info" => \$belwue_info,
           "config" => \$config,
           "download-belwue-data" => \$download_belwue_data,
           "analyze-belwue-data" => \$analyze_belwue_data,
           "json|j+" => \$json,
           "verbose|v+" => \$Conf::log_level,
           "school|share|s=s" => \$school,
           "user|u=s" => \$user,
          );

my %sophomorix_result=&result_sophomorix_init("sophomorix-mail");
# Prüfen, ob Optionen erkannt wurden
&check_options($testopt,\%sophomorix_result,$json);

# Reading Configuration
my ($ldap,$root_dse) = &AD_bind_admin(\@arguments,\%sophomorix_result,$json);
my $root_dns=&AD_dns_get($root_dse);
my %sophomorix_config=&config_sophomorix_read($ldap,$root_dse,\%sophomorix_result);
my ($smb_admin_pass)=&AD_get_passwd($DevelConf::sophomorix_file_admin,
                                     $DevelConf::secret_file_sophomorix_file_admin);


# no option --> do all
if ($download_belwue_data==0 and
    $analyze_belwue_data==0){
    # analyze and download
    $download_belwue_data=1;
    $analyze_belwue_data=1;
} elsif ($download_belwue_data==1){
    # only download
    $analyze_belwue_data=0;
} elsif ($analyze_belwue_data==1){
    # only analyze
    $download_belwue_data=0;
}



# --help
if ($help==1) {
   # Scriptname ermitteln
   my @list = split(/\//,$0);
   my $scriptname = pop @list;
   # Befehlbeschreibung
   print('
sophomorix-mail calcultes mailinglist and does  ... nothing so far

Options
  -h  / --help
  -v  / --verbose
  -vv / --verbose --verbose


Show the mailaccounts and maillists that should be created 
  -i  / --info
  --belwue--info --json --analyze-belwue-data 
    (show the same information after modifications by --analyze-belwue-data)

Belwue options:

Show config (contains paswords)
  --config --json (--json --json)
Download and parse only (no analyzing):
  --download-belwue-data
Analyze the download only (no download/parsing):
  --analyze-belwue-data

Additional members not in the same maildomain:
  One member per line in
  /etc/linuxmuster/sophomorix/<school>/belwue/<maillist-name>.txt
  These are added at the end of the maillist

Please see the sophomorix-mail(8) man pages for full documentation
');
   print "\n";
   exit;
}




# create sharelist from options
# --school <school>/--share <share>
my @sharelist=();
if ($school ne ""){
    if (exists $sophomorix_config{'samba'}{'net_conf_list'}{$school}){
	push @sharelist,$school;
    } else {
        print "\nERROR: $school is not a SMB-share!\n\n";
	exit 88;
    }
} else {
    # without option use only school shares
    @sharelist=@{ $sophomorix_config{'LISTS'}{'SCHOOLS'} };
}




# --user user1,user2
my @userlist=();
if ($user ne ""){
    @userlist=split(/,/,$user);
}



my $ref_mail=&AD_get_quota({ldap=>$ldap,
                             root_dse=>$root_dse,
                             root_dns=>$root_dns,
                             smbcquotas=>0,
                             smb_admin_pass=>$smb_admin_pass,
                             sophomorix_config=>\%sophomorix_config,
                           });



if ($info==1 and $user eq ""){
    &json_dump({json => $json,
                jsoninfo => "MAIL",
                jsoncomment => "sophomorix mail",
                object_name => $school,
                log_level => $Conf::log_level,
                hash_ref=>$ref_mail,
                sophomorix_config=>\%sophomorix_config,
              });
    exit;
} elsif ($info==1 and $user ne ""){
    # user given
    &console_print_mail_user({user => $user,
                              log_level => $Conf::log_level,
                              ref_mail=>$ref_mail,
                              ref_sophomorix_config=>\%sophomorix_config,
                            });
    &console_print_mailquota_user({user => $user,
                                   log_level => 2, # always show maildata as a block
                                   ref_quota=>$ref_mail,
                                   ref_sophomorix_config=>\%sophomorix_config,
                                 });

    exit;
}



################################################################################
# continue with the calculated mail from $ref_mail
################################################################################

&result_sophomorix_check_exit(\%sophomorix_result,\%sophomorix_config,$json);
# ===========================================================================
# Start
# ===========================================================================
&log_script_start(\@arguments,\%sophomorix_result,\%sophomorix_config);


#my %mailconf=();

# setting up mailconf
foreach my $school (@sharelist){
    my $config;
    if (exists $sophomorix_config{'SCHOOLS'}{$school}{'MAILCONF'}){
        $config=$sophomorix_config{'SCHOOLS'}{$school}{'MAILCONF'};
    }

    if ($config eq "none"){
        print "School $school ($config) has no MAILTYPE\n";
        next;
    } elsif (not -e $config){
        print "No config found for $school ($config)\n";
        next;
    } 

    # decide which sub to use
    if ($sophomorix_config{'SCHOOLS'}{$school}{'MAILTYPE'} eq "belwue"){
        # belwue
        my $ref_belwue_mailconf=&belwue_maildata_config(
            $school,
            $sophomorix_config{'SCHOOLS'}{$school}{'MAILCONF'},
            \%sophomorix_config);
	if ($download_belwue_data==1){
            &belwue_maildata_fetch(
                $school,
                $ref_belwue_mailconf,
                \%sophomorix_config);
        }
	if ($analyze_belwue_data==1){
            &belwue_maildata_check(
                $school,
                $ref_belwue_mailconf,
                $ref_mail,
                \%sophomorix_config);
        }
        if ($belwue_info==1){
            &json_dump({json => $json,
                        jsoninfo => "MAIL",
                        jsoncomment => "sophomorix mail after belwue",
                        object_name => $school,
                        log_level => $Conf::log_level,
                        hash_ref=>$ref_mail,
                        sophomorix_config=>\%sophomorix_config,
                      });
        }
        exit;
    } else {
        print "\n\nERROR: $sophomorix_config{'SCHOOLS'}{$school}{'MAILTYPE'} not known\n";
        exit 88;
    }
}



&AD_unbind_admin($ldap);
&log_script_end(\@arguments,\%sophomorix_result,\%sophomorix_config,$json);
############################################################
# End
############################################################



############################################################
# subs
############################################################
sub bind_belwue_admin {
    my ($ref_belwue_mailconf)=@_;
    # check connection 
    if($Conf::log_level>=3){
        print "   Checking Belwue connection ...\n";
    }

    # bind
    if($Conf::log_level>=3){
        print "HOST:      $ref_belwue_mailconf->{'CONNECT'}{HOST} \n";
        print "ADMINUSER: $ref_belwue_mailconf->{'CONNECT'}{ADMINUSER} \n";
        print "PASS:      $ref_belwue_mailconf->{'CONNECT'}{PASSWORD}\n";
    }
    my $ldap = Net::LDAP->new($ref_belwue_mailconf->{'CONNECT'}{HOST});

    my $mesg = $ldap->bind($ref_belwue_mailconf->{'CONNECT'}{ADMINUSER}, 
                      password => $ref_belwue_mailconf->{'CONNECT'}{PASSWORD});
    # show errors from bind
    $mesg->code && die $mesg->error;
    return ($ldap);
}



sub unbind_belwue_admin {
    my ($ldap) = @_;
    my $mesg = $ldap->unbind();
    #  show errors from unbind
    $mesg->code && die $mesg->error;
}



sub wget_return {
    my ($return,$object)=@_;
    if ($return==0){
        print "   * Succesfully downloded html page for $object\n";
    } else {
        print "   * ERROR downloading $object: wget returned error code $return\n";
        exit 88;
    }
}



sub belwue_maildata_config {
    my ($school,$mailconf,$ref_sophomorix_config)=@_;
    my %belwue_mailconf=();
    my $ref_belwue_mailconf=\%belwue_mailconf;
    &print_title("Fetching maildata for school $school:");
    tie %{ $ref_belwue_mailconf->{'CONFIG'} }, 'Config::IniFiles',
        ( -file => $mailconf, 
          -handle_trailing_comment => 1,
        );

    # check some options
    if ($ref_belwue_mailconf->{'CONFIG'}{'CONFIG'}{'MAILBOX_CREATE'} ne "all" and
        $ref_belwue_mailconf->{'CONFIG'}{'CONFIG'}{'MAILBOX_CREATE'} ne "maillistmembers"){
        print "\nERROR: Unknown option for MAILBOX_CREATE: $ref_belwue_mailconf->{'CONFIG'}{'CONFIG'}{'MAILBOX_CREATE'}\n\n";
        exit 88;
    }

    # calculate connect data
    $ref_belwue_mailconf->{'CONNECT'}{'BASE'}="CN=".$ref_belwue_mailconf->{'CONFIG'}{'ACCOUNT'}{'BASE'};
    $ref_belwue_mailconf->{'CONNECT'}{'BASESIMPLE'}=$ref_belwue_mailconf->{'CONFIG'}{'ACCOUNT'}{'BASE'};
    $ref_belwue_mailconf->{'CONNECT'}{'SCOPE'}="sub";
    $ref_belwue_mailconf->{'CONNECT'}{'FILTER'}="(cn=*)";
    $ref_belwue_mailconf->{'CONNECT'}{'HOST'}=$ref_belwue_mailconf->{'CONFIG'}{'ACCOUNT'}{'PROTOCOL'}."://".
        $ref_belwue_mailconf->{'CONFIG'}{'ACCOUNT'}{'SERVER'}.":".
        $ref_belwue_mailconf->{'CONFIG'}{'ACCOUNT'}{'PORT'};
    $ref_belwue_mailconf->{'CONNECT'}{'ADMINUSER'}=$ref_belwue_mailconf->{'CONFIG'}{'ACCOUNT'}{'ADMINUSER'}.
        "@".
        $ref_belwue_mailconf->{'CONFIG'}{'ACCOUNT'}{'BASE'};
    $ref_belwue_mailconf->{'CONNECT'}{'ADMINURL'}="https://".
        $ref_belwue_mailconf->{'CONFIG'}{'ACCOUNT'}{'SERVER'}.
        ":9010/DomainAdmin";
    $ref_belwue_mailconf->{'CONNECT'}{'PASSWORD'}=$ref_belwue_mailconf->{'CONFIG'}{'ACCOUNT'}{'PASSWORD'};

    # config dir (maillist appendices)
    $ref_belwue_mailconf->{'CONFIG_DIR'}=$ref_sophomorix_config->{'SCHOOLS'}{$school}{'MAILCONFDIR'};

    # logindata dir
    $ref_belwue_mailconf->{'PWD'}{'FIRSTPWD_DIR'}=$ref_sophomorix_config->{'INI'}{'PATHS'}{'MAIL'}.
        "/belwue/".$school."/".$school.".belwue.logindata";
        
    # download dir/files
    $ref_belwue_mailconf->{'DOWNLOAD'}{'DIR'}=$ref_sophomorix_config->{'INI'}{'PATHS'}{'MAIL'}.
        "/belwue/".$school."/".$school.".belwue.downloads";
    $ref_belwue_mailconf->{'DOWNLOAD'}{'OBJECTS'}=$ref_belwue_mailconf->{'DOWNLOAD'}{'DIR'}.
	"/objects.html";

    # result dir/files
    $ref_belwue_mailconf->{'RESULT'}{'DIR'}=$ref_sophomorix_config->{'INI'}{'PATHS'}{'MAIL'}.
        "/belwue/".$school."/".$school.".belwue.data";
    $ref_belwue_mailconf->{'RESULT'}{'MAILBOXES'}=$ref_belwue_mailconf->{'RESULT'}{'DIR'}.
        "/".$school.".belwue.multimailboxes";
    $ref_belwue_mailconf->{'RESULT'}{'MAILLISTS'}=$ref_belwue_mailconf->{'RESULT'}{'DIR'}.
        "/".$school.".belwue.maillists";
    $ref_belwue_mailconf->{'RESULT'}{'ALIASES'}=$ref_belwue_mailconf->{'RESULT'}{'DIR'}.
        "/".$school.".belwue.aliases";

    # upload dir/files
    $ref_belwue_mailconf->{'UPLOAD'}{'DIR'}=$ref_sophomorix_config->{'INI'}{'PATHS'}{'MAIL'}.
        "/belwue/".$school."/".$school.".belwue.uploads";
    $ref_belwue_mailconf->{'UPLOAD'}{'MAILBOXES_ADD'}=$ref_belwue_mailconf->{'UPLOAD'}{'DIR'}.
        "/MAILBOXES_ADD_".$school.".belwue.multimailboxes-utf8.txt";
    $ref_belwue_mailconf->{'UPLOAD'}{'ALIAS_ADD'}=$ref_belwue_mailconf->{'UPLOAD'}{'DIR'}.
        "/ALIASES_ADD_".$school.".belwue.txt";
    $ref_belwue_mailconf->{'UPLOAD'}{'ALIAS_DELETE'}=$ref_belwue_mailconf->{'UPLOAD'}{'DIR'}.
        "/ALIASES_DELETE_".$school.".belwue.txt";
    $ref_belwue_mailconf->{'UPLOAD'}{'MAILBOXES_DELETE'}=$ref_belwue_mailconf->{'UPLOAD'}{'DIR'}.
        "/MAILBOXES_DELETE_".$school.".belwue.multimailboxes-utf8.txt";

    if ($config==1){
        &json_dump({json => $json,
                    jsoninfo => "BELWUECONFIG",
                    jsoncomment => "sophomorix mail",
                    object_name => $school,
                    log_level => $Conf::log_level,
                    hash_ref=>\%belwue_mailconf,
                    sophomorix_config=>\%sophomorix_config,
                  });
        exit;
    }

    return \%belwue_mailconf;
}



sub belwue_maildata_fetch {
    my ($school,$ref_belwue_mailconf,$ref_sophomorix_config)=@_;
    my %belwue=();
    
    ############################################################
    # ldap address book
    ############################################################ 
    print "Accessing Belwue addressbook via ldap\n";
    my ($ldap) = &bind_belwue_admin($ref_belwue_mailconf);
    my $mesg = $ldap->search(
                   base   => $ref_belwue_mailconf->{'CONNECT'}{'BASE'},
                   scope => $ref_belwue_mailconf->{'CONNECT'}{'SCOPE'},
                   filter => $ref_belwue_mailconf->{'CONNECT'}{'FILTER'},
                        );

    my $max = $mesg->count; 
    my $count = $mesg->count;
    for( my $index = 0 ; $index < $max ; $index++) {
        my $num=$index+1;
        my $entry = $mesg->entry($index);
        my $dn=$entry->dn();
        my $uid=$entry->get_value('uid');
        my $cn=$entry->get_value('cn');
        my $given=$entry->get_value('givenName');
        my $sn=$entry->get_value('sn');
        my $server=$entry->get_value('hostServer');
        my $mail=$entry->get_value('mail');

        if (not defined $given){
            $given="";
        }
        if($Conf::log_level>=2){
	    print "$num) dn: $dn\n";
	    print "   * cn:          $cn\n";
	    print "   * givenName:   $given\n";
	    print "   * hostServer:  $server\n";
	    print "   * mail:        $mail\n";
	    print "   * sn:          $sn\n";
	    print "   * uid:         $uid\n";
            print "\n";
        }

        $belwue{'OBJECTS'}{$uid}{'CN'}=$cn;
        $belwue{'OBJECTS'}{$uid}{'givenName'}=$given;
        $belwue{'OBJECTS'}{$uid}{'hostServer'}=$server;
        $belwue{'OBJECTS'}{$uid}{'mail'}=$mail;
        $belwue{'OBJECTS'}{$uid}{'sn'}=$sn;
        $belwue{'OBJECTS'}{$uid}{'uid'}=$uid;
    }
    &unbind_belwue_admin($ldap); 

    ############################################################
    # downloading objects
    ############################################################ 
    print "Downloading/parsing Objects page:\n";
    system("mkdir -p $ref_belwue_mailconf->{'DOWNLOAD'}{'DIR'}");
    system("mkdir -p $ref_belwue_mailconf->{'RESULT'}{'DIR'}");

    # download object list
    my $download_objects_command="wget -q --http-user=admin ".
         "--http-password=$ref_belwue_mailconf->{'CONNECT'}{PASSWORD} ".
         "--output-document=$ref_belwue_mailconf->{'DOWNLOAD'}{'DIR'}/objects.html ".
         "\"$ref_belwue_mailconf->{'CONNECT'}{ADMINURL}/$ref_belwue_mailconf->{'CONNECT'}{BASESIMPLE}".
         "/ObjectList.html?domainName=$ref_belwue_mailconf->{'CONNECT'}{BASESIMPLE}\"";

   if($Conf::log_level>=2){
       print "\nWGET: $download_objects_command\n\n";
    }
    my $return=system($download_objects_command);
    &wget_return($return,"Objects");

    ############################################################
    # parsing objects
    ############################################################
    # file to parse
    print "   * Parsing $ref_belwue_mailconf->{'DOWNLOAD'}{'OBJECTS'}\n";

    # list of headers
    my $table_headers = [ 'Objekt', 'Typ','Speicher','Letzter Zugriff' ];

    # constructor
    my $table_extract = HTML::TableExtract->new(headers => $table_headers);
    $table_extract->utf8_mode(1);
    $table_extract->parse_file($ref_belwue_mailconf->{'DOWNLOAD'}{'OBJECTS'});
    my ($table) = $table_extract->tables;
    print "... done with Objects page:\n";
    print "Downloading/parsing html pages:\n";

    foreach my $row ($table->rows) {
        my ($object,$type,$storage,$access)=@$row;
        if (not defined $storage){
            $storage="---";
        }
        if (not defined $access){
            $access="---";
        }
        if (not defined $access){
            $access="never";
        }

        if($Conf::log_level>=2){
            print "      Object: $object\n";
            print "      Type: $type\n";
            print "      Storage: $storage\n";
            print "      Access: $access\n";
        }

        # add to types
        if ($type eq "Mailingliste"){
            $belwue{'maillist'}{$object}{'type'}=$type;
            push @{ $belwue{'LISTS'}{'MAILLISTS'} }, $object;
            ############################################################
            # downloading maillist data
            ############################################################
            my $download_list_command="wget -q --http-user=admin ".
                "--http-password=$ref_belwue_mailconf->{'CONNECT'}{PASSWORD} ".
                "--output-document=$ref_belwue_mailconf->{'DOWNLOAD'}{'DIR'}/$object.html ".
                "\"$ref_belwue_mailconf->{'CONNECT'}{ADMINURL}/$ref_belwue_mailconf->{'CONNECT'}{BASESIMPLE}".
                "/Subscribers.html?InCluster=1&domainName=$ref_belwue_mailconf->{'CONNECT'}{BASESIMPLE}".
                "&&listName=$object\"";
            if($Conf::log_level>=2){
                print "\nWGET: $download_list_command\n\n";
            }
            my $return=system($download_list_command);
            &wget_return($return,$object);

            ############################################################
            # parsing maillist data
            ############################################################
            my $html_doc = $ref_belwue_mailconf->{'DOWNLOAD'}{'DIR'}."/".$object.".html";
            print "   * Parsing $html_doc\n";

            # list of headers
            # Umlaut in header does nor work
#            my $table_headers = [ 'Email','Zustellungsart','Anmeldezeit','Nachrichten zurückgewiesene','Angezeigter Name' ];
            my $table_headers = [ 'Email', 'Zustellungsart', 'Anmeldezeit'];

            # constructor
            my $table_extract = HTML::TableExtract->new(headers => $table_headers);
            $table_extract->utf8_mode(1);
            $table_extract->parse_file($html_doc);
            my ($table) = $table_extract->tables;
            foreach my $row ($table->rows) {
                my ($member_email,$type,$time,$bounced,$displayname)=@$row;
                if (not defined $member_email){
                    # no members
                    last;
                }
                #print "$object: $member_email  $type  $time\n";
                if ($type ne "Abonnement aufheben"){
                    $belwue{'maillist'}{$object}{'members'}{$member_email}="member";
                    push @{ $belwue{'maillist'}{$object}{'memberlist'} }, $member_email;
                }
            }
            # sort the memberlist if not empty
            if ( $#{ $belwue{'maillist'}{$object}{'memberlist'} }>0 ){
                 @{ $belwue{'maillist'}{$object}{'memberlist'} } = sort @{ $belwue{'maillist'}{$object}{'memberlist'}  };
            }
        } elsif ($type eq "Alias"){
            $belwue{'alias'}{$object}=$storage;
            $belwue{'alias_reverse'}{$storage}=$object;
            # aliases are in storage
            $belwue{'OBJECTS'}{$storage}{'alias'}=$object;
            push @{ $belwue{'LISTS'}{'ALIASES'} }, $object;
        } elsif ($type eq "Multi-Mailbox"){
            $belwue{'multimailbox'}{$object}{'type'}=$type;
            $belwue{'multimailbox'}{$object}{'storage'}=$storage;
            $belwue{'multimailbox'}{$object}{'access'}=$access;
            push @{ $belwue{'LISTS'}{'MAILBOXES'}  }, $object;
        } else {
            print "Unknown object $type\n";
        }
    }
    ############################################################
    # printout data/write data into files
    ############################################################
    open (BOX,   ">$ref_belwue_mailconf->{'RESULT'}{'MAILBOXES'}");
    open (ALIAS, ">$ref_belwue_mailconf->{'RESULT'}{'ALIASES'}");
    open (LIST,  ">$ref_belwue_mailconf->{'RESULT'}{'MAILLISTS'}");

    # MAILBOXES
    ##################################################
    @{ $belwue{'LISTS'}{'MAILBOXES'} } = sort @{ $belwue{'LISTS'}{'MAILBOXES'} };
    print "MultiMailboxes:\n";
    my $num_mbox=1;

    my $mailbox_num=$#{ $belwue{'LISTS'}{'MAILBOXES'} }+1;
    print "   $mailbox_num MAILBOXES at belwue.\n";
    foreach my $uid (@{ $belwue{'LISTS'}{'MAILBOXES'} }){
        print BOX $uid.";\n";
        if($Conf::log_level>=2){
            print "   $num_mbox) $uid\n";
        }
        $num_mbox++;
    }

    # MAILLISTS
    ##################################################
    @{ $belwue{'LISTS'}{'MAILLISTS'} } = sort @{ $belwue{'LISTS'}{'MAILLISTS'} };
    my $maillist_num=$#{ $belwue{'LISTS'}{'MAILLISTS'} }+1;
    print "Mailing Lists:\n";
    print "   $maillist_num MAILLISTS at belwue.\n";
    foreach my $list ( @{ $belwue{'LISTS'}{'MAILLISTS'} } ){
        my $member_string=join(",",@{ $belwue{'maillist'}{$list}{'memberlist'} });
        my $member_num=$#{ $belwue{'maillist'}{$list}{'memberlist'} }+1;
        print LIST "$list:$member_string\n";
        if($Conf::log_level>=2){
            print "   * $list ($member_num members)\n";
        }
        my $num_list=1;
        foreach my $member ( @{ $belwue{'maillist'}{$list}{'memberlist'} } ){
            if (not defined $member){
                next;
            } 
            if($Conf::log_level>=2){
                print "     $num_list) --> $member\n";
            }
            $num_list++;
        }
    }

    # ALIASES
    ##################################################
    @{ $belwue{'LISTS'}{'ALIASES'} } = sort @{ $belwue{'LISTS'}{'ALIASES'} };
    print "Mail Aliase:\n";
    my $mailalias_num=$#{ $belwue{'LISTS'}{'ALIASES'} };
    print "   $mailalias_num MAILALIAS at belwue.\n";
    my $num=1;
    foreach my $alias ( @{ $belwue{'LISTS'}{'ALIASES'} }){
        print ALIAS "$alias:$belwue{'alias'}{$alias}\n";
        if($Conf::log_level>=2){
            print "   $num) $alias --> $belwue{'alias'}{$alias}\n";
        }
        $num++;
    }

    close(BOX);
    close(ALIAS);
    close(LIST);
    print "\n";

    if($Conf::log_level>=2){
        print Dumper(\%belwue);
    }
}



sub belwue_maildata_check {
    my ($school,$ref_belwue_mailconf,$ref_mail,$ref_sophomorix_config)=@_;
    my %action=();
    my @belwue_tmp=();
    if (not -f $ref_belwue_mailconf->{'DOWNLOAD'}{'OBJECTS'} ){
        print "\nERROR: No previous belwue download found!\n\n";
        exit 88;
    }

    system("mkdir -p $ref_belwue_mailconf->{'PWD'}{'FIRSTPWD_DIR'}");

    
    ############################################################
    # ALIASES
    ############################################################
    # create belwue list
    open (ALIAS, "<$ref_belwue_mailconf->{'RESULT'}{'ALIASES'}");
    while (<ALIAS>){
        chomp();
        my ($alias,$user)=split(/:/);
        $action{'ALIASES'}{$user}{'BELWUE'}=$alias;
    }
    close(ALIAS);

    ############################################################
    # MAILBOXES
    ############################################################
    open (BOX, "<$ref_belwue_mailconf->{'RESULT'}{'MAILBOXES'}");
    while (<BOX>){
        my ($user)=split(/;/);
        $action{'MAILBOXES'}{$user}{'BELWUE'}="EXISTS";
        push @belwue_tmp, $user;
    }
    close(BOX);

    # mailaccounts
    # Walk through AD users, decide ADD/KEEP
    foreach my $user (@{ $ref_mail->{'LISTS'}{'USER_by_SCHOOL'}{$school} }){
        if ($ref_belwue_mailconf->{'CONFIG'}{'CONFIG'}{'MAILBOX_CREATE'} eq "all"){
            # all
            if (exists $action{'MAILBOXES'}{$user}){
		#print "$user KEEP\n";
                $action{'MAILBOXES'}{$user}{'AD'}="EXISTS";
                $action{'MAILBOXES'}{$user}{'ACTION'}="KEEP";
            } else {
		#print "$user ADD\n";
                $action{'MAILBOXES'}{$user}{'ACTION'}="ADD";
                $action{'MAILBOXES'}{$user}{'AD'}="EXISTS";
            }
        } elsif ($ref_belwue_mailconf->{'CONFIG'}{'CONFIG'}{'MAILBOX_CREATE'} eq "maillistmembers"){
            # maillistmembers
            if ($ref_mail->{'QUOTA'}{'USERS'}{$user}{'MAIL'}{'MAILLISTMEMBER'} eq "TRUE"){
                if (exists $action{'MAILBOXES'}{$user}){
   		    #print "$user KEEP\n";
                    $action{'MAILBOXES'}{$user}{'AD'}="EXISTS";
                    $action{'MAILBOXES'}{$user}{'ACTION'}="KEEP";
                } else {
  		    #print "$user ADD\n";
                    $action{'MAILBOXES'}{$user}{'AD'}="EXISTS";
                    $action{'MAILBOXES'}{$user}{'ACTION'}="ADD";
                }
	    } else {
                # mark user as unneeded
                $action{'MAILBOXES'}{$user}{'ACTION'}="NO_MAILBOX";
            }
        }
    }
    
    # Walk through belwue users, decide DELETE
    foreach my $belwue_user (@belwue_tmp){
        if (not exists $ref_mail->{'QUOTA'}{'USERS'}{$belwue_user}){
            # DELETE if NONEXISTING
            $action{'MAILBOXES'}{$belwue_user}{'ACTION'}="DELETE";
	} elsif ( $ref_belwue_mailconf->{'CONFIG'}{'CONFIG'}{'MAILBOX_CREATE'} eq "maillistmembers" ){
            # DELETE if user is not MAILLISTMEMBER=TRUE
            if ( $ref_mail->{'QUOTA'}{'USERS'}{$belwue_user}{'MAIL'}{'MAILLISTMEMBER'} eq "FALSE" ){
                $action{'MAILBOXES'}{$belwue_user}{'ACTION'}="DELETE";
            }

	}
    }

    # create walk through lists ADD/KEEP/DELETE
    print "\n";
    print "ACTION MAILBOXES:\n";
    foreach my $user (keys %{ $action{'MAILBOXES'} } ){
        if ($action{'MAILBOXES'}{$user}{'ACTION'} eq "KEEP"){
            print "   KEEP:        $user\n";
            push @{ $action{'ACTIONLIST'}{'KEEP'} }, $user;
        } elsif ($action{'MAILBOXES'}{$user}{'ACTION'} eq "DELETE"){
            print "   DELETE:      $user\n";
            push @{ $action{'ACTIONLIST'}{'DELETE'} }, $user;
        } elsif ($action{'MAILBOXES'}{$user}{'ACTION'} eq "ADD"){
            print "   ADD:         $user\n";
            push @{ $action{'ACTIONLIST'}{'ADD'} }, $user;
        } elsif ($action{'MAILBOXES'}{$user}{'ACTION'} eq "NO_MAILBOX"){
            print "   NO_MAILBOX:  $user\n";
            push @{ $action{'ACTIONLIST'}{'NO_MAILBOX'} }, $user;
        } else {
            print "##########################unknown #######:    $user\n";
        }
    }

    # sort the result lists for ADD/KEEP/DELETE
    if ( $#{ $action{'ACTIONLIST'}{'KEEP'} }>0 ){
        @{ $action{'ACTIONLIST'}{'KEEP'} } = sort @{ $action{'ACTIONLIST'}{'KEEP'} };
    }
    if ( $#{ $action{'ACTIONLIST'}{'DELETE'} }>0 ){
        @{ $action{'ACTIONLIST'}{'DELETE'} } = sort @{ $action{'ACTIONLIST'}{'DELETE'} };
    }

    if ( $#{ $action{'ACTIONLIST'}{'ADD'} }>0 ){
        @{ $action{'ACTIONLIST'}{'ADD'} } = sort @{ $action{'ACTIONLIST'}{'ADD'} };
    }
    if ( $#{ $action{'ACTIONLIST'}{'NO_MAILBOX'} }>0 ){
        @{ $action{'ACTIONLIST'}{'NO_MAILBOX'} } = sort @{ $action{'ACTIONLIST'}{'NO_MAILBOX'} };
    }

    # write the MAILBOX files
    # delete previous files    
    system("mkdir -p $ref_belwue_mailconf->{'UPLOAD'}{'DIR'}");
    system("rm -f $ref_belwue_mailconf->{'UPLOAD'}{'DIR'}/*");
    my @password_chars=&get_passwd_charlist();

    # ADD
    if ( $#{ $action{'ACTIONLIST'}{'ADD'} }>-1 ){
        open (ADD,">$ref_belwue_mailconf->{'UPLOAD'}{'MAILBOXES_ADD'}");
        print ADD "Name\tRealname\tType\tPassword\tStorage\tAliases\n";
        foreach my $user (@{ $action{'ACTIONLIST'}{'ADD'} }){
            my $alias="";
            my $mailquota=$ref_mail->{'QUOTA'}{'USERS'}{$user}{'MAILQUOTA'}{'CALC'};
            if ($ref_mail->{'QUOTA'}{'USERS'}{$user}{'MAIL'}{'ALIAS'} eq "TRUE"){
                $alias=$ref_mail->{'QUOTA'}{'USERS'}{$user}{'MAIL'}{'ALIASNAME'};
            }

            my $file=$ref_mail->{'QUOTA'}{'USERS'}{$user}{'sophomorixAdminFile'};
            my $plain_password;
            my $pwd_file=$ref_belwue_mailconf->{'PWD'}{'FIRSTPWD_DIR'}."/".$user.".pwd";
            my $login_file=$ref_belwue_mailconf->{'PWD'}{'FIRSTPWD_DIR'}."/".$user.".txt";
            if ( -f $pwd_file ){
                $plain_password=`cat $pwd_file`;
                open (PWD,"<$pwd_file");
                while (<PWD>){
                    $plain_password=$_;
                }
                close(PWD);
            } else {
                $plain_password=&get_plain_password(
                                $ref_mail->{'QUOTA'}{'USERS'}{$user}{'sophomorixRole'},
                                $file,
                                $ref_sophomorix_config->{'FILES'}{'USER_FILE'}{$file}{'RANDOM_PWD'}, 
                                $ref_sophomorix_config->{'FILES'}{'USER_FILE'}{$file}{'PWD_LENGTH'}, # length of random pwd
                                "01.01.1970",
                                $ref_sophomorix_config,
                                @password_chars);
                # save password in file
                open (PWD,">$pwd_file");
                print PWD $plain_password;
                close(PWD);
                # create login card
                my $alias_display;
                if ($alias eq ""){
                    $alias_display="---";
                } else {
                    $alias_display=$alias."\@".$ref_belwue_mailconf->{'CONFIG'}{'ACCOUNT'}{'BASE'};
                }
                open (LOGIN,">$login_file");
                print LOGIN "Zugangsdaten für die Email-Adresse: ".$user."\@".$ref_belwue_mailconf->{'CONFIG'}{'ACCOUNT'}{'BASE'}."\n";
                print LOGIN "                             Alias: ".$alias_display."\n";
                print LOGIN "\n";
                print LOGIN "Webmail-Abruf:     https://".$ref_belwue_mailconf->{'CONFIG'}{'ACCOUNT'}{'SERVER'}."\n";
                print LOGIN "   Benutzername:   ".$user."\@".$ref_belwue_mailconf->{'CONFIG'}{'ACCOUNT'}{'BASE'}."\n";
                print LOGIN "   Kennwort:       ".$plain_password."\n";
                print LOGIN "Mailquota:         ".$mailquota." MiB\n";
                print LOGIN "Mailbox-Typ:       MultiMailbox\n";
                print LOGIN "Adressbuch-Name:   ".$ref_mail->{'QUOTA'}{'USERS'}{$user}{'MAIL'}{'displayName'}."\n";
                close(LOGIN);
	    }
            # write entry
            print ADD "$user\t".
                  "$ref_mail->{'QUOTA'}{'USERS'}{$user}{'MAIL'}{'displayName'}\t".
                  "MultiMailbox\t".
                  "$plain_password\t".
                  "${mailquota}M\t".
                  "$alias\n";
        }
        close(ADD);
    }

    # KEEP (take care about aliases)
    print "\n";
    print "ACTION ALIASES:\n";
    if ( $#{ $action{'ACTIONLIST'}{'KEEP'} }>-1 ){
        open (ALIAS_ADD,">$ref_belwue_mailconf->{'UPLOAD'}{'ALIAS_ADD'}");
        open (ALIAS_DELETE,">$ref_belwue_mailconf->{'UPLOAD'}{'ALIAS_DELETE'}");
        foreach my $user (@{ $action{'ACTIONLIST'}{'KEEP'} }){
            if ($ref_mail->{'QUOTA'}{'USERS'}{$user}{'MAIL'}{'ALIAS'} eq "TRUE"){
                # user has wrong alias
                my $alias_AD=$ref_mail->{'QUOTA'}{'USERS'}{$user}{'MAIL'}{'ALIASNAME'};
                my $alias_belwue=$action{'ALIASES'}{$user}{'BELWUE'};
                if ( $alias_belwue ne $alias_AD){
                     # add
                     my $add_string="ADD alias ".$alias_AD.
                                    " to user ".$user." (wrong alias ".
                                    $alias_belwue." , should be ".$alias_AD.")\n";
                     print ALIAS_ADD $add_string;
                     print "   ".$add_string;
                     # delete
                     my $del_string="DELETE alias ".$alias_belwue.
                                    " of user ".$user." (wrong alias ".
                                    $alias_belwue." , should be ".$alias_AD.")\n";
                     print ALIAS_DELETE $del_string;
                     print "   ".$del_string;
                }
            }
            
            # user should NOT have alias, but its there
            if ($ref_mail->{'QUOTA'}{'USERS'}{$user}{'MAIL'}{'ALIAS'} eq "FALSE" and 
                exists $action{'ALIASES'}{$user}{'BELWUE'}){
                my $alias_belwue=$action{'ALIASES'}{$user}{'BELWUE'};
                # delete
                my $del_string="DELETE alias ".$alias_belwue.
                               " of user ".$user." (no alias configured)\n";
                print ALIAS_DELETE $del_string;
                print "   ".$del_string;
            }

            # user has no alias, but must have one
            if ($ref_mail->{'QUOTA'}{'USERS'}{$user}{'MAIL'}{'ALIAS'} eq "TRUE" and 
                not exists $action{'ALIASES'}{$user}{'BELWUE'}){
                my $alias_AD=$ref_mail->{'QUOTA'}{'USERS'}{$user}{'MAIL'}{'ALIASNAME'};
                # add
                my $add_string="ADD alias ".$alias_AD.
                               " to user ".$user." (alias configured but missing)\n";
                print ALIAS_ADD $add_string;
                print "   ".$add_string;
            }
        }
        close(ALIAS_ADD);
        close(ALIAS_DELETE);
    }

    # DELETE
    if ( $#{ $action{'ACTIONLIST'}{'DELETE'} }>-1 ){
        open (DELETE,">$ref_belwue_mailconf->{'UPLOAD'}{'MAILBOXES_DELETE'}");
        foreach my $user (@{ $action{'ACTIONLIST'}{'DELETE'} }){
            print DELETE $user."\n";
            # delete cached firstpassword/logindata, when user disappears in AD
            my $pwd_file=$ref_belwue_mailconf->{'PWD'}{'FIRSTPWD_DIR'}."/".$user.".pwd";
            my $login_file=$ref_belwue_mailconf->{'PWD'}{'FIRSTPWD_DIR'}."/".$user.".txt";
            if ( -f $pwd_file ){
                system("rm $pwd_file");
            }
            if ( -f $login_file ){
                system("rm $login_file");
            }
        }
        close(DELETE);
    }


    ############################################################
    # MAILLISTS
    ############################################################
    my %belwue_maillist_tmp=();
    my @belwue_maillist_tmp=();    

    # create belwue list
    open (LIST, "<$ref_belwue_mailconf->{'RESULT'}{'MAILLISTS'}");
    while (<LIST>){
        chomp();
        my ($maillist,$string)=split(/:/);
        my @members=split(/,/,$string);
        $action{'MAILLISTS'}{$maillist}{'BELWUE'}="EXISTS";

        push @{ $action{'MAILLISTS'}{$maillist}{'MEMBERS'} }, @members;
        push @belwue_maillist_tmp, $maillist;
    }
    close(LIST);

    # Walk through AD maillists, decide ADD/KEEP/UPDATE
    foreach my $maillist (@{ $ref_mail->{'LISTS'}{'MAILLISTS_by_SCHOOL'}{$school} }){
        if (exists $action{'MAILLISTS'}{$maillist}){
            #print "  * Maillist $maillist: nothing to do\n";
            $action{'MAILLISTS'}{$maillist}{'AD'}="EXISTS";
            $action{'MAILLISTS'}{$maillist}{'ACTION'}="KEEP";
            # ... test for update, matching users?
            
        } else {
            #print "  * Maillist: $maillist ADD\n";
            $action{'MAILLISTS'}{$maillist}{'AD'}="EXISTS";
            $action{'MAILLISTS'}{$maillist}{'ACTION'}="ADD";
        }
    }

    # Walk through belwue maillist, decide DELETE
    foreach my $belwue_maillist (@belwue_maillist_tmp){
        if (not exists $ref_mail->{'QUOTA'}{'LOOKUP'}{'MAILLISTS_by_SCHOOL'}{$school}{$belwue_maillist}){
            $action{'MAILLISTS'}{$belwue_maillist}{'ACTION'}="DELETE";
            #print "  * Maillist: $belwue_maillist DELETE\n";
        }
    }


    # create walk through lists ADD/KEEP/DELETE
    print "\n";
    print "ACTION MAILLISTS:\n";
    foreach my $maillist (keys %{ $action{'MAILLISTS'} } ){
        if ($action{'MAILLISTS'}{$maillist}{'ACTION'} eq "KEEP"){
            print "   KEEP:   $maillist\n";
            push @{ $action{'ACTIONLIST'}{'MAILLIST_KEEP'} }, $maillist;
        } elsif ($action{'MAILLISTS'}{$maillist}{'ACTION'} eq "DELETE"){
            print "   DELETE: $maillist\n";
            push @{ $action{'ACTIONLIST'}{'MAILLIST_DELETE'} }, $maillist;
        } elsif ($action{'MAILLISTS'}{$maillist}{'ACTION'} eq "UPDATE"){
            print "   UPDATE: $maillist\n";
            push @{ $action{'ACTIONLIST'}{'MAILLIST_UPDATE'} }, $maillist;
        } elsif ($action{'MAILLISTS'}{$maillist}{'ACTION'} eq "ADD"){
            print "   ADD:    $maillist\n";
            push @{ $action{'ACTIONLIST'}{'MAILLIST_ADD'} }, $maillist;
        } else {
            print "##########################unknown #######:    $maillist\n";
        }
    }
    
    # write the MAILLIST files
    # MAILLIST_ADD
    print "\n";
    foreach my $maillist (@{ $action{'ACTIONLIST'}{'MAILLIST_ADD'} }){
        my @member_mod=(); # modified and appendixed list

        # add domain modified members
        foreach my $member ( @{ $ref_mail->{'MAILLIST'}{$maillist}{'LIST'} } ){
            # replace domain
            my ($user,$domain)=split(/\@/,$member);
            my $member_mod=$user."\@".$ref_belwue_mailconf->{'CONFIG'}{'ACCOUNT'}{'BASE'};
            push @member_mod, $member_mod;
        }
 
        # add appendix members (if file exists)
        my $appendix_file=$ref_belwue_mailconf->{'CONFIG_DIR'}."/".$maillist.".txt";
        if (-f $appendix_file ){
            open(APPENDIX,"<$appendix_file");
            while(<APPENDIX>){
                my $line=$_;
                chomp($line);
                $line=~s/ //g; # remove whitespace
                if ($line ne ""){
                push @member_mod, $line;
                }
            }
            close(APPENDIX);
        }

        # mod the list address
        my $list_mod=$maillist."\@".$ref_belwue_mailconf->{'CONFIG'}{'ACCOUNT'}{'BASE'};
	$ref_mail->{'MAILLIST'}{$maillist}{'mail'}=$list_mod;

        # replace list in the hash for further use
        @{ $ref_mail->{'MAILLIST'}{$maillist}{'LIST'} }=@member_mod;
        

        # write the file:
        # filename MAILLIST_ADD_name.txt
        my $upload_file="MAILLIST_ADD_".$school.".belwue.".$maillist.".txt";
        my $upload_file_abs=$ref_belwue_mailconf->{'UPLOAD'}{'DIR'}."/".$upload_file;
	print "ADD $upload_file to upload dir\n";
        open (MAILLIST_ADD,">$upload_file_abs");
        foreach my $member (@member_mod){
            print "   * $member\n";
            print MAILLIST_ADD $member."\n";
        }
        print "\n";
        close('MAILLIST_ADD');
    }

    # MAILLIST_KEEP
    # nothing to do, maillist and members are kept as is

    # MAILLIST_UPDATE
    foreach my $maillist (@{ $action{'ACTIONLIST'}{'MAILLIST_UPDATE'} }){
         # filename MAILLIST_UPDATE_name.txt
    }

    # MAILLIST_DELETE
    foreach my $maillist (@{ $action{'ACTIONLIST'}{'MAILLIST_DELETE'} }){
         # filename MAILLIST_DELETE_name.txt
    }


    # sophomorix-gruppe sollte auch eine maillist anlegen
    # (zusammenlegen von hausmeister, teachers, zu kollegium )

    #print Dumper( $ref_mail->{'MAILLIST'} );


    my $ref_action=\%action;
#print Dumper( $ref_action );
#print Dumper( $ref_action->{'MAILLISTS'} );
    # print "bz:\n";
    # print Dumper( $ref_action->{'MAILBOXES'}{'bz'} );
    # print "bz2:\n";
    # print Dumper( $ref_action->{'MAILBOXES'}{'bz2'} );
    # print "znk:\n";
    # print Dumper( $ref_action->{'MAILBOXES'}{'znk'} );
    # print "maiersa23:\n";
    # print Dumper( $ref_action->{'MAILBOXES'}{'maiersa23'} );

    # print Dumper( $ref_action->{'ACTIONLIST'} );

    #print Dumper( \%action{'MAILBOXES'}{'EXISTS'}{'bz'} );
    #print Dumper( \%action{'MAILBOXES'}{'EXISTS'}{'bz2'} );
}
