#! /arch/unix/bin/perl5
################################################################
# $Id: mail_info,v 1.11 2000/01/15 18:17:58 danielr Exp $
################################################################
# Daniel Rinehart <danielr@ccs.neu.edu>
#
#     What this beast does:
# Report new mail / total mail for Pine mail folders
################################################################
# Other modules we need
#
use Getopt::Long;

# Setup defaults
#
my( $default_pref ) = $ENV{ "HOME" } . "/.mailinforc";

# Parse the command line
#
&GetOptions( "-help",
	     "-rcfile=s"
	   );

&usage() if ( $Getopt::Long::error || defined( $opt_help ) );

# Find the preferences file
#
my( $pref ) = defined( $opt_rcfile ) ? $opt_rcfile : $default_pref;

&usage( "Preferences file \"$pref\" not found." ) if ( ! -e $pref );

# Setup config variables
#
my( @check );

my( $busy ) = 0;
my( $separate ) = 0;
my( $toptotal ) = 0;
my( $onlynew ) = 0;

my( $sort ) = "uti";

my( %exclude ) = ();
my( @excluderegex ) = ();

# Parse the preferences file
#
open( PREF, $pref ) || die "Unable to open \"$pref\" : $!\n";

my( $line );
while ( defined( $line = <PREF> ) ) {
    chomp( $line );
    next if ( $line =~ /^\s*\#/ );

    $line =~ s/\s*$//;
    next if ( $line eq "" );

    if ( $line eq "busy" ) {
	$busy = 1;
    } elsif ( $line eq "separate" ) {
	$separate = 1;
    } elsif ( $line eq "toptotal" ) {
	$toptotal = 1;
    } elsif ( $line eq "onlynew" ) {
	$onlynew = 1;
    } elsif ( $line =~ /^sort/ ) {
	( $sort ) = ( $line =~ /sort\s(...)/ );
	&usage( "The sort option must have three values\n" )
	  if ( length( $sort ) != 3 );
    } elsif ( $line =~ /^x\s/ ) {
	my( $file ) = ( $line =~ /^x\s(.*)/ );
	$exclude{ $file } = 1;
    } elsif ( $line =~ /^X\s/ ) {
	my( $regex ) = ( $line =~ /^X\s(.*)/ );
	push( @excluderegex, $regex );
    } else {
	push( @check, $line );
    }
}      
close( PREF );

my( @cursor ) = ("|", "/", "-", "\\");
$| = 1 if ( $busy );

################################################################
# Find the folders to work on
# 
my( @folders );

my( $check );
foreach $check ( @check ) {

    if ( -d $check ) {
	opendir( MAIL, $check ) ||
	  die "Unable to open \"$check\" : $!\n";
	my( @files ) = grep( ! /^\.\.?/, readdir( MAIL ) );
	closedir( MAIL );
	
	my( $file );
	foreach $file ( @files ) {
	    next if ( $file =~ /\.lock$/i );
	    next if ( $exclude{ "$check/$file" } );
	    next if ( ! &validFolder( "$check/$file" ) );

	    print "." if ( $busy );
	    push( @folders, "$check/$file" ) if ( ! -d "$check/$file" );
	}
    } elsif ( -e $check ) {
	next if ( $exclude{ $check } );
	next if ( ! &validFolder( $check ) );

	print "." if ( $busy );
	push( @folders, $check );
    }
}

print "\r" if ( $busy );

################################################################
# Collect information on the folders
#
my( $totalnew, $totalall );
my( %new, %total );
my( $folder );
foreach $folder ( @folders ) {
    print $cursor[ 0 ] if ( $busy );

    my( $readcounter ) = 0;
    my( $totalcounter ) = 0;
    my( $counter ) = 0;

    open ( MAILFILE, $folder ) || 
      die "Unable to open mail folder \"$folder\" : $!\n";
    
    my( $line );
    my( $getStatus ) = 0;
    while ( defined( $line = <MAILFILE> )  ) {
	if ( $getStatus && $line =~ /^Status: RO/ ) {
	    $readcounter++;
	    $getStatus = 0;
	}
	if ( $line =~ /^From\s.*\s\s?[SMTWF]/ ) {
	    $totalcounter++;
	    print "\b", $cursor[ ( ++$counter % 4 ) ] 
	      if ( $busy && ! ( $totalcounter % 10 ) );
	    $getStatus = 1;
	}
	if ( $line =~ /^Subject: DON\'T DELETE THIS MESSAGE/ ) {
	    $readcounter--;
	    $totalcounter--;
	}
    }
    close ( MAILFILE );

    print "\b*" if ( $busy );

    $folder =~ s/.*\/([^\/]*)/$1/;
    if ( exists( $new{ $folder } ) ) {
	my( $folderCount ) = 2;
	while ( exists( $new{ "$folder ($folderCount)" } ) ) {
	    $folderCount++;
	}
	$folder .= " ($folderCount)";
    }
    $new{ $folder } = $totalcounter - $readcounter;
    $total{ $folder } = $totalcounter;

    next if ( $onlynew && $new{ $folder } == 0 );
    
    $totalnew += $new{ $folder };
    $totalall += $totalcounter;
}

################################################################
# Output the results
#
print "\n" if ( $busy );
$| = 0 if ( $busy );

if ( $onlynew && $totalnew == 0 ) {
    print "No new messages\n";
    exit( 0 );
}

my( @pattern );
my( $option );
foreach $option ( split( //, $sort ) ) {
    push( @pattern, &getSortPattern( $option ) );
}

eval( '@folders = sort( { ( ' . join( " ) || ( ", @pattern ) . ' ) } keys( %new ) )' );

if ( $toptotal ) {
    printf( "%4d/%4d total\n", $totalnew, $totalall );
    print "---- ----\n" if ( $separate );
}

foreach $folder ( @folders ) {
    next if ( $onlynew && $new{ $folder } == 0 );
    printf( "%4d/%4d %s\n", $new{ $folder }, $total{ $folder }, $folder );
}

if ( ! $toptotal ) {
    print "---- ----\n" if ( $separate );
    printf( "%4d/%4d total\n", $totalnew, $totalall );
}

################################################################
# Helper Functions
#
sub validFolder {
    my( $name ) = shift;
    
    my( $regex );
    foreach $regex ( @excluderegex ) {
	return( 0 ) if ( $name =~ /$regex/ );
    }
    return( 1 );
}

sub getSortPattern {
    my( $option ) = shift;
    my( $pattern );

    if ( lc( $option ) eq "u" ) {
	$pattern = '$new{ A } <=> $new{ B }';
    } elsif ( lc( $option ) eq "t" ) {
	$pattern = '$total{ A } <=> $total{ B }';
    } elsif ( lc( $option ) eq "f" ) {
	$pattern = 'A cmp B';
    } elsif ( lc( $option ) eq "i" ) {
	$pattern = 'lc( A ) cmp lc( B )';
    } else {
	&usage( "\"$option\" is not a valid sorting option." );
    }
    
    if ( lc( $option ) eq $option ) {
	$pattern =~ s/A/\$a/;
	$pattern =~ s/B/\$b/;
    } else {
	$pattern =~ s/A/\$b/;
	$pattern =~ s/B/\$a/;
    }	

    return( $pattern );
}

sub usage {
    my( $errorMessage ) = shift;

    print <<"EOT";

This is the Pine folder information program
Daniel Rinehart <danielr\@ccs.neu.edu>

The default configuration should be located at "$default_pref"

Syntax:
     One file or directory per line

Options:
     Begin a line with # to have it ignored
     Set a line to "busy" to turn on the busy indicator
     Set a line to "separate" to print a separator before the totals
     Set a line to "toptotal" to have the totals printed first
     Set a line to "onlynew" to show only folders that have new messages
     Set a line to "sort [order]" to change the sorting options
        <order> is a 3 letter combination, in any order. You must use
        one letter from each set:
        Capital letters reverse the sort order
        Either u or U - unread messages
        Either t or T - total messages
        Either f, F, i, or I - folder name (i = case insensitive )

        The order of the three options determines how items are sorted
        For example: "uti" sorts first by unread, then total, and lastly
                     folder name

   * Note x and X apply to the full path name of a folder

     Set a line to "x [filename]" to remove it from the files being searched
     Set a line to "X [regex]" to remove any files matching that regular
        expression from the files being searched
        This should be a proper Perl regular expression with special 
        characters escaped
        For example: "old" would exclude all files that contain the word old
                     "^\\/home" would exclude all files that being with /home

Command Line Usage: $0 <options>
     Command line options may be abbreviated to shortest distinct match

     -help                  This help text 

     -rcfile [filename]     Specify a different preferences file from 
                            the default

EOT

    print "\nThe following error occurred:\n$errorMessage\n\n" 
      if ( $errorMessage ne "" );
    exit( 0 );
}
