#!/usr/bin/perl
#-----------------------------------------------------------------------------
# trashmail 0.9h - smart mail-purging utility
# Copyright (c) 1998 Edwin P. Pranoto (edwin@indo.net.id)
#
# trashmail allows you to free up disk space by cleaning out unused/unwanted
# mails, by feeding some options (as criterias) it will do the job smartly.
#
# The source code is freely redistributeable and may be used for any purpose. 
# This copyright notice must stay here.
#
# The author is not reponsible for the consequences of using this program.
#-----------------------------------------------------------------------------

$AUTHOR  = "Edwin P. Pranoto \<edwin\@indo.net.id\>";

$ID      =  $0;
$ID      =~ s#.*/(.*)#$1#;
$DATE    = "25 Sep 1998";
$VERSION = "0.9h";

$SIG{'INT'} = $SIG{'PIPE'} = $SIG{'QUIT'} = trashmail_handler;

sub trashmail_handler {
   close (MBOX2);
   unlink ($usermboxtemp);
   if ($keep_trash) {
      close (MTRASH);
      unlink ($usertrashtemp);
   }
   print "\n" if ($verbose==2);
   mydie (0, "...aborted");
}

# -- default variables
$default_mail_logic    = "and";
$default_mail_location = "/var/spool/mail";
$default_mail_backup   = "/tmp";

$mail_logic            = $default_mail_logic;
$mail_location         = $default_mail_location;
$mail_backup           = $default_mail_backup;
$verbose               = 1;
$force_run             = 0;
$list_only             = 0;
$keep_trash            = 0;
$do_backup             = 1;
$reverse_trashmail     = 0;
$re_index              = 0;
$strict_case           = 0;
$check_attachment      = 0;
$total_parsed_size     = 0;

# -- Parse arguments, and create variable on the fly
#    see option --help for valid options

if (!@ARGV) {
   mydie (0, "smart mail trasher, by $AUTHOR\nType `$ID --help' for help");
}
 
while (@ARGV) {
   $_ = shift (@ARGV);

   if (/^-/) {
      ($option,$val) = split ('=', $_);

      if (/^--help/ || /^-h/ || /^-\?/) {
         &trashmail_help;
      }

      if (/^--reverse/ || /^-r/) {
         $reverse_trashmail = 1;
         next;
      }

      if (/^--quiet/ || /^--silent/ || /^-q/) {
         $verbose = 0;
         next;
      }

      if (/^--verbose/ || /^-v/) {
         $verbose = 2;
         next;
      }

      if (/^--keep-trash/ || /^-k/) {
         $keep_trash = 1;
         next;
      }

      if (/^--no-backup/ || /^-b/) {
         $do_backup = 0;
         next;
      }

      if (/^--force-run/ || /^-f/) {
         $force_run = 1;
         next;
      }

      if (/^--list-only/ || /^-l/) {
         $list_only = 1;
         next;
      }

      if (/^--re-index/ || /^-i/) {
         $re_index = 1;
         next;
      }

      if (/^--attachment/ || /^-x/) {
         $check_attachment = 1;
         next;
      }

      if (/^--and/ || /^-a/) {
         $mail_logic = "and";
         next;
      }

      if (/^--or/ || /^-o/) {
         $mail_logic = "or";
         next;
      }

      if (/^--version/ || /^-V/) {
         $verbose = 1;
         mydie (0, "ver $VERSION ($DATE)");
      }

      if (/^--strict-case/ || /^-c/) {
         $strict_case = 1;
         next;
      }

      if (/^--regex/ || /^-R/) {
         $regex = 1;
         next;
      }

      if (/^$option=/) {
         $option =~ s/^--//g;
         $option =~ tr/-/_/;
         if (($option eq "logic") || 
             ($option eq "location") || 
             ($option eq "backup")) {
            eval "\$mail_$option = \$val;";
         } else {
            if (($option eq "month") || ($option eq "day")) {
               $val = tolower ($val);
            }
            $option = tolower ($option);
            eval "push (\@mail_$option, \$val);";
         }
      }
   } else {
      mydie (1, "argument not recognized");
   }
}

if ($list_only) {
   $reverse_trashmail = !$reverse_trashmail;
}
 
# -- wrong location?
chdir ($mail_location) || mydie (3, "can't access directory $mail_location");

while (@mail_user) {
   $user = shift (@mail_user);
   if ($user) {
      $all_mail_user = "$all_mail_user $user";
   }
}

# -- empty argument for user?
if (!$all_mail_user) {
   mydie (2, "no user specified",
             "no user specified, use `--user=USERNAME'");
} else {
   $all_mail_user =~ s/,/ /g;
}

# -- go get the user's mailbox
@listmbox = `/bin/ls -1 $all_mail_user 2> /dev/null`;
if (!@listmbox) {
   mydie (4, "user(s) not found",
             "user(s) not found at location $mail_location");
}

if (! -d $mail_backup) {
   mydie (5, "can't access directory $mail_backup");
}

# -- when is now?
$DATENOW   = getdate();
$SECSTODAY = num_of_seconds ($DATENOW, gettime());
$DAYSTART  = num_of_seconds ($DATENOW, "00:00:00");

# -- check all users specified in --user
foreach $listmbox (@listmbox) {
   chop ($listmbox);
   $user                  = $listmbox;
   $user                  =~ s#.*/(.*)#$1#;
   $trash_it              = 0;
   $tempfile              = "/tmp/.$ID.$user";
   $lockfile              = "/tmp/.locked.$ID.$user";
   $usermbox              = "$mail_location/$user";
   $usermboxold           = "$mail_backup/$user.old";
   $usertrash             = "$mail_backup/$user.trash";
   $usermboxtemp          = "/tmp/.$user.temp";
   $usertrashtemp         = "/tmp/.$user.trash.temp";
   $got_mail_index        = 0;
   $got_mail_trashed      = 0;
   $got_mail_trashed_size = 0;

   next if !$listmbox;

   if ($mail_min_file_size[0]) {
      next if (-s $usermbox < check_unit_size ($mail_min_file_size[0])); 
   }

   if ($mail_until_file_size[0]) {
      next if (-s $usermbox < check_unit_size ($mail_until_file_size[0])); 
   }

   if ($verbose) {
      print "Processing user $user... ";
      if ($verbose==1 || $list_only) {
         print "\n";
      }
   }
   if (!$list_only) {
      debug (2, "\n  checking user's process... ");
      if (-f $lockfile) {
         if ($force_run) {
            debug (1, "warning: forcing process\n");
         } else {
            debug (1, "already running\n");
            next;
         }
      } else {
         debug (2, "ok\n");
      }  

      debug (2, "  creating lock file... ");
      $rc = open (LOCK, "> $lockfile");
      if (!$rc) {
         debug (1, "failed\n");
         $done = 0;
         next;
      } else {
         debug (2, "ok\n");
         print LOCK "locked";
         close (LOCK);
      }
   }

   debug (2, "  opening mailbox... ");

   $rc = open (MBOX, "< $usermbox");
   if (!$rc) {
      debug (1, "failed\n");
      $done = 0;
      unlink ($lockfile);
      next;
   } else {
      debug (2, "ok\n");
   }

   if (!$list_only) {
      $rc = open (MBOX2, "> $usermboxtemp");
      if (!$rc) {
         $done = 0;
         unlink ($lockfile);
         close (MBOX);
         next;
      }
      if ($keep_trash) {
         $rc = open (MTRASH, "> $usertrashtemp");
         if (!$rc) {
            $keep_trash = -1;
         };
      }
   }

   $do_search = 1;
   do {
      $process_msg = "  parsing mailbox... [$got_mail_index]";
      if ($got_mail_trashed) {
         $process_msg = "$process_msg, trashing... [$got_mail_trashed]";
      }
      debug (2, "$process_msg\r");

      open (TEMP, "> $tempfile");
      if (read_header ($last, MBOX, TEMP)) {
         $last = read_body (MBOX, TEMP);
         ++$got_mail_index;
      }
      close (TEMP);

      if ($do_search) {
         undef @return_code;
         push (@return_code,
         multiple_search_mail (unMime ($parsed_mail_subject), @mail_subject),
         multiple_search_mail (unMime ($parsed_mail_from), @mail_from),
         multiple_search_mail ($parsed_mail_day, @mail_day),
         multiple_search_mail ($parsed_mail_month, @mail_month),
         multiple_check_range ("date", $parsed_ddmmyy, @mail_date),
         multiple_check_range ("time", $parsed_mail_time, @mail_time),
         multiple_check_range ("age", $parsed_mail_age, @mail_age),
         multiple_check_range ("index", $got_mail_index, @mail_index),
         multiple_check_range ("size", $parsed_mail_size, @mail_size),
         multiple_check_range ("num-of-to", 
                               $parsed_mail_xto, @mail_num_of_to),
         multiple_check_range ("num-of-cc", 
                               $parsed_mail_xcc, @mail_num_of_cc),
         multiple_check_range ("num-of-relay", 
                               $parsed_mail_xpath, @mail_num_of_relay),
         );

         for $foo (@search_headers) {
            if (($foo ne "date") && (eval "\@mail_$foo")) {
               push (@return_code,
               eval "multiple_search_mail (\$parsed_mail_$foo, \@mail_$foo)");
            }
         }

         if ($check_attachment) {
             push (@return_code, $parsed_mail_attachment);
         }

         $trash_it = test_logic (@return_code);
         if ($reverse_trashmail) {
            $trash_it = !$trash_it;
         }
      } else {
         $trash_it = 0;
      }

      if (!$trash_it) {
         if ($list_only && $do_search) {
            my $mail_from_who = unMime ($parsed_mail_from);
            $mail_from_who    =~ s/"//g;

            ++$got_mail_trashed;
            $got_mail_trashed_size+= $parsed_mail_size;

            printf "%5d %s %-20.20s %-3s %02d/%02d/%4d %-8.8s %6.6s %-19.19s\n",
                   ($re_index ? $got_mail_trashed : $got_mail_index),
                   ($parsed_mail_attachment ? "@" : " "),
                   $mail_from_who, $parsed_mail_day, 
                   $parsed_mail_date, 
                   month2num (tolower($parsed_mail_month)), 
                   $parsed_mail_year, $parsed_mail_time,
                   tidyup ($parsed_mail_size), 
                   unMime ($parsed_mail_subject);

            undef $mail_from_who;
         } else {
            open (TEMP, "< $tempfile");
            while (<TEMP>) {
               print MBOX2 $_;
            }
            close (TEMP);
         }
      } else {
         if (!$list_only) {
            ++$got_mail_trashed;
            $got_mail_trashed_size+= $parsed_mail_size;
         }

         if ($keep_trash==1) {
            open (TEMP, "< $tempfile");
            while (<TEMP>) {
               print MTRASH $_;
            }
            close (TEMP);
         }
      }
      unlink ($tempfile);

      if ($mail_process_only[0]) {
         if ($got_mail_index >= $mail_process_only[0]) {
            $do_search = 0; 
         }
      }

      if ($mail_match_first[0]) {
         if ($got_mail_trashed >= $mail_match_first[0]) {
            $do_search = 0; 
         }
      }

      if ($mail_until_file_size[0]) {
         if (-s $usermbox < (check_unit_size ($mail_until_file_size[0]) + $total_parsed_size)) {
            $do_search = 0; 
         }
      }
   } until eof (MBOX);

   if (!$list_only) {
      $process_msg = "  parsing mailbox...";
      if (!$got_mail_index) {
         $result_msg = "none"; 
      } else {
         if (!$got_mail_trashed) {
            $result_msg = "[$got_mail_index], no mail trashed";
         } else {
            $result_msg = "[$got_mail_index], trashing... [$got_mail_trashed]";
         }
      }
      debug (2, "$process_msg $result_msg\n");
      debug (2, "  closing mailbox... ");
   } else {
      if ($verbose==2 && $got_mail_index) {
         if ($got_mail_trashed) {
            printf "%d match%s out of %d mail%s, will save %d bytes\n",
                   $got_mail_trashed,
                   ($got_mail_trashed > 1) ? "es" : "",
                   $got_mail_index,
                   ($got_mail_index > 1) ? "s" : "",
                   $got_mail_trashed_size;
         } else {
            print "No match\n";
         }
      }
   }

   close (MBOX);
   close (MBOX2);
   close (MTRASH);

   if (!$list_only) {
      debug (2, "ok\n");
      debug (2, "  removing lockfile... ");
      unlink ($tempfile);
      unlink ($lockfile);
      debug (2, "ok\n");
      finish_up ($usermbox, $usermboxtemp);
      $done = 1;
   }
}
if ($verbose && $done) {
   print "Done.\n";
}

#------------------------------------------------------------------------------
sub tidyup {
   my ($arg) = @_;
   my $len   = length ($arg);
   my $div   = 1;
   my $unit  = " ";

   if ($len >= 6) {
      $div  = 1024;
      $unit = "k";
   } 
   if ($len >= 9) {
      $div  = 1024*1024;
      $unit = "m";
   } 
   $arg = int ($arg / $div);

   return "$arg$unit";
}
#------------------------------------------------------------------------------
sub check_unit_size {
   my ($arg) = @_;
   my $unit  = tolower ($arg);

   $arg  =~ s/[a-z,A-Z]//g;
   $unit =~ s/[0-9]//g; 

   SWITCH: {
      if (($unit eq "b") || ($unit eq "")) {
         last SWITCH; 
      }
      if ($unit eq "k") { 
         $arg *= 1024;
         last SWITCH;
      }
      if ($unit eq "m") { 
         $arg *= 1024*1024;
         last SWITCH;
      }
   }
   return $arg;
}

sub is_attachment {
   my ($attach) = @_;
   my $rc       = 0;
   $savedarg    = $_;

   $_      = $attach;
   $attach = tolower ($attach);
   chop;

   if (/^Content_Type:/) {
      if (index ($attach, "text") < 0) {
         $rc = 1;
      }
   }
   $_ = $savedarg;

   return $rc;
}

sub read_header {
   my ($laststr, $mbox, $temp) = @_;
   my $rc = 0;

   $parsed_mail_from1       = "";
   $parsed_mail_day         = "";
   $parsed_mail_month       = "";
   $parsed_mail_date        = "";
   $parsed_mail_ddmmyy      = "";
   $parsed_mail_time        = "";
   $parsed_mail_year        = "";
   $parsed_mail_timezone    = "";
   $parsed_mail_age         = 0;
   $parsed_mail_size        = 0;
   $parsed_mail_xpath       = 0;
   $parsed_mail_xto         = 0;
   $parsed_mail_xcc         = 0;
   $parsed_mail_attachment  = 0;
 
   for $foo (@search_headers) {
      eval "undef \$parsed_mail_$foo;";
   }
   undef (@search_headers);

   if ($laststr) {
      $_ = $laststr;
   } else {
      $_ = <$mbox>;
   }

   if ($_) {
      $rc = 1;
   }

   parse_topheader ($_);

   while (1) {
      if ($list_only || $check_attachment) {
         if (!$parsed_mail_attachment) {
            $parsed_mail_attachment = is_attachment ($_);
         }
      }
      $parsed_mail_size+= length;
      print $temp $_;
      last if /^$/;
      $_ = <$mbox>;
      parse_header ($_);
   }
   return $rc;
}
#------------------------------------------------------------------------------
sub parse_topheader {
   my ($str) = @_;
   chop ($str);

   $str                  =~ s/  / /g;
   my @fromline          = split (' ', $str);
   $parsed_mail_from1    = $fromline[1];
   $parsed_mail_day      = $fromline[2];
   $parsed_mail_month    = $fromline[3];
   $parsed_mail_date     = $fromline[4];
   $parsed_mail_time     = $fromline[5];
   $parsed_mail_timezone = "";
   $parsed_mail_year     = $fromline[6];
   if ($fromline[7]) {
      $parsed_mail_timezone = $fromline[6];
      $parsed_mail_year     = $fromline[7];
   }
   $parsed_ddmmyy = "$parsed_mail_date/$parsed_mail_month/$parsed_mail_year";
   $parsed_mail_age = $SECSTODAY - 
                      num_of_seconds ($parsed_ddmmyy, $parsed_mail_time);

   # are we parsing the 'header'?
   my $rcday   = 1;
   my $rcdate  = 1;
   my $rcmonth = 0;
   my $rcyear  = 1;

   if ($parsed_mail_day =~ /\d/) {
      $rcday   = 0;
   }
   if ($parsed_mail_date =~ /\D/) {
      $rcdate  = 0;
   }
   if (month2num (tolower ($parsed_mail_month))) {
      $rcmonth = 1;
   }
   if ($parsed_mail_year =~ /\D/) {
      $rcyear  = 0;
   }

   return ($rcday & $rcdate & $rcmonth & $rcyear);
}
#------------------------------------------------------------------------------
sub mimeToChar {
    my ($str) = @_;
    $str =~ s/=//;

    return pack ("C", hex ($str));
}

sub unMimeWord {
    my ($str) = @_;
    $str =~ s/_/\x20/g;
    $str =~ s/(=..)/mimeToChar ($1)/ige;

    return $str;
}

sub unMime {
    my ($str) = @_;
    $str =~ s/=\?iso-8859-1\?q\?([^\?]*)\?=/unMimeWord ($1)/ige;

    return $str;
}
#------------------------------------------------------------------------------
sub parse_header {
   my $str;
   my $foo;

   chop;
   $_ =~ s/-/_/g;

   if (/^Received: /) {
      ++$parsed_mail_xpath;
   }

   if (/^([a-z,A-Z].*?): (.*)$/) {
      $foo = tolower ($1);
      if (eval "\@mail_$foo"  ||
         ($foo eq "subject")  || ($foo eq "from") ||
         ($foo eq "to")       || ($foo eq "cc")
      ) {
         $str = $2;
         if (eval "\$parsed_mail_$foo") {
            eval "\$parsed_mail_$foo = \"\$parsed_mail_$foo \$str\";";
         } else {
            eval "\$parsed_mail_$foo = \$str;";
         }
         $search_headers [1+$#search_headers] = $foo;
      }
   }
}
#------------------------------------------------------------------------------
sub parsed_count {
   my ($parsed_arg) = @_;
   my $num  = 1 + $parsed_arg =~ tr/,/,/;
   my $num2 = $parsed_arg =~ tr/\@/\@/;

   return (($num > $num2)? $num2 : $num);
}

sub read_body {
   my ($mbox, $temp) = @_;
   my $blankbefore   = 1;

   $parsed_mail_xto = parsed_count ($parsed_mail_to);
   $parsed_mail_xcc = parsed_count ($parsed_mail_cc);

   while (<$mbox>) {
      if ((/^From /) && $blankbefore) {
         last if (parse_topheader ($_));
      }
      $parsed_mail_size+= length;
      if ($list_only || $check_attachment) {
         if (!$parsed_mail_attachment) {
            $parsed_mail_attachment = is_attachment ($_);
         }
      }
      $blankbefore = 0; $blankbefore = 1 if /^$/;
      print $temp "$_";
   }
   $total_parsed_size+= $parsed_mail_size;

   return $_;
}
#------------------------------------------------------------------------------
sub myrename {
   my ($source, $destination) = @_;
   system "mv $source $destination";
}

sub finish_up {
   my $tmp = "$usermboxtemp.tmp";
   my ($file1, $filetemp) = @_;
   my ($x,$x,$mode,$x,$uid,$gid,$x,$x,$x,$x,$x,$x,$x) = stat ($file1); 
   my $local_do_backup  = $do_backup;
   my $local_keep_trash = $keep_trash;

   if (!$got_mail_trashed) {
      $local_do_backup = $local_keep_trash = 0;
   }

   if ($local_do_backup) {
      debug (2, "  creating backup at $mail_backup/$user.old... ");
      myrename ($file1, $tmp);
   }
   myrename ($filetemp, $file1);
   if ($local_do_backup) {
      myrename ($tmp, $usermboxold);
   } else {
      unlink ($tmp);
   }
   chown $uid, $gid, $file1;
   chmod $mode, $file1;
   if ($local_do_backup) {
      debug (2, "ok\n");
   }

   if ($local_keep_trash != 0) {
      debug (2, "  creating trashed part at $mail_backup/$user.trash... ");
      if ($local_keep_trash==1) {
         myrename ($usertrashtemp, $usertrash);
         debug (2, "ok\n");
      } else {
         debug (2, "failed\n");
      }
   }
}   
#------------------------------------------------------------------------------
sub mydie {
   my ($rc, $brief, $detail) = @_;
   if ($brief) {
      if ($verbose) {
         print "$ID: ";
         if ($verbose==1) {
            print "$brief";
         }
         if ($verbose==2) {
            if (!$detail) {
               print "$brief";
            } else {
               print "$detail";
            }
         }
         print "\n\n";
      }
   } else {
      print "\n";
   }
   if ($tempfile) {
      unlink ($tempfile);
   }
   if ($lockfile) {
      unlink ($lockfile);
   }

   close (MBOX);
   close (MBOX2);
   close (MTRASH);

   exit $rc;
}
#------------------------------------------------------------------------------
sub debug {
   my ($rc, $message) = @_;
   if ($verbose >= $rc && !$list_only) {
      if (($verbose==1) && ($rc==1)) {
         print "  *";
      }
      print "$message";
   }
}
#------------------------------------------------------------------------------
sub test_logic {
   my $result = 0;
   my $arg;

   if ($mail_logic eq "and") {
      $result = 1;
   }
   while (@_) {
      $arg = pop (@_);
      if ($mail_logic eq "and") {
         $result &= $arg;
      } else {
         $result |= $arg;
      }    
   }
   return $result;
}
#------------------------------------------------------------------------------
sub multiple_search_mail {
   my ($parsed, @array) = @_;
   my $rc = test_logic();
   my @retcode=();

   while (@array) {
      my $arg = shift (@array);
      if (!$strict_case) {
         $parsed = tolower ($parsed);
         $arg    = tolower ($arg);
      }
      $rc = 0;
      if (($regex && ($parsed=~/$arg/)) || (index ($parsed, $arg) >= 0)) {
         $rc = 1;
      }
      push (@retcode, $rc);
   }
   return test_logic (@retcode);
}
#------------------------------------------------------------------------------
sub multiple_check_range {
   my ($option, $parsed, @array) = @_;
   my $arg;
   my @retcode=();

   while (@array) {
      $arg = shift (@array);
      push (@retcode, check_range ($option, $parsed, $arg));
   }
   return test_logic (@retcode);
}

sub check_range {
   my ($option, $parsed, $local_range) = @_;
   my $error  = "argument --$option=$local_range is not valid";
   my $ercode = 5;
   my $rc     = test_logic();

   if ($local_range ne "") {
      my $local_alpha = $local_range;
      $rc             = 0;
      $local_range    =~ s/[-+,a-z,A-Z]//g;
      $local_alpha    =~ s/[0-9]//g;
      my $len_comp    = 2;
      my $len_alpha   = ($local_alpha ? length ($local_alpha) : 0);
  
      if ($option eq "time") {
         ++$len_comp;
         $local_range = time_into_seconds ($local_range);
         $parsed      = time_into_seconds ($parsed);
      }

      if ($option eq "date") {
         my $temp_var = $parsed;
         ++$len_comp;
         $parsed      = date_into_seconds ($local_range);
         $local_range = date_into_seconds ($temp_var);
      }

      if (($len_alpha != 0) && ($len_alpha > $len_comp)) {
         mydie ($ercode, $error);
      } else {
         my $unit = $local_alpha;
         my $sign = $local_alpha;
         $unit    =~ s/[-+]//g;
         $sign    =~ s/[\/:,a-z,A-Z]//g;

         if ($option eq "age") {
            my $STARTDAY = $DAYSTART - 
                           num_of_seconds ($parsed_ddmmyy, "00:00:00");
            $local_range =~ s/://g;
            SWITCH: {
               if ($unit eq "s") {
                  last SWITCH; 
               }
               if ($unit eq "m") {
                  $local_range *= 60;
                  last SWITCH; 
               }
               if ($unit eq "h") {
                  $local_range *= 3600;
                  last SWITCH; 
               }
               if (($unit eq "D") || ($unit eq "")) {
                  $local_range *= 86400;
                  $parsed       = $STARTDAY;
                  last SWITCH; 
               }
               if ($unit eq "W") { 
                  $local_range *= (7 * 86400);
                  $parsed       = $STARTDAY;
                  last SWITCH;
               }
               if ($unit eq "M") { 
                  $local_range *= (30 * 86400);
                  $parsed       = $STARTDAY;
                  last SWITCH;
               }
               if ($unit eq "Y") { 
                  $local_range *= (365 * 86400);
                  $parsed       = $STARTDAY;
                  last SWITCH;
               }
               mydie ($ercode, $error);
            }
         }

         if ($option eq "size") {
            $local_range =~ s/://g;
            $local_range = check_unit_size ("$local_range$unit");
         }

         SWITCH: {
            if ($sign eq "+") { 
               if ($parsed > $local_range) {
                  $rc = 1;
               }
               last SWITCH;
            }
            if ($sign eq "-") {
               if ($parsed < $local_range) {
                  $rc = 1;
               }
               last SWITCH;
            }
            if ($parsed == $local_range) {
               $rc = 1;
            }
         }
      }
   }
   return $rc;
}
#------------------------------------------------------------------------------
sub getdate {
   my $strtime      = localtime;
   $strtime         =~ s/  / /g;
   $strtime         = tolower ($strtime);
   my @splitstrtime = split (' ', $strtime);

   return "$splitstrtime[2]/$splitstrtime[1]/$splitstrtime[4]";
}

sub gettime {
   my $strtime      = localtime;
   $strtime         =~ s/  / /g;
   $strtime         = tolower ($strtime);
   my @splitstrtime = split (' ', $strtime);

   return $splitstrtime[3];
}

sub month2num {
   my $rc;
   my ($month) = @_;
   my %months = (
      "jan", 1, "feb", 2, "mar", 3, "apr", 4,  "may", 5,  "jun", 6,
      "jul", 7, "aug", 8, "sep", 9, "oct", 10, "nov", 11, "dec", 12
   );
   my $num = $month;
   $num =~ s/[0-9]//g;
   if ($num eq $month) {
      $rc = $months{$month};
   } else {
      $rc = $month;
   }

   return $rc;
}
#------------------------------------------------------------------------------
sub time_into_seconds {
   my ($arg) = @_;
   my @timerange = split (':', $arg);
   my $local_range = $timerange[0]*3600 + $timerange[1]*60 + $timerange[2];

   if (!$arg) {
      $local_range = 0;
   }

   return $local_range;
}

sub date_into_seconds {
   my ($arg) = @_;
   my @daterange = split ('/', $arg);
   my @datetoday = split ('/', $DATENOW);

   $daterange[0] = $datetoday[0] if (!$daterange[0]);
   $daterange[1] = $datetoday[1] if (!$daterange[1]);
   $daterange[2] = $datetoday[2] if (!$daterange[2]);
   $maildate = "$daterange[0]/$daterange[1]/$daterange[2]";

   my $local_range = ($DAYSTART - num_of_seconds ($maildate, "00:00:00"));
   if (!$arg) {
      $local_range = 0;
   }

   return $local_range;
}

sub num_of_seconds {
   my ($arg, $arg2) = @_;
   my @months       = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
   my $base         = 1900;
   my $leapfactor   = 0;
   my $totaldays    = 0;
   my @dmy          = split ('/', $arg);
   my $dd           = $dmy[0];
   my $mm           = month2num (tolower ($dmy[1]));
   my $yyyy         = $dmy[2];
   my $daysbase     = ($yyyy - $base) * 365;
   my $leapdays     = int (0.75 + ($yyyy - $base) / 4);

   if (($yyyy%4 == 0) && ($mm > 2)) {
      $leapfactor = 1;
   }
   for (my $i=0; $i<$mm-1; $i++) {
      $totaldays+= $months[$i];
   }
   $totaldays+= ($dd + $daysbase + $leapdays + $leapfactor);

   return ((86400 * $totaldays) + time_into_seconds ($arg2));
}
#------------------------------------------------------------------------------
sub tolower {
   my ($arg) = @_;
   $arg =~ tr/A-Z/a-z/;

   return $arg;
}
#------------------------------------------------------------------------------
sub trashmail_help {
   print 
   "Usage: $ID [options]\n", 
   "options: [defaults in brackets after descriptions]\n\n",
   "Info:\n",
   "  -h, --help                    print this message\n",
   "  -V, --version                 print version info\n\n",
   "Processing:\n",
   "  -q, --quiet, --silent         ssstttt...\n",
   "  -v, --verbose                 print detail activities\n",
   "  -l, --list-only               list all mail's header ala `from'\n",
   "  -i, --re-index                when listing mail, try to reindex\n",
   "  -k, --keep-trash              keep trashed part in backup directory\n",
   "  -b, --no-backup               do not keep old mail(s)\n",
   "  -f, --force-run               force $ID to run and override lock!\n",
   "                                only use this if you're sure NO other\n",
   "                                process for user(s) is running\n",
   "  -a, --and                     logical `and' operation, see --logic=and\n",
   "  -o, --or                      logical `or' operation, see --logic=or\n\n",
   "  --min-file-size=SIZE[b|k|m]   only process mail file with minimum\n",
   "                                SIZE (in [b]ytes, kb or mb)\n\n",
   "  --until-file-size=SIZE[b|k|m] process until mail's size is less or equal\n",
   "                                than SIZE (in [b]ytes, kb or mb)\n",
   "  --match-first=FIRST           match only the first FIRST items\n",
   "  --process-only=MAX            process until index #MAX\n\n",
   "Directory and file names:\n",
   "  --location=DIR                location of mail(s) is in DIR [$default_mail_location]\n",
   "  --backup=DIR                  backup is in DIR [$default_mail_backup]\n\n",
   "Matching criteria:\n",
   "  -R, --regex                   use regular expression to match string\n",
   "  -c, --strict-case             case sensitive search\n",
   "  -r, --reverse                 reverse polarity of $ID -> keepmail\n",
   "  -x, --attachment              match mail with attachment\n\n",
   "  --logic=[and|or]              perform logical operation on options [$default_mail_logic]\n",
   "                                see also --and / --or\n",
   "  --user=USERNAME[,..]          USERNAME to be checked, wildcard is ok\n",
   "  --[header-tags]=STRING        you can have any of them to be used\n",
   "                                as options, like Subject (--subject=),\n",
   "                                To (--to=), X-Mailer (--x-mailer=), etc.\n",
   "                                STRING is any substrings to locate\n",
   "  --month=MONTH                 equal to MONTH (jan, feb, ...)\n",
   "  --day=DAY                     equal to DAY (sun, mon, ...)\n",
   "  --date=[+|-]DD[/MM/YYYY]      after/before/equal to date (DD/MM/YYYY)\n",
   "  --index=[+|-]INDEX            greater/smaller/equal INDEX\n",
   "  --size=[+|-]SIZE[b|k|m]       greater/smaller/equal SIZE\n",
   "                                in [b]ytes, kb or mb\n",
   "  --time=[+|-]HH[:MM:SS]        greater/smaller/equal time in HH:MM:SS\n",
   "  --age=[+|-]AGE[s|m|h|D|W|M|Y] greater/smaller/equal AGE counted in\n",
   "                                secs, minutes, hours, [D]ays, Weeks,\n",
   "                                Months, or Years\n",
   "  --num-of-to=[+|-]NUMBER       total NUMBER of person in 'To:' field\n",
   "  --num-of-cc=[+|-]NUMBER       total NUMBER of person in 'Cc:' field\n",
   "  --num-of-relay=[+|-]NUMBER    total NUMBER of 'Received:' line\n",
   "\n";
   exit 0;
}
#------------------------------<end of code>-----------------------------------
