#!/usr/bin/perl # # quotacheck.pl # # Written by Mark Borrie, ITS, University of Otago # Dunedin, New Zealand # mark at gandalf.otago.ac.nz # # Version : March 1 1999. # # Time zone and message priority fixes 20030603 by # Karsten Behrens # # Additional logfile to be used as Postfix regexp table (to reject # mails to full mailboxes) and some indention added 20030720 by # Karsten Behrens # # 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/lib/cyrus/quota/quotas.tmp"; # The program that generates the quota data $doquota="/usr/lib/cyrus/bin/quota"; # Log file of all the mailboxes we are interested in $log="/usr/lib/cyrus/quota/quota.log"; # Log file of all the full mailboxes found (kbe) $fulllog="/etc/postfix/mailboxfull"; $rejecttext="554 User mailbox is over quota"; # The cyrus delivery program $mail="/usr/lib/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/lib/cyrus/quota/mailwarn.message"; $mailfull="/usr/lib/cyrus/quota/mailfull.message"; # Store the accounts that have been sent mail in a data file (we send e-mail to these accounts about full or almost full mailboxes) $quotafull = "/usr/lib/cyrus/quota/quotafull.dat"; # Store the clients who are using more than the std quota $accountlog="/usr/lib/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'} : 'CEST' ) : ''; $TZ = `date "+%Z"`; print "Timezone is set to : ",$TZ,"\n" if $debug; open(LOGFILE,">>".$log); open(FULLLOG,">".$fulllog); # (kbe) # Preload the previous full account data # The format of the file is a space separated field file with # # 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() { 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 %H:%M:%S %z (%Z)",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 < Subject: Important message - you mailbox is almost full Date: $date Importance: high X-Priority: 1 ENDOFTEXT open (MAILMESSAGE,"<".$mailwarn) or print "Could not open $mailwarn\n"; # Read the main message which is non variable text while () { print TMPFILE $_; } close (MAILMESSAGE); close (TMPFILE); open (TMPFILE,">".$mailfull.".tmp"); print TMPFILE < Subject: Important message - you mailbox is full Date: $date Importance: high X-Priority: 1 ENDOFTEXT open (MAILMESSAGE,"<".$mailfull) or print "Could not open $mailfull\n"; # Read the main message which is non variable text while () { 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); # original open(ACCOUNTING,">>".$accountlog); used for listing the accounts with more quota then the default # Discard the first line of the quota file $firstline = ; while () { # 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) > 5) { $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\@mydomain\.ac\.il < $mailfull.tmp"); } $moduser=$user; # (kbe) $moduser=~s/\./[@.]/g; # (kbe) print FULLLOG "/$moduser/ $rejecttext\n"; # (kbe) } elsif ($percent >= 90 && !$bbs) { if (($offset - $lastwarnoffset) > 3) { $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\@mydomain\.ac\.il -s \"Quota warn for $user\" < $mailwarn.tmp"); } } if (($quota > 102400)) { # check the Kb non std. accounts have above the default quota $chargable=$quota - 102400; print ACCOUNTING "$user, $chargable, $date\n"; } } close(LOGFILE); close(FULLLOG); system("postmap $fulllog"); 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;