#!/usr/bin/perl
#
# quotacheck.pl
# 
# Written by Mark Borrie, ITS, University of Otago
#            Dunedin, New Zealand
#            mark@gandalf.otago.ac.nz
#
# Version : March 1 1999.
# 
# A utility to check cyrus quotas and mail users who have used more than
# 90% of their quota. In addition users who have used all of their quota
# are also notified.
#
# Users who are over 90% are warned every 3 days, while user with full
# quotas are warned every five days.
#
# By using the delivery program directly we can deliver mail directly to
# the users mailbox even when the mailbox is full.
# 
# In addition, users who have orgainised extended quotas have their extra
# space accounted for.  At Otago we give users 5Mb of quota for standard
# use.  Users can contract to pay for additional space.  We record that 
# additional space usage. 
#

# DECLARATIONS

# Some debugging things
$debug=0;
$verbose=0;
$dohash=0;
$threshold=100;
$total=0;

#   A temp file with the quota data
$quotadata="/usr/cyrus/quota/quotas.tmp";
#   The program that generates the quota data
$doquota="/usr/cyrus/bin/quota";
#   Log file of all the mailboxes we are interested in
$log="/usr/cyrus/quota/quota.log";
#   The cyrus delivery program
$mail="/usr/cyrus/bin/deliver";
#   The 2 files that contain the email message to the clients.
#   mailwarn is sent to users whose quota is nearly full and mailfull
#   to users with a full mailbox.
$mailwarn="/usr/cyrus/quota/mailwarn.message";
$mailfull="/usr/cyrus/quota/mailfull.message";
#   Store the accounts that have been sent mail in a data file
$quotafull = "/usr/cyrus/quota/quotafull.dat";
#   Store the clients who are using more than the std quota
$accountlog="/usr/cyrus/quota/account.log";


# INCLUDES

# we need this to do time things. If the ENVIRONMENT variable TZ is NOT
# set this doesn't work too well.
require "ctime.pl";
#require "ptime.pl";
use POSIX qw(strftime);

# better actually check if TZ was set before we go off and do things
# I got this from someone else so I'm not sure what happens if TZ is not
# set. The following line will need changed elsewhere.
$TZ = defined($ENV{'TZ'}) ? ( $ENV{'TZ'} ? $ENV{'TZ'} : 'NZDT' ) : '';
print "Timezone is set to : ",$TZ,"\n" if $debug;

open(LOGFILE,">>".$log);


# Preload the previous full account data 
# The format of the file is a space separated field file with
# <lastwarningdate> <lastfulldate> <popid>
# lastwarningdate and lastfulldate are set to zero if the other
# value is non-zero.
# the values lastwarningdate and lastfulldate are more or less the 
# number of days since Jan 1 1999.

print "Preloading previous full account data," if $debug;
$counter=0;
open(TABLE,"<".$quotafull);
while(<TABLE>) {
    chop;
    @fields = split(/[ \t]+/,$_);# white space separated fields
    $lastwarndate{$fields[2]} = $fields[0];
    $lastfulldate{$fields[2]} = $fields[1];
    $counter++;
}
close(TABLE);

print "Read $counter records from previous data\n" if $debug;


# MAIN  LOOP

# This is not leap year compliant. Jan 1 the year following a leap year
# will have the same index as Dec 31 (the day before). This will simply
# increase the message sending interval by one day arround this time.

$year=strftime("%Y",localtime);
$day=strftime("%j",localtime);
$offset= (($year-1999)*365) + $day; # days since 1/1/99,approx.
$date = strftime("%a, %d %b %y %r",localtime);


# Create the 2 warning message files with appropriate dates
# These can then be delivered directly to the cyrus mailbox
# The From: line will need customizing.

open (TMPFILE,">".$mailwarn.".tmp");
print TMPFILE <<ENDOFTEXT;
From:     "Postmaster" <postmaster\@domain.tld>
Subject:  Wichtige Meldung - eMail Quota Warnung
Date:     $date
Priority: urgent

ENDOFTEXT

open (MAILMESSAGE,"<".$mailwarn) or print "Could not open $mailwarn\n";

  # Read the main message which is non variable text
  while (<MAILMESSAGE>) {
    print TMPFILE $_;
  }
close (MAILMESSAGE);
close (TMPFILE);


open (TMPFILE,">".$mailfull.".tmp");
print TMPFILE <<ENDOFTEXT;
From:     "Postmaster" <postmaster\@domain.tld>
Subject:  Wichtige Meldung - eMail Quota Limit ueberschritten
Date:     $date
Priority: urgent

ENDOFTEXT

open (MAILMESSAGE,"<".$mailfull) or print "Could not open $mailfull\n";

  # Read the main message which is non variable text
  while (<MAILMESSAGE>) {
    print TMPFILE $_;
  }
close (MAILMESSAGE);
close (TMPFILE);

# Now change the date variable to something else
#$date = strftime("%d %b %y",localtime);
$date = &'ctime(time);
print "Entering main processing loop" if $debug;

# Generate quota file - remember to remove first line.
system("su - cyrus -c \"$doquota > $quotadata\"");

open(QUOTAFILE,"<".$quotadata); 
open(ACCOUNTING,">>".$accountlog);

# Discard the first line of the quota file
$firstline = <QUOTAFILE>;

while (<QUOTAFILE>) {
#    print "Main loop\n" if $debug;
    if ($dohash) {
	$total++;
	if ( $cntr++ > $threshold ) {
	    $cntr=0;
	    print STDERR "Processed ", $total," records\n" if $verbose;
	}

    }	

	
# split input line into useful fields
        ($quota,$percent,$kbytes,$tmp)=split(" ",$_);
	$user=$bbs="";
	print "tmp=$tmp\n"if $debug;
	$user=$tmp if $tmp=~/^user\//i;
	$bbs=$tmp if $tmp=~/^public\//i;
	$user=~s/^\S*\///;
	$bbs=~s/^\S*\///;
#	$user=substr($tmp,5);
	print "user=$user, bbs=$bbs\n" if $debug;
        $lastfulloffset=$lastfulldate{$user};
        $lastwarnoffset=$lastwarndate{$user};
        if (!defined($lastfulloffset) ) {
          $lastfulloffset=0;
        }
        if (!defined($lastwarnoffset) ) {
          $lastwarnoffset=0;
        }

        if ($percent >= 100 && !$bbs)  {
          if (($offset - $lastfulloffset) > 0) {
	    $lastwarndate{$user}=0;
            $lastfulldate{$user}=$offset;
            print LOGFILE "$user quota is full : $date\n";
            system("su - cyrus -c \"$mail -e -q $user < $mailfull.tmp\"");
	    system("mail -s \"Quota full for $user\" postmaster\@domain\.tld < $mailfull.tmp");
          }
        } elsif  ($percent >= 90 && !$bbs) {
          if (($offset - $lastwarnoffset) > 0) {
	    $lastfulldate{$user}=0;
            $lastwarndate{$user}=$offset;
            print LOGFILE "$user quota is nearly full : $date\n";
            system("su - cyrus -c \"$mail -e -q $user < $mailwarn.tmp\"");
	    system("mail postmaster\@domain\.tld -s \"Quota warn for $user\" < $mailwarn.tmp");
 
          }
         }
        if (($quota > 5120) and ($kbytes > 5120)) {
          $chargable=$kbytes - 5120;
          print ACCOUNTING "$user, $chargable, $date\n";
        }

}

close(LOGFILE);
close(ACCOUNTING);

# Write out the quota full data again
open(TABLE,">".$quotafull);
$counter=0;
foreach ( keys %lastwarndate ) {
    print TABLE "$lastwarndate{$_} $lastfulldate{$_} $_\n";
$counter++;
}
close(TABLE);

print "Wrote  $counter records to login data\n" if $debug;

