###########################################################################
# Imail version 6.X lacks the ability to issue warnings to users
# approaching the mailbox size limit.
# This perl script scans the registry for each domain and checks each user's
# mailbox size against MaxSize entered for the user in the registry.
# If the user has 0 entered as MaxSize then the domain's MaxSize entry is used.
# If the mailbox is over 90% capacity it emails a caution to the user
# and logs it. If the mailbox is over 95% capacity it emails a warning
# to the user and logs it. If the user's mailbox is over the limit it just logs it. 
# This window of warning can be adjusted by changing the line 
# $notify_window = .10. The resulting log file is then 
# emailed to the postmaster account. Sizes are reported in bytes.
#
# To run the script every 24 hours, schedule with the command
# "AT 2:00 /interactive /every:Su,M,T,W,Th,F,S C:\BIN\LIMIT.PL"
#
# Written by Joel Morgan jpmorgan@bigfoot.com
###########################################################################

###########################################################################
# Subroutine to return directory size. Contributed by David Gregg dgregg@dgsoft.com
# and modified for recursion and wildcards by Joel Morgan jpmorgan@bigfoot.com.
###########################################################################

sub dir_size { 
local($l_physicaldirectory, $l_searchpattern) = @_;
local(@l_allfiles, $l_dirsize, $l_filename); 
local($l_fdev, $l_fino, $l_fmode, $l_fnlink, $l_fuid, $l_fgid, $l_frdev, $l_fsize, $l_fatime, $l_fmtime, $l_fctime, $l_fblksize, $l_fblocks); 
$l_totsize = 0; 

use File::Find;
find sub { push @l_allfiles, $File::Find::name if /$l_searchpattern/ }, $l_physicaldirectory; 

foreach $l_filename (@l_allfiles)
	{
	#print $l_filename; 
	#print "\n"; 
	($l_fdev, $l_fino, $l_fmode, $l_fnlink, $l_fuid, $l_fgid, $l_frdev, $l_fsize, $l_fatime, $l_fmtime, $l_fctime, $l_fblksize, $l_fblocks) = stat($l_filename); 
	$l_dirsize += $l_fsize; 
	}
return $l_dirsize; 
}

###########################################################################
# Original version of dir_size to get the size of directory tree under Windows
# Takes the dir of directory with the wide (/w) option to get a shorter list 
# and /s option to get all sub dirs
###########################################################################   
#sub dir_size {
#my $test_dir = $_[0];
#@res = `dir /s/w "$test_dir"`;
## The second to last line has the number of files and                     
## total size of the the directory
#my $LastLine = $res[-2];
## Isolate directory size number
#@res = split(/ /,$LastLine);
##remove commas;
#$_ = $res[-2];
#tr/0-9//cd;
#$res[-2] = $_;
#return $res[-2];
#}

###########################################################################
# Subroutine contributed by David Gregg dgregg@dgsoft.com to return a list of subdirectories.
###########################################################################

sub dir_list {
local($l_physicaldirectory) = @_;
local(@l_alldirs, $l_dir);
chdir("$l_physicaldirectory");
opendir(THISDIR, ".");
@l_alldirs = grep(-d, grep(!/^\.\.?$/ , readdir(THISDIR)));
closedir(THISDIR);
@l_alldirs = sort(@l_alldirs);
return @l_alldirs;
}

###########################################################################
# Subroutine to get registry value of path and key passed to it
###########################################################################

sub get_key_value {
local($hkey);
local($myhash);
$param = $_[0];
$param2 = $_[1];
#$HKEY_LOCAL_MACHINE->Open($param, $hkey) || die $!;
if ($HKEY_LOCAL_MACHINE->Open($param, $hkey))
{
$hkey->GetValues($myhash) || die $!;
return $myhash->{$param2}[2];
}
}

#Main Program
use Win32::Registry;

my $Domain_key = "Software\\Ipswitch\\IMail\\Domains";
my ($hkey, @key_list, $key);
$admin_address = 'postmaster@' . get_key_value('SOFTWARE\Ipswitch\IMail\Global', 'HostName');
$imail = get_key_value('SOFTWARE\Ipswitch\IMail\Global', 'TopDir');
$imail1 = $imail . "\\imail1.exe";
$temp_msg = $imail . "\\outmail$$.txt";
$mailbox = $imail . "\\mailbox$$.txt";
$subject = 'Mailbox Size Report!';
open (LOGFILE, ">$mailbox") || die "open postmail or sendmail";
print "Mailbox size report generated on " . localtime() . "\n";
print LOGFILE "Mailbox size report generated on " . localtime() . "\n";
print "\n";
print LOGFILE "\n";

$HKEY_LOCAL_MACHINE->Open($Domain_key,$hkey)|| die $!;
$hkey->GetKeys(\@key_list);
foreach $key (@key_list)
	{	
	#Need to check for MaxSize key or TopDir key to aviod "file not found" and unnecessary loop for "$virtual001"
	
	$domain_max_dir_size = get_key_value($Domain_key . "\\" . $key , 'MaxSize');
	#
	$users_dir_path = get_key_value($Domain_key . "\\" . $key , 'TopDir') . "\\users";
	# Check for TopDir key if the key is not found $users_dir_path will be \users
	if ($users_dir_path ne "\\users")
		{
		print "Processing domain " . $key . "\n";
		print LOGFILE "Processing domain " . $key . "\n";
		print "Default Mailbox limit " . $domain_max_dir_size . " bytes" . "\n";
		print LOGFILE "Default Mailbox limit " . $domain_max_dir_size . "\n";
		print "User mailboxes located in " . $users_dir_path . "\n";
		print LOGFILE "User mailboxes located in " . $users_dir_path . "\n";
		print "\n";
		print LOGFILE "\n";
		#chdir($users_dir_path);
		@dirs = dir_list($users_dir_path);
		foreach $dir (@dirs)
			{
			#print "Processing user " . $dir . "\n";
			#print "Current mailbox size " . dir_size($users_dir_path . "\\" . $dir, '*.mbx') . " bytes" . "\n";
			
			#Generates no such file or directory if reg key doesn't exist.
			#Check for key. If it doesn't exist, set $user_max_dir_size to $domain_max_dir_size

			$user_max_dir_size = get_key_value($Domain_key . "\\" . $key . "\\Users\\" . $dir, 'MaxSize');						
			#if key doesn't exist or is set to 0, set $user_max_dir_size to domain default
			if ($user_max_dir_size == 0)
				{
				$user_max_dir_size = $domain_max_dir_size
				}

			if ($user_max_dir_size > 0)
				{
				$notify_window = .10;
				$lower_notify_dir_size = $user_max_dir_size - ($user_max_dir_size * $notify_window);
				$upper_notify_dir_size = $user_max_dir_size - ($user_max_dir_size * (.5 * $notify_window));
				#print "Mailbox limit " . $user_max_dir_size . " bytes\n";
				#print "Notify at " . $lower_notify_dir_size . " & " . $upper_notify_dir_size . " bytes\n";
				#print "\n";
				# Use "\.mbx$" for just mailbox files (*.mbx) or "$" for all files (*.*)
				$mbx_size = dir_size($users_dir_path . "\\" . $dir, '\.mbx$');
				if ($mbx_size > $lower_notify_dir_size)
					{
					$toaddress = $dir . "@" . $key;
					if ($mbx_size < $user_max_dir_size)
						{
						open (MAIL, ">$temp_msg") || die "open postmail or sendmail";
						if ($mbx_size < $upper_notify_dir_size)
							{
							# Construct Caution e-mail to user
							# Create A temporary File to construct the e-mail
							print MAIL "Caution; you are approaching the total mailbox size limit of " . $user_max_dir_size . " bytes. ";
							print MAIL "With a total mailbox size of " . $mbx_size . " bytes, your mailbox is at " . (($mbx_size / $user_max_dir_size)*100) . "% capacity. ";
							print MAIL "Routinely delete mesages to keep your mailbox reasonably below the limit. ";
							print MAIL "You won't receive email messages that cause your total mailbox size to exceed the limit." . "\n";
							print "Caution; user " . $toaddress . " is approaching the limit." . "\n";
							print LOGFILE "Caution; user " . $toaddress . " is approaching the limit.\n";
							}else{
							# Construct Warning e-mail to user
							# Create A temporary File to construct the e-mail
							print MAIL "Warning; you are close to the total mailbox size limit of " . $user_max_dir_size . " bytes. ";
							print MAIL "With a total mailbox size of " . $mbx_size . " bytes, your mailbox is at " . (($mbx_size / $user_max_dir_size)*100) . "% capacity. ";
							print MAIL "Routinely delete mesages to keep your mailbox reasonably below the limit. ";
							print MAIL "You won't receive email messages when your total mailbox size reaches the limit." . "\n";
							print "Warning; user " . $toaddress . " is close to the limit.\n";
							print LOGFILE "Warning; user " . $toaddress . " is close to the limit.\n";
							}
						close MAIL;
						system ("$imail1 -f $temp_msg -s $subject -t $toaddress");
						# Remove the File
						unlink $temp_msg;
						} else {
						print "Alert; user " . $toaddress . " has exceded the limit!\n";
						print LOGFILE "Alert; user " . $toaddress . " has exceeded the limit!\n";
						}
					print "Max. Mailbox Size: " . $user_max_dir_size . " | ";
					print LOGFILE "Max. Mailbox Size: " . $user_max_dir_size . " | ";				
					print "Total Size: " . $mbx_size . " bytes" . " | ";			
					print LOGFILE "Total Size: " . $mbx_size . " | ";
					print "Caution at: " . $lower_notify_dir_size . " | ";
					print LOGFILE "Caution at: " . $lower_notify_dir_size . " | ";
					print "\n";
					print LOGFILE "\n";
					print "\n";
					}
								
				}
			}
		}
	}
$hkey->Close();
print "\n";
print "Mailbox size report sent to " . $admin_address . "\n";
print LOGFILE "\n";
print LOGFILE "Mailbox size report sent to " . $admin_address . "\n";
close LOGFILE;
system ("$imail1 -f $mailbox -s $subject -t $admin_address");
# Remove the File
unlink $mailbox;

