###########################################################################
# 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 (#1 work in progress) contributed by David Gregg dgregg@dgsoft.com
# to return directory size.
###########################################################################

#sub dir_size {
#local($l_physicaldirectory, $l_searchpattern) = @_;
#local(@l_allfiles, $l_filename, $l_filesize);
#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);
#
#chdir("$l_filedirectory");
#opendir(THISDIR, ".");
#@l_allfiles = grep(/$l_searchpattern/i, readdir(THISDIR));
#closedir(THISDIR);
#
#@l_allfiles = sort(@l_allfiles);
#
#foreach $l_filename (@l_allfiles) {
#($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_physicaldirectory/$l_filename");
#
# calc file size for display
#$l_filesize = $l_fsize/1024;
#if ($l_filesize < 1) {
#$l_filesize = 1;
#} else {
#$l_filesize = int($l_filesize);
#}

#$l_totsize += $l_filesize;
#print "$l_filename $l_filesize\n";
#}
#print "Total: $l_totsize kilobytes\n";
#return $l_totsize;
#}

###########################################################################
# Subroutine (#2 work in progress) contributed by David Gregg dgregg@dgsoft.com
# to return directory size.
###########################################################################

#sub dir_size { 
#local($l_physicaldirectory) = @_;
#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); 
##chdir("$l_physicaldirectory");
#opendir(THISDIR, "$l_physicaldirectory"); 
#@l_allfiles = grep(!-d, readdir(THISDIR)); 
#closedir(THISDIR); 
#$l_totsize = 0; 
#foreach $l_filename (@l_allfiles) { 
#($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_physicaldirectory/$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;
}

###########################################################################
# Original version of sub dir_list using "dir /ad" to return a list of subdirectories.
###########################################################################

#sub dir_list {
#my $test_dir = $_[0];
#
#@lines = `dir /ad "$test_dir"`;
##Remove first 7 lines, and last 2 lines
#pop(@lines);
#pop(@lines);
#shift(@lines);
#shift(@lines);
#shift(@lines);
#shift(@lines);
#shift(@lines);
#shift(@lines);
#shift(@lines);
##Loop through each line of directory output and strip out everything 
##but the directory then call dir_size.
##assign @lines to $line, one at a time
#foreach $line (@lines)                
#	{
#	@line = split(/ /,$line,21);
#	splice(@line,0,20);
#	chomp(@line);
#	my $current_dir = $line[0];
#	push (@list, $current_dir);
#	}
#return @list;
#}

###########################################################################
# 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($dir) . " 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";
				$mbx_size = dir_size($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.\n";
							print MAIL "With a total mailbox size of " . $mbx_size . " bytes, your mailbox is at " . (($mbx_size / $user_max_dir_size)*100) . "% capacity." . "\n";
							print MAIL "You must routinely delete mesages to keep your mailbox reasonably below the limit.\n";
							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.\n";
							print MAIL "With a total mailbox size of " . $mbx_size . " bytes, your mailbox is at " . (($mbx_size / $user_max_dir_size)*100) . "% capacity." . "\n";
							print MAIL "You must routinely delete mesages to keep your mailbox reasonably below the limit.\n";
							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;


