#!/usr/bin/perl

# Copyright 2001-2003 Scott Jann

use Sys::Hostname;
use WWW::StockPrice;
use POSIX qw(strftime);

# set up stock prices
my %stockCache;
my %stockCacheTime;


# get defaults

my $debug = 0;
foreach my $arg (@ARGV)
{
	$debug = 1 if($arg eq '-d');
}

my $shell = (getpwuid($<))[8];
my $update = 30;
my $format = "%h: %t %d";
my $defMail;
{
	my $mailPrefix = '/var/mail';
	my $user = getpwuid $<;
	$defMail = "$mailPrefix/$user";
}



#####

sub SigHandler
{
	my ($sig) = @_;
	$| = 1;
	print "]0;Have a nice day. :)\007";
	kill TERM, 0 if($sig eq 'HUP');
	kill HUP, 0 if($sig eq 'TERM');
	exit 0;
}

sub CopyRCFile
{
	open(F, ">>$ENV{'HOME'}/.noidlerc") || return;
	print F <<"EOF";
shell		screen -R -T xterm
		# command and arguments for subprocess (default: login shell)
		# use 'screen -R -T xterm' for a screen session
update 30	# seconds between updates (default: 30)
# %h		short hostname
# %s(symbol)	stock price for symbol
# %t(x)		time (where x is 0 for 12 hr time, or 1 for 24 hr time)
#		in format hh:mm?M or hh:mm in 24 hr mode (default: 0)
# %d		date in format mm/dd/year
# %l		short system load (i.e. 1 minute average)
# %L		system load (i.e. 1, 5 and 15 minute averages)
# %m(mailbox)	mail count marked with * if there are unread messages
#		(default: /var/mail/<username>)
format %h: %t %d - %L
EOF
	close F;
	die "Please edit $ENV{'HOME'}/.noidlerc to suit your needs and rerun noidle.\n";
}

sub ReadConfig
{
	my $path = "$ENV{'HOME'}/.noidlerc";
	open(F, $path) || return(CopyRCFile);
	while(<F>)
	{
		chop;
		s/#.*//g;
		s/\s+/ /g;
		s/^\s//;
		s/\s$//;
		next if($_ eq '');
		$shell = $1 if(/^shell\s(.*)$/i);
		$update = $1 if(/^update\s(\d+)$/i && $1);
		$format = $1 if(/^format\s(.*)$/i);
	}
	close F;
}

sub GetHostname
{
	$host = hostname;

	$host =~ s/\..*$//;
	return $host;
}

sub GetTime
{
	my ($tfhr) = @_;  # 24 hour time?

	my $str;
	if($tfhr)
	{
		$str = strftime("%R", localtime(time));
	} else {
		$str = strftime("%I:%M%p", localtime(time));
	}
	return $str;
}

sub GetDate
{
	my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
		localtime(time);
	$year += 1900;
	$mon++;

	my $str = sprintf "%02d/%02d/%d",
		$mon, $mday, $year;
	return $str;
}

sub GetLoadavg
{
	my ($long) = @_;
	if(open AVG, '/proc/loadavg')
	{
		my ($load1, $load5, $load15) = split /\s/, <AVG>;
		close AVG;
		if($long)
		{
			return "$load1, $load5, $load15";
		} else {
			return "$load1";
		}
	} elsif(open AVG, 'uptime|')
	{
		my $str = <AVG>;
		close AVG;
		chop $str;
		my $avg;
		if($long)
		{
			$str =~ /load averages:\s(.*)$/i;
			$avg = $1;
		} else {
			$str =~ /load averages:\s*(\d*\.\d*)/i;
			$avg = $1;
		}
		return $avg;
	}
	return '';
}

sub GetMail
{
	my ($mail) = @_;
	$mail = $defMail if($mail eq '');
	my $count = 0;
	my $skipping = 0;
	my $blank = 1; # catch first From
	my $readMail = 0;
	if(open M, $mail)
	{
		while(<M>)
		{
			chop;
			if($_ eq '')
			{
				$blank = 1;
				next;
			}

			if($blank && /^From\s/)	
			{
				if($count == 0 && /^From\sMAILER-DAEMON\s/)
				{
					$skipping = 1;
				} else {
					$skipping = 0;
					$count++;
				}
			}

			if($skipping == 0 && /^Status:\s(\w+)/)
			{
				my $status = $1;
				$readMail++ if($status =~ /R/);
			}

			$blank = 0;
		}
		close M;
	}

	my $newMail = '';
	$newMail = '*' if($count - $readMail > 0);
	my $str = "$count$newMail";
	return $str;
}

sub GetStock
{
	my ($sym) = @_;

	my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
		localtime(time);

	if(time - $stockCacheTime{$sym} < 600)
	{
		# only refresh stock over network every 10 min
		return $stockCache{$sym} if(defined($stockCache{$sym}));
	}
	if($hour > 15 || $hour < 6 || $wday == 0 || $wday == 6) {
		# markets not open
		return $stockCache{$sym} if(defined($stockCache{$sym}));
	}
	my $price = GetStockPrice($sym);
	$price =~ /^[^:]*:\s([^\s]+)\s/;
	$stockCache{$sym} = $1;
	$stockCacheTime{$sym} = time;
	return $1;
}

sub ParseFormat
{
	my $str = $format;

	while($str =~ /%(\w)(\([^\)]*\))?/)
	{
		my $key = $1;
		my $parm = $2;
		$parm =~ s/^\(//;
		$parm =~ s/\)$//;
		my $val;
		if($key eq 'h')
		{
			$val = GetHostname;
		} elsif($key eq 't') {
			$val = GetTime($parm);
		} elsif($key eq 'd') {
			$val = GetDate;
		} elsif($key eq 'l') {
			$val = GetLoadavg;
		} elsif($key eq 'L') {
			$val = GetLoadavg(1);
		} elsif($key eq 'm') {
			$val = GetMail($parm);
		} elsif($key eq 's') {
			$val = GetStock($parm);
		} else {
			if($parm ne '')
			{
				$val = "\001$key($parm)";
			} else {
				$val = "\001$key";
			}
		}

		if($parm ne '')
		{
			$str =~ s/%$key\($parm\)/$val/;
		} else {
			$str =~ s/%$key/$val/;
		}
	}
	$str =~ s/\001/%/g;
	return $str;
}

#####

ReadConfig;

if($debug)
{
	my $str = ParseFormat;
	print "$str\n";
	exit 0;
}


# force vt100, so subprocesses don't try to set title
$ENV{'TERM'} = 'vt100';


$topPid = $$;

# spawn watcher and shell
$pid = fork();
if($pid)
{
	$pid2 = fork();
	if($pid2)
	{
		$pid3 = wait;
		$| = 1;
		print "]0;Have a nice day. :)\007";
		if($pid3 == $pid)
		{
			kill HUP, $pid2;
			kill TERM, 0;
		}
		else
		{
			kill TERM, $pid;
			kill TERM, 0;
		}
		exit 0;
	}
	exec $shell;
}

# set our term to xterm, so we can set title
$ENV{'TERM'} = 'xterm';

#$SIG{'HUP'} = 'SigHandler';
#$SIG{'TERM'} = 'SigHandler';

$| = 1; # flush
while(1)
{
	my $str = ParseFormat;
	print "]0;$str\007";
	sleep $update;
}

