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


# Bibliotheken
use strict;
use Quota;
use Getopt::Long;
use Sophomorix::SophomorixConfig;
use Sophomorix::SophomorixBase;
use Sophomorix::SophomorixAPI;
Getopt::Long::Configure ("bundling");
use DBI;
use Net::LDAP;
use IMAP::Admin;
use Mail::Send;
use Sophomorix::SophomorixPgLdap qw(show_modulename
                                    check_connections
                                    get_sys_users
                                    update_user_db_entry
                                    user_reaktivieren
                                    user_deaktivieren
                                    pg_get_group_list
                                    db_connect
                                    db_disconnect
                                    fetchdata_from_account
                                    fetchusers_from_adminclass
                                   );

my @arguments = @ARGV;


# Liste der Filesysteme auf denen Quota gesetzt werden
my @quota_fs=&get_quota_fs_liste();

# now
my $epoche_jetzt=time;

# ===========================================================================
# Anzahl quotierte Dateisysteme ermitteln
# ==========================================================================
my $quota_fs_num = &get_quota_fs_num();


# ===========================================================================
# Optionen verarbeiten
# ==========================================================================

# Variablen für Optionen
$Conf::log_level=1;
my $help=0;
my $noninteractive=0;
my $info=0;
my $loginname="";
my $classes="";
my $projects="";
my $student=0;
my $teacher=0;
my $administrator=0;
my $rooms="";
my $ws=0;
my $force=0;
my $skiplock=0;
my $sum=0;
my $system=0;
my $set=0;
my $cron=0;

# Parsen der Optionen
my $testopt=GetOptions(
           "users|user|u=s" => \$loginname,
           "class|classes|c=s" => \$classes,
           "project|projects|p=s" => \$projects,
           "student|students|s" => \$student,
           "teacher|teachers|t" => \$teacher,
           "administrator|administrators" => \$administrator,
           "room|rooms|r=s" => \$rooms,
           "workstations|workstation|w" => \$ws,
           "force" => \$force,
           "skiplock" => \$skiplock,
           "set" => \$set,
           "test" => \$DevelConf::testen,
           "sum" => \$sum,
           "verbose|v+" => \$Conf::log_level,
           "help|h" => \$help,
           "cron" => \$cron,
           "noninteractive" => \$noninteractive,
           "system" => \$DevelConf::system,
           "info|i" => \$info
          );

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


my $check;
if ($force==1){
    $check=0;
} else {
    $check=1;
}





# --help
if ($help==1) {
   # Scriptname ermitteln
   my @list = split(/\//,$0);
   my $scriptname = pop @list;
   # Befehlsbeschreibung
   print('
sophomorix-quota sets/shows quota of users

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

Getting information about quota:
  -i  / --info
  -i --class class|--students|--teachers|--project pro|--room room
 
Setting quota:
  --force (not checking loginnames)
  --set (set the quota even if it remains the same)
  --sum (Todo)
  --system (untested, on your own risk!)
  --cron (send mail to user, if mailquota is almost used)

Selecting users (Default is: all users)
  -s / --students
  -t / --teachers
  -w / --workstations
  -u user1,user2,...   /  --users user1,user2,...
  -c class1,class2,... /  --class class1,class2,... 
  -p project1,project2,... /  --project project1,project2,... 
  -r room1,room2,...   /  --room room1,room2,...

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


# --info
if ($info==1 and $classes eq "" 
             and $projects eq ""
             and $rooms eq ""
             and $loginname eq ""
             and $student==0
             and $teacher==0
             and $administrator==0
             and $ws==0
   ) {
   my $fs="";
   my $i=0;
   my $j=0;
   my $l=0;
   # Scriptname ermitteln
   my @list = split(/\//,$0);
   my $scriptname = pop @list;
   my @mb_liste=();

   # automatisch oder Liste in sophomorix.conf
   if ($Conf::quota_filesystems[0] eq "auto") {
      # "auto" in sophomorix.conf
      print "The following usrquota filesystems were found by $scriptname\n";
      print "on this server:\n\n";
    } else {
      # Liste in sophomorix.conf angegeben
      print "WARNING: You have manually configured the order of the \n"; 
      print "usrquota filesystems in sophomorix.conf.\n\n";
      print "You should know what you are doing!\n\n";
    }

   # Tatsächlich benutzte Liste ausgeben
   foreach $fs (@quota_fs) {
     $i=$i+1;
     print"  Filesystem $i:    $fs\n";
   }

   print "\n";
   if ($quota_fs_num>1) {
       print "The order of the $quota_fs_num filesystems "; 
       print "is important!\n\n";
   }
   print "I.e.: To set the Standard-Quota for all students on your host,\n";
   print "you must have a line like this in ${DevelConf::config_pfad}/quota.txt:\n\n";
   print "   standard-schueler:";
   
   # Beispiel angeben
   foreach $fs (@quota_fs) {
     $j=$j+1;
     my $mb=30;
     if (not $j==1){
         print "+";
     }
     $mb=$mb*$j;
     print"$mb";
     push (@mb_liste, $mb);
   }

   print "\n\nThis line in quota.txt would set the following usrquota:\n\n";
   
   # Ergebnis angeben
   foreach $fs (@quota_fs) {
     $l=$l+1;
     print"  Filesystem ${l}:    $fs     to $mb_liste[${l}-1] MB\n";
   }
   print "\n";

   print "To see an overview of all quota use:\n";
   foreach $fs (@quota_fs) {
     $l=$l+1;
     print"  repquota -tsv $fs \n";
   }
   print "\n\n";
   exit;
}


# --info --class|....
if ($info==1 and ($classes ne "" or
                  $projects ne "" or
                  $rooms ne "" or
                  $loginname ne "" or
                  $student!=0 or
                  $teacher!=0 or
                  $administrator!=0 or
                  $ws!=0
                 )
   ) {

    print "Reporting quota for some users:\n";
    # userlist according to options
    if ($teacher==1){
        $classes=${DevelConf::teacher}.",".$classes;
    }
    my @userlist=&create_userlist($loginname,$classes,0,$projects,0,$student,
                               $rooms,$ws,$administrator,$check);

    print "                          Block   limits             File \n";
    print "User       BF     used     soft     hard   grace    grace \n";
    print "------------------------------------------------------------\n";
    foreach my $user (@userlist){
	&print_sys_quota($system,$user,\@quota_fs);
    }
    exit;
}


&log_script_start(@arguments);


# check if I have to ...
if($Conf::use_quota ne "yes" and $noninteractive==0){
  # ... abort
  print "\nsophomorix.conf says:  You don't want to use quota.\n\n";
  print "Set  \$use_quota=\"yes\"  in sophomorix.conf to use quota.\n\n";
  print "For more information:  man sophomorix-quota \n\n";
  &log_script_exit("",1,1,0,@arguments);
} elsif ($Conf::use_quota ne "yes" and $noninteractive==1){
  # ... or do nothing
  &titel("sphomorix-quota: Not Setting quota ... \$use_quota=\"no\"");
  &log_script_exit("",1,1,0,@arguments);
}



# --sum
if ($sum==1){
   &Sophomorix::SophomorixPgLdap::fetchquota_sum();
   &log_script_exit("",1,1,0,@arguments);
}



# --cron
if ($cron==1) {
    print "Running with option --cron\n";
    if ($Conf::mailquota_warnings ne "yes"){
        &log_script_exit("quota warnings not enabled",1,1,0,@arguments);
    }
    my @students=&fetchstudents_from_school();
    my @teachers=&fetchusers_from_adminclass(${DevelConf::teacher});
    my @users = (@teachers,@students);

    my $imap=&imap_connect("localhost",${DevelConf::imap_admin});

    foreach my $user (@users){
        print "\nChecking mailquota of $user: \n";
        my @mailquota = &imap_fetch_mailquota($imap,$user,0,0);
        my $send_mail=0;

        if (not defined $mailquota[0]){
            $mailquota[0]="Nouser";
        }
        if (not defined $mailquota[1]){
            $mailquota[1]=0;
        }
        if (not defined $mailquota[2]){
            $mailquota[2]=0;
        }

        # calculate percentage
        if ($mailquota[2]==0){
            # avoid division by zero
            $mailquota[2]=0.0001;
        }

        my $percentage = 100-($mailquota[1]/$mailquota[2])*100;
        $percentage = int($percentage*10)/10;
        # avoid negativ percentages
        if ($percentage<0){
            $percentage=0;
        }

        # calculating kb left
        my $kb_left = ($mailquota[2]-$mailquota[1])*1000;
        $kb_left = int($kb_left);
        if ($kb_left<0){
            $kb_left=0;
        }

	print "   Percentage left  : $percentage \% ";
        if (${Conf::mailquota_warn_percentage} < $percentage){
            print "\n";
        } else {
            $send_mail=1;
            print "(WARNING: only ",
                  "${Conf::mailquota_warn_percentage} \% allowed) \n";
        }

        print "   Mailquota left   : $kb_left kB ";
        if (${Conf::mailquota_warn_kb} < $kb_left){
            print "\n";
        } else {
            $send_mail=1;
            print "(WARNING: only ",
                  "${Conf::mailquota_warn_kb} kB allowed) \n";
        }
        # send mail
        if ($send_mail==1){
            # send a mail to user
            my $mail_message = new Mail::Send;
            $mail_message -> subject('Mailquota warning');  
            $mail_message -> to("${user}".'@'."localhost");  
            my $mail_body = "This is a warning from".
                            " your cyrus mail system:\n\n";
            $mail_body.= "   - Only $kb_left kB (${percentage} %)".
                         " of your mailquota is left. \n";
            $mail_body.= "\nYour Administrator \n";
            my $fh = $mail_message -> open("sendmail");
            print $fh $mail_body;
            $fh -> close();  
        }
    }
    &imap_disconnect($imap);
    #&log_script_exit("",1,1,0,@arguments);
    &log_script_end(@arguments);
}



# connect to imap server
my $imap=&imap_connect("localhost",${DevelConf::imap_admin});


&titel("Calculating usrquota/mailquota ... (this may take a while)");

# 
my %login_type = &login_type();
if($Conf::log_level>=2){
   &print_hash(\%login_type,"","Login:","Type:")
}


my ($ref_db_quota,$ref_db_quota_mail) = &get_db_quota();
my %db_quota = %$ref_db_quota;
my %db_quota_mail = %$ref_db_quota_mail;
if($Conf::log_level>=2){
    &print_hash(\%db_quota,"","Login:","Quota in DB:");
    &print_hash(\%db_quota_mail,"","Login:","MailQuota in DB:");
}


my ($ref_teacher_quota,$ref_teacher_quota_mail) = &get_teacher_quota();
my %teacher_quota = %$ref_teacher_quota;
my %teacher_quota_mail = %$ref_teacher_quota_mail;
if($Conf::log_level>=2){
    &print_hash(\%teacher_quota,"","Teacher:","Quota in DB:");
    &print_hash(\%teacher_quota_mail,"","Teacher:","MailQuota in DB:");
}


my %quota_txt = &get_quota_txt();
if($Conf::log_level>=2){
    &print_hash(\%quota_txt,"","quota.txt:","Quota:");
}
my %mail_quota_txt = &get_mail_quota_txt();
if($Conf::log_level>=2){
    &print_hash(\%mail_quota_txt,"","mailquota.txt:","MailQuota:");
}


my ($ref_class_quota,$ref_class_quota_mail) = &get_class_quota();
my %class_quota = %$ref_class_quota;
my %class_quota_mail = %$ref_class_quota_mail;
if($Conf::log_level>=2){
    &print_hash(\%class_quota,"","Adminclass:","Quota:");
    &print_hash(\%class_quota_mail,"","Adminclass:","MailQuota:");
}


my ($ref_projects_add_quota,$ref_projects_add_quota_mail) 
    = &get_projects_add_quota();
my %projects_add_quota = %$ref_projects_add_quota;
my %projects_add_quota_mail = %$ref_projects_add_quota_mail;
if($Conf::log_level>=2){
    &print_hash(\%projects_add_quota,"","Project:","AddQuota:");
    &print_hash(\%projects_add_quota_mail,"","Project:","AddMailQuota:");
}



# add teachers to classes if option is given
if ($teacher==1){
    if ($classes eq ""){
        $classes=${DevelConf::teacher};
    } else {
        $classes=$classes.",".${DevelConf::teacher};
    }
}



# create the list of users from options
my @userlist=();
&titel("Creating a userlist from options ...");
if ($loginname eq ""
      and $classes eq ""
      and $projects eq ""
      and $student==0
      and $rooms eq ""
      and $ws==0
      and $administrator==0){
    # all users
    @userlist=&create_userlist("","${DevelConf::teacher}",0,"",0,1,"",1,1,$check);
} else {
    # userlist according to options
    @userlist=&create_userlist($loginname,$classes,0,$projects,0,$student,
                               $rooms,$ws,$administrator,$check);
}


if ($#userlist+1==0 and $sum==0){
    print "INFO: No valid users given\n\n";
}



&titel("Searching for users with changed quota/mailquota...");
if ($set==1){
    &titel("Setting Quota for all users in the userlist ...");
    # setting quota for every user
    my $count=0;
    my $all=$#userlist+1;
    foreach my $user (@userlist){
        $count++;
        my ($new_quota,$mailquota)=&get_quota($user);

        ##### quota
        if (not defined $new_quota){
            print "NOT setting quota (No quota found for $user).\n";
        } else {
            my @q_list = &check_quotastring($quota_fs_num,$new_quota);
            if ($q_list[0]!=-3 and $q_list[1] ne "quota"){
                if($Conf::log_level==1){
                    print "Setting quota of user $user ($count/$all) to @q_list:\n";
                }
	        &set_quota($system,$user,\@quota_fs,\@q_list);
            } else {
	        print "ERROR: $new_quota for $user is not correct, skipping ...\n";
            }
        }

        ##### mailquota
        # check the new quotastring ???? must be integer
        if (not defined $mailquota){
            print "NOT setting mailquota (No mailquota found for $user).\n";
        } else {
            &imap_set_mailquota($imap,$user,$mailquota);        
            # update the ldap database with new mailquota
            &update_user_db_entry($user,"MailQuota=$mailquota");
        }
    }
} else {
   &titel("Setting changed Quota for users in the userlist ...");
   &set_quota_if_needed();
}


&imap_disconnect($imap);

&log_script_end(@arguments);







############################################################
# subs
############################################################

# set the quota fot that user
# system=0 -> use perl modul, system=1 -> use setquota 
sub set_quota {
   my ($system,$user,$quota_fs, $q_list)=@_;
   my $quota="";
   my $fs="";
   my $j=0;
   my $uid=-1;
   my $quota_befehl="";
   my ($q_opt1,$q_opt3,$q_opt4)=("","","");
   # for every fs in
   for ($j=0; $j < @$quota_fs; $j++){

      # Aus der Listenreferenz das j-te Element herausnehmen
      $quota = $q_list->[$j];
      $fs = $quota_fs->[$j];

      # ??? Leerzeichen aus quota entfernen und return abschneiden
      chomp($quota);
      $quota=~s/ //g;

      if ($quota eq ""){
          next;
      }

      # Softlimit ca. 20% unter Hardlimit
      $q_opt1=$quota-int($quota/5);
      # 80% des Hardlimits
      $q_opt3=80*$quota;
      # Wenn Dateien durchschnittlich unter 10kB/Datei gibts Probleme
      $q_opt4=100*$quota;

      # user-ID ermitteln
      if ($login_type{$user} eq "passwd"){
          # sysuser
          ($a,$a,$uid)=getpwnam("$user");
      } else {
          # sophomorix user
          ($a,$a,$a,$a,$uid)=&fetchdata_from_account("$user");
      }
      # Ausgeben der ermittelten werte
      if($Conf::log_level>=3){
         print("  Quotateilstring $j:  ${quota}\n");
         print("    Device:             ${fs}\n");
         print("    User:               ${user}\n");
         print("    UserID:             $uid\n");
         print("    Block-Softlimit:    ${q_opt1}000  \n");
         print("    Block-Hardlimit:    ${quota}000  \n");
         print("    Inode-Softlimit:    ${q_opt3}     \n");
         print("    Inode-Hardlimit:    ${q_opt4}     \n");
      }
      # Mit setquota die Quota der user tatsächlich anpassen
      if (not $DevelConf::system==1){
         # Quota-Modul benutzen
         if(not $DevelConf::testen==1) {
            # do it
            Quota::setqlim($fs,$uid,"${q_opt1}000","${quota}000",$q_opt3,$q_opt4);
	 } else {
            # test
            print "  Test (quota are not set!): \n";
         }
            print "  setting quota ($fs,uid $uid): "; 
            print "${q_opt1}M ${quota}M $q_opt3 $q_opt4 \n";
      } else {
         # Systembefehl benutzten
         $quota_befehl="setquota -u ${user} ${q_opt1}000 ".
                       "${quota}000 ${q_opt3} ${q_opt4} ${fs}";
         if(not $DevelConf::testen==1) {
            # do it
            system("${quota_befehl}")
         } else {
            # test
            print "  Test (quota are not set!): \n";
         }
         print("   Quota command: ${quota_befehl}","\n");
      } 
   }
   # was gemacht wurde zusammensetzen
   my $quotastring=join "+", @$q_list;

   # skip updating db, when user is administrator, ...
   if ($login_type{$user} eq "passwd"
       #or $user eq "administrator"
       #or $user eq "pgmadmin"
       #or $user eq "wwwadmin"
       or $user eq "www-data"
      ){
      print "NOT updating db ($user is not a sophomorix user)\n";
   } else {
      &update_user_db_entry($user,"Quota=$quotastring");
   }
}






# check for which users quota must be updated in the database. 
# if yes: call set_quota for each user
sub set_quota_if_needed {
    my $new_quota="";
    my $mailquota;
    my $count=0;
    my $all=$#userlist+1;
    foreach my $login (@userlist){
        $count++;
        my $type=$login_type{$login};
        if (not defined $type){
	    $type="none";
        }

        print "Checking user $login ($count/$all):\n";

        if($Conf::log_level>=2){
            print "  $login is type $type\n";
        }
        if ($type eq "domcomp"){
            # not setting quota for machine accounts ($)
            print "   Not setting quota for $login ($type)\n";
	    next;
        }
        ($new_quota,$mailquota)=&get_quota($login);

        ##### quota
        # set quota to empty if not defined
	if (not defined $db_quota{$login}){
	    $db_quota{$login}="";
	}
	if (not defined $new_quota){
            # do nothing
        } elsif ($new_quota eq $db_quota{$login}){
            # do nothing, quota seems up to date
            if($Conf::log_level>=2){
	        print "  * Quota of $login seems up to date ($new_quota in MB)\n";
            }
        } else {
           if($Conf::log_level>=2){
               print "  New quota: $new_quota \n";
               print "  db  quota: $db_quota{$login}\n";
           }
           # check the new quotastring
           my @q_list = &check_quotastring($quota_fs_num,$new_quota);

           if ($q_list[0]!=-3 and $q_list[1] ne "quota"){
	       &set_quota(0,$login,\@quota_fs,\@q_list);
           } else {
	       print "ERROR: $new_quota for $login is not correct, skipping ...\n";
           }
        }


        ##### mailquota
        # set quota to empty if not defined
	if (not defined $db_quota_mail{$login}){
	    $db_quota_mail{$login}="";
	}
        if (not defined $mailquota){
            # do nothing
        } elsif ($mailquota eq $db_quota_mail{$login}){
            # do nothing, mailquota seems up to date
            if($Conf::log_level>=2){
	        print "  * Mailquota of $login seems up to date ($mailquota MB)\n";
	    }
        } else {
           if($Conf::log_level>=2){
               print "  New mailquota: $mailquota \n";
               print "  db  mailquota: $db_quota_mail{$login}\n";
           }
           # check the new quotastring ???? must be integer
           &imap_set_mailquota($imap,$login,$mailquota);
           # update the ldap database with new mailquota
           &update_user_db_entry($login,"MailQuota=$mailquota");
        }
    }
}





# create hash with teacher_quota
sub get_teacher_quota {
   my $login="";
   my $quotastring="";
   my $mailquota="";
   my %teacher_quota=();
   my %teacher_quota_mail=();
   if (-e "${DevelConf::users_pfad}/lehrer.txt"){
       open(TEACHER,"${DevelConf::users_pfad}/lehrer.txt") || die "Fehler: $!";
       while(<TEACHER>){
          chomp();
          s/\s//g; # Whitespace Entfernen
          if ($_ eq ""){next;} # Wenn Zeile Leer, dann aussteigen
          if(/^\#/){next;} # Bei Kommentarzeichen aussteigen
          ($a,$a,$a,$a,$login,$a,$a,$quotastring,$mailquota)=split(/;/);
          # Wenn Quotaangabe vorhanden, dann benutzen
          if($quotastring ne "quota"){
             $teacher_quota{$login}=$quotastring;
          }
          if($mailquota ne "mailquota"){
             $teacher_quota_mail{$login}=$mailquota;
          }
       }
       close(TEACHER);
   }
   return (\%teacher_quota,\%teacher_quota_mail);
}




# hash: login -> type(student,teacher,workstation)
sub login_type {
    my %login_type=();
    my %login_type_new=();
    my $login="";
    my $home="";
    my $type="";

    # others
    my $dbh=&db_connect();

    # select the columns that i need
    my $sth= $dbh->prepare( "SELECT uid,homedirectory,gecos,gid
                            FROM userdata 
                           " );
    $sth->execute();
    my $array_ref = $sth->fetchall_arrayref();
    foreach my $row (@$array_ref){
       # split the array, to give better names
       my ($uid,$home,$gecos,$group)=@$row;
       if (defined $home){
          if ($home=~/^$DevelConf::homedir_pupil\//){
              $type="student";
          } elsif ($group  eq ${DevelConf::teacher}){
	      $type="teacher";
          } elsif ($home=~/^$DevelConf::homedir_ws\//){
              $type="examaccount";
          } elsif ($home=~/\/dev\/null/){
              $type="domcomp";
          } elsif ($home=~/^$DevelConf::homedir_all_admins\//){
              $type="administrator";
          } else {
              $type="none";
          }
    }
       $login_type{$uid}=$type;
    }
    &db_disconnect($dbh);

    # fetching sysusers
    if (-e "/etc/passwd"){
        open(PASS, "/etc/passwd");
        while(<PASS>) {
            my ($login)=split(/:/);
            $login_type{$login}="passwd";
         }
        close(PASS);
    }
    return %login_type;
}




# calculates the quota of the user login
sub get_quota{
    my ($login) = @_;
    my $quotastring="";
    my $mailquota=0; 

    if (not exists $login_type{$login}){
        print "WARNING: Could not determine type of user ",
              "$login (I guess user is nonexisting)\n";
        $quotastring=undef;
        $mailquota=undef;
        return ($quotastring,$mailquota);
    }

    my @groups = &pg_get_group_list($login);
    my $pri_group=shift(@groups);
    if (not defined $pri_group){
        # avoid undef
        $pri_group="";
    }
    if($Conf::log_level>=2){
        print "  Primary Group:    $pri_group \n";
        print "  Secondary Groups: @groups \n";
    }

    ##### quota
    if (exists $quota_txt{$login}){
        # look in quota.txt
        $quotastring=$quota_txt{$login};
	print "   Found quota.txt quota: $quotastring\n" if($Conf::log_level>=2);
    } elsif (exists $teacher_quota{$login}){
        # look in teacher.txt
        $quotastring=$teacher_quota{$login};
	print "   Found lehrer.txt quota: $quotastring\n" if($Conf::log_level>=2);
    } elsif (exists $class_quota{$pri_group}){
        # look in class
        $quotastring=$class_quota{$pri_group};
	print "   Found quota for class $pri_group: $quotastring\n" 
        if($Conf::log_level>=2);
    } else {
        # take standard values
        if ($login_type{$login} eq "student"){
	    $quotastring=$quota_txt{"standard-schueler"};
        } elsif ($login_type{$login} eq "teacher"){
	    $quotastring=$quota_txt{"standard-lehrer"};
        } elsif ($login_type{$login} eq "examaccount"){
	    $quotastring=$quota_txt{"standard-workstations"};
        } elsif ($login_type{$login} eq "none"){
            # must be user in attic,
            # keep quota from db
	    $quotastring=$db_quota{$login};
        } else {
            print "WARNING: Could not find any quota for user $login.\n";
            $quotastring=undef;
        }
    }
    foreach my $group (@groups){
        print "   Checking for additional quota of ",
              "project $group \n" if($Conf::log_level>=2);
        if (exists $projects_add_quota{$group}){
        print "   Adding $projects_add_quota{$group}\n" if($Conf::log_level>=2);
        $quotastring = &quota_addition($projects_add_quota{$group},$quotastring);
        }
    }


    #####  mailquota
    if (exists $mail_quota_txt{$login}){
        # look in mailquota.txt
        $mailquota=$mail_quota_txt{$login};
	print "   Found mailquota.txt mailquota: $mailquota\n" if($Conf::log_level>=2);
    } elsif (exists $teacher_quota_mail{$login}){
        # look in teacher.txt
        $mailquota=$teacher_quota_mail{$login};
	print "   Found lehrer.txt mailquota: $mailquota\n" if($Conf::log_level>=2);
    } elsif (exists $class_quota_mail{$pri_group} ){
        # look in class
        $mailquota=$class_quota_mail{$pri_group};
	print "   Found mailquota for class $pri_group: $mailquota\n" 
        if($Conf::log_level>=2);
    } else {
        # take standard values
        if ($login_type{$login} eq "student"){
	    $mailquota=$mail_quota_txt{"standard-schueler"};
        } elsif ($login_type{$login} eq "teacher"){
	    $mailquota=$mail_quota_txt{"standard-lehrer"};
        } elsif ($login_type{$login} eq "examaccount"){
	    $mailquota=$mail_quota_txt{"standard-workstations"};
        } elsif ($login_type{$login} eq "none"){
            # must be user in attic,
            # keep mailquota from db
	    $mailquota=$db_quota_mail{$login};
        } else {
            print "WARNING: Could not find any mailquota for user $login.\n";
            $mailquota=undef;
        }
    }
    foreach my $group (@groups){
        print "   Checking for additional mailquota of ",
              "project $group \n" if($Conf::log_level>=2);
        if (exists $projects_add_quota_mail{$group}){
        print "   Adding $projects_add_quota_mail{$group}\n" if($Conf::log_level>=2);
        $mailquota = $mailquota+$projects_add_quota_mail{$group};
        }
    }
    return ($quotastring,$mailquota);
}





# hash login -> additional quota
sub get_projects_add_quota {
    my %projects_add_quota=();
    my %projects_add_quota_mail=();
    my $dbh=&db_connect();
    my $sth;
    $sth = $dbh->prepare("SELECT gid,addquota,addmailquota FROM projectdata");
    $sth->execute();
    while (my $row = $sth->fetchrow_hashref) {
       if(not defined $row->{'addquota'}){
           next;
       } elsif($row->{'addquota'} ne "quota" and $row->{'addquota'} ne "0"){
          $projects_add_quota{ $row->{'gid'} } = $row->{'addquota'}; 
       }
       if(not defined $row->{'addmailquota'}){
           next;
       } elsif($row->{'addmailquota'} ne "quota" and $row->{'addmailquota'} ne "0"){
          # ????????????????????
          $projects_add_quota_mail{ $row->{'gid'} } = $row->{'addmailquota'}; 
       }
    }
    $sth->finish();
    &db_disconnect($dbh);
    return (\%projects_add_quota,\%projects_add_quota_mail);
}





# hash: class -> quota 
sub get_class_quota {
    my $class="";
    my %class_quota=();
    my %class_quota_mail=();
    my $dbh=&db_connect();
    my $sth;
    $sth = $dbh->prepare("SELECT gid,quota,mailquota FROM classdata");
    $sth->execute();
    while (my $row = $sth->fetchrow_hashref) {
       if(not defined $row->{'quota'}){
           next;
       } elsif($row->{'quota'} ne "quota"){
          $class_quota{ $row->{'gid'} } = $row->{'quota'}; 
       }
       if(not defined $row->{'mailquota'}){
           next;
       } elsif($row->{'mailquota'}!=-1){
          $class_quota_mail{ $row->{'gid'} } = $row->{'mailquota'}; 
       }
    }
    $sth->finish();
    &db_disconnect($dbh);
    return (\%class_quota,\%class_quota_mail);
}





# hash: login -> quota  (login can be also: standard-*) 
sub get_quota_txt {
   my %quota_txt=();
   my $user="";
   my $quotastring="",
   open(QUOTATXT,"${DevelConf::config_pfad}/quota.txt") || die "Fehler: $!";
   while(<QUOTATXT>){
      chomp();
      s/\s//g; # Whitespace Entfernen
      if ($_ eq ""){next;} # Wenn Zeile Leer, dann aussteigen
      if(/^\#/){next;} # Bei Kommentarzeichen aussteigen
      # user von sollquota splitten
      ($user,$quotastring)=split(/:/);
      if (exists $login_type{$user}){
          if ($login_type{$user} eq "teacher"){
              print "WARNING: User $user in quota.txt is a teacher.\n";
              print "         Use lehrer.txt for teacher quota. Skipping ...\n";
          } else {
              $quota_txt{$user}=$quotastring;
          }
      } else {
          $quota_txt{$user}=$quotastring;
      }
   }
   close(QUOTATXT);
   # Rückgabe-Hash enthält standard-quota UND Einzel-Quota
   return %quota_txt;
}



# hash: login -> quota  (login can be also: standard-*) 
sub get_mail_quota_txt {
   my %mail_quota_txt=();
   my $user="";
   my $quotastring="",
   open(MAILQUOTATXT,"${DevelConf::config_pfad}/mailquota.txt") || die "Fehler: $!";
   while(<MAILQUOTATXT>){
      chomp();
      s/\s//g; # Whitespace Entfernen
      if ($_ eq ""){next;} # Wenn Zeile Leer, dann aussteigen
      if(/^\#/){next;} # Bei Kommentarzeichen aussteigen
      # user von sollquota splitten
      ($user,$quotastring)=split(/:/);
      if (exists $login_type{$user}){
          if ($login_type{$user} eq "teacher"){
              print "WARNING: User $user in mailquota.txt is a teacher.\n";
              print "         Use lehrer.txt for teacher quota. Skipping ...\n";
          } else {
              $mail_quota_txt{$user}=$quotastring;
          }
      } else {
          $mail_quota_txt{$user}=$quotastring;
      }
   }
   close(MAILQUOTATXT);
   # Rückgabe-Hash enthält standard-quota UND Einzel-Quota
   return %mail_quota_txt;
}




# hash: login -> quotastring in the sophomorix database(user_db)
sub get_db_quota {
    my $login="";
    my $quotastring="";
    my $sophomorixstatus="";
    my %db_quota=();
    my %db_quota_mail=();
#    $db_quota{"admin"}=0;
#    $db_quota_mail{"admin"}=0;

    my $dbh=&db_connect();

    # select the columns that i need
    my $sth= $dbh->prepare( "SELECT uid,quota,mailquota,sophomorixstatus 
                             FROM userdata" );
    $sth->execute();

    my $array_ref = $sth->fetchall_arrayref();

    foreach my $row (@$array_ref){
       my ($login,$quotastring,$mailquota,$sophomorixstatus) = @$row;
       if (defined $sophomorixstatus){
          $db_quota{$login}=$quotastring;
          $db_quota_mail{$login}=$mailquota;
       } else {
          # not a sophomorix user
       }
    }
    &db_disconnect($dbh);
    return (\%db_quota,\%db_quota_mail);
}

# fetches and prints system quota of a user
sub print_sys_quota {
   my ($system,$user,$quota_fs) = @_;
   my $user_display=$user;
   # sophomorix user
   my $uid=-1;
   ($a,$a,$a,$a,$uid)=&fetchdata_from_account("$user");
   my $fs="";
   my $j=0;
   my $quota="";


   # for every fs in
   for ($j=0; $j < @$quota_fs; $j++){
      # Aus der Listenreferenz das j-te Element herausnehmen
      $fs = $quota_fs->[$j];
      my ($b_used,$b_soft,$b_hard,$b_grace, 
          $i_used,$i_soft,$i_hard,$i_grace) = Quota::query($fs, $uid);

      my $b="-";
      my $f="-";

      if ($j!=0){
          $user_display="";
      }

      if ($b_grace==0){
          $b_grace=0;
      } else {
          $b_grace=$b_grace-$epoche_jetzt;
          if ($b_grace<0){
              $b_grace="none";
          } else {
              $b_grace=int($b_grace/86400);
              $b_grace=$b_grace."days";
          }
      }

      if ($i_grace>1000000){
          # simplified
          $i_grace="none";
      }

      if ($b_used>$b_soft){
          $b="+";
      }

      if ($i_used>$i_soft){
          $f="+";
      }

      my $bf=$b.$f;
      $b_used=&format_quota($b_used); 
      $b_soft=&format_quota($b_soft); 
      $b_hard=&format_quota($b_hard); 

      printf "%-11s% 2s% 9s% 9s% 9s% 8s% 9s\n",
             $user_display,$bf,$b_used,$b_soft,$b_hard,$b_grace,$i_grace;
    }
}


sub format_quota {
    my ($quota) = @_;
    if ($quota>=1024){
        $quota=$quota/102.4;
        $quota=int($quota);
        $quota=$quota/10;
        $quota=$quota."M";
    }
    return $quota;
}

# EOF
