#!/usr/bin/perl -w # C.J.Keene 2002 # # Report on the size of a users inbox # # Usage: # mailsize # to report on mail box size for the current user # mailsize login # to report on the mail box size of a given user # mailsize -e # to email the user with the output # # use strict; # some varibles that need to be set up before we process_arguments my $login; my $sendemail; my $currentuser; my $argpathtoinbox; my $checkinboxonly; my $home; my $maildir; process_arguments(); # ######################################################### # # Settings - some things that might want to be changed... # # # number of emails to display for each mail folder # default is to show the five largest emails my $numofemailstoshow = 5; # name of mail file for current user # by default uses file named in MAIL varible my $mailfilename = $ENV{MAIL}; # location of mail file when a username has been specified # use $login for the username and $home for home dir my $mailfilelogin = "$home/.mail"; # another popular location, uncomment to use... # my $mailfilelogin = "/var/mail/$login"; # If the inbox is smaller than the value below then do not # show the largest emails in the inbox (in kb) i.e just show # the total size for the inbox my $mininboxsize = "500"; # if emailing the output, provide the command which the output # should be sent to my $emailprogram = "/usr/bin/mailx"; # a message is displayed at the top of the output. # this can be set below. my $welcomemessage = "This email shows you the size of your inbox," . "and the largest emails \nwithin your inbox. You should try to keep" . " your inbox under 3Mb. Anything\nabove this size will result in " . "slower access times."; # when sending email, we need to create a temporary file # default is to create a tmp file in the users home directory my $emailfile = "$home/.mailsize.tmp"; # alternative example, store file in the /tmp folder, filename # being "mailsize", then the users login, then the epoch (time in # seconds since 1970). # Note: on multiuser systems, this may allow other users to # read the file, and to possible modify it, while the program is # running. USE WITH CARE. #my $emailfile = "/tmp/" . "mailsize.$login" . time; # location of the mail directory that holds mail folders other # than the users inbox. NOTE if this varible is unset (i.e. # commented out, with a hash at the start of the line), then # it will check either ~username/mail or ~username/Mail # which ever is larger in size - this is useful when some # users on a system use Mail and others use mail, depending # on their mail client. # By default this is commented, so mailsize will use the process # above, uncomment and set as needed. $login and $home can be used. #$maildir = "$home/mail"; # # # # # ## END OF SETTINGS ## # ######################################################## # set some varibles up my %mailhash; my $mailfilekb; # do some setting up, like opening the mail file setupstuff(); # print welcome message printintrotext(); # show inbox file size showmailboxsize(); # only show large emails if inbox is larger than a set sized. if ($mailfilekb > $mininboxsize) { # find biggest emails in inbox findbigemails(); # print out the largest emails displaybigemails(); } # check other email folders, unless the user only wants to check their # inbox if (!$checkinboxonly) { # first of all decide where their mail folder is, see if one # was set above, if not see if ~/mail or ~/Mail is bigger # and use that. if (!$maildir) { # maildir not set find out if mail or Mail should be used. } # get a list of files within the mail dir, find largest files } ########################################### # setupstuff # # merge defaults and params, act apon what we have been passed sub setupstuff { # if we were passed a path to inbox as a arg then use that # if not, then use one of two varibles depending on if we were # passed a username if ($argpathtoinbox) { # we were passed an arg for path to inbox, let's set it $mailfilename = $argpathtoinbox; } else { # we were not passed a path, but what path we now use depends # on if we were passed a username as a arg # i.e. if we were passed a username (and so currentuser is false # set the mailfilename varible to that of the mailfilelogin if (!$currentuser) { $mailfilename = $mailfilelogin; } } # now open the mail inbox open(DOTMAIL, "$mailfilename") or die "Can not open mail file $1\n"; # # if we are using email, redirect stdout if ($sendemail) { # first, check to see if their is a ~ tilda in the location # if so, replace it with the full home dir path $emailfile =~ s{ ^ ~ ( [^/]* ) } { $1 ? (getpwnam($1))[7] : ( $ENV{HOME} || $ENV{LOGDIR} || (getpwuid($>))[7] ) }ex; print " emailfile $emailfile\n\n"; # now we can actually open the temporary file open(STDOUT, ">$emailfile") or die "unable to create temporary file for $login"; } } ########################################### # printintrotext # # print the welcome message, if needed sub printintrotext { print "\n"; print $welcomemessage; print "\n\n"; } ########################################### # showmailboxsize # # show size of a mailbox sub showmailboxsize { # report on size, we use stat to get the size in bytes, then convert # this to kb and mb. my @mailfilestat = stat DOTMAIL; # convert to kb my $mailfilekbfloat = $mailfilestat[7] / 1024; # remove stuff after the decimal point ($mailfilekb,my $trash) = split /\./, $mailfilekbfloat; # now same for mb my $mailfilembfloat = $mailfilekbfloat / 1024; (my $mailfilemb,my $mailfilembRemainder) = split /\./, $mailfilembfloat; # for Mb we're show two deciamal places my $MBremainder = substr($mailfilembRemainder,0,2); print "Your inbox is currently $mailfilemb\.$MBremainder Mb"; print " ($mailfilekb kb) in size\n\n"; } ########################################## # findbigemails # # add all emails to a hash, along with each emails byte size sub findbigemails { # first set some varibles my $firstfive; my $currentline; my $maildate; my $mailsubject; my $mailsender; my $trash; my $headersdone; my $bytecount; my $linelength; while ($currentline = ) { # is this the start of a new email - if so it will start with # "From " $firstfive = substr($currentline,0,5); if ($firstfive eq "From ") { ########################### # this is the start of a new email # first add the old email to the hash addmailtohash ($bytecount, $maildate, $mailsender, $mailsubject); # set bytecount back to zero $bytecount = 0; $maildate = ""; $mailsubject = ""; $mailsender = ""; $headersdone = "no"; } else { ############################# # the is still the same email as the last line # find how many bytes (characters) are in this line $linelength = length $currentline; $bytecount = $bytecount + $linelength; # if we do not yet have date, subject AND sender then... # does this line contain either from,date or subject? if ($headersdone eq "yes") { # do nothing. This check is here because it is possible # that an email body can contain a line that starts with # From: or Date: or Subject: - if it did, then the real data # would be replaced with useless data from the email body. # # By allowing the first if to be true, once all headers are # collected, the remaining tests are skipped. Plus, this should # make things a little quicker as it will avoid unnecessary # pattern matching } elsif ($currentline =~ /^Date:/) { ($trash,$maildate) = split /e:/, $currentline; } elsif ($currentline =~ /^From:/) { ($trash,$mailsender) = split /m:/, $currentline; } elsif ($currentline =~ /^Subject:/) { ($trash,$mailsubject) = split /t:/, $currentline; } else { # we will be here if headersdone != yes (i.e. no) # and the currentline does not start with any of the above. # lets check to see if we now have the three bits of data, # and if so, set headersdone to yes if ($maildate ne "" and $mailsender ne "" and $mailsubject ne "") { $headersdone = "yes"; } } # end of sender,subject,date collecting if statement } # end of "is this start of new email, or same as last time" if } # end of "repeat for each line of mail file" while } # end of sub ################################################ # addmailtohash # # called from findbigemails. Once we have reached the end of an email # add it to the hash sub addmailtohash { # convert passed data into strings... my $bytecount = "1"; my $date = "unknown date"; my $sender = "unknown sender"; my $subject = "no subject"; $bytecount = $_[0] if ($_[0]); $date = $_[1] if ($_[1]); $sender = $_[2] if ($_[2]); $subject = $_[3] if ($_[3]); # clean up a bit chop $subject; chop $date; chop $sender; # check that subject is not to long #!!!!!!!!!!!!!!!!!!!!!todo $sender = substr($sender,0,40); $date = substr($date,0,26); # my $mailheaders = "$date " . "$sender\n " . "\t Subject: $subject\n"; $mailhash{$mailheaders} = $bytecount; } # end of addmailtohash sub ################################################ # displaybigemails # # order hash sub displaybigemails { my $kb; my $trash; # make sure numofemailstoshow is set $numofemailstoshow = 5 if ($numofemailstoshow eq ""); my $shownemailscount = 0; my $key; foreach $key (sort { $mailhash{$b} <=> $mailhash{$a} } keys %mailhash) { $shownemailscount++; return if ($shownemailscount > $numofemailstoshow); # turn bytes in to kb $kb = $mailhash{$key} /1024; ($kb, $trash) = split /\./, $kb; print "$kb" . "kb\t $key \n"; } } ############################################ # whichmaildir # # if no mail dir is set then find out which is bigger # mail or Mail sub whichmaildir { # } ############################################ # process_arguments # # take any arguments passed on the command line sub process_arguments { while(@ARGV) { my $param = shift @ARGV; if ($param eq "-e") { # they want to send email $sendemail = 1; } elsif ($param eq "-h" || $param eq "--help") { print "\nmailsize: shows size of email inbox and folders, "; print "displays the largest emails\n\n"; print "Usage: mailsize [-e] [-p path_to_inbox] [-i] [username]\n"; print " -e email the output to the user whose mail we are"; print " checking\n"; print " -p specify a path to the inbox to be checked.\n"; print " -i only check the user's inbox, not their other mail"; print " folders\n"; print " username the name of the user you wish to check\n\n"; print "With no arguments, mailsize checks the current user's"; print " inbox and mail store,\n and prints to standard output.\n\n"; exit; } elsif ($param eq "-i") { # they only want the inbox checked, not subfolders $checkinboxonly = 1; } elsif ($param eq "-p") { # the next thing should be a path $param = shift @ARGV; $argpathtoinbox = $param; } else { # presume that anything we have left is the username $login = $param; } # end of if } # end of while # if login is not set, it was not passed as a param, so the user # wants to check their own mail. if (!$login) { $login = getlogin; # set currentuser true if we have not been passed a username $currentuser = 1; } # Now we have login set, regardless of if we were passed a username # or not, we can now find the home dir, in case it is needed. ($home) = (getpwnam($login))[7]; }