#!/usr/bin/perl
# ----------------------------------------------------------------
# sysinfo for xchat
# (c) 2002,2003 Sebastian Wenzler <sickathomedotanddotdrunkdotat>
# usage : /sys [-p] [<module>] [<module>] ...
# Optional requirements: xdpyinfo, nvclock, sensors, hddtemp, lspci ;)
#
# edited by mistery <mist3ry@pandora.be> A.k.a. pittaman a.k.a Aaron Lenoir
#
# Allright, this is version two of my sysinfo script. I decided to edit 
# it again and clean up the code after I saw an edited version of my
# script on the net. I downloaded it, and copied some stuff from it
# to my own script and made it version two. You can find that script
# on: http://www.sh.nu/download/code/sysinfo.pl
#
# It says in the comments that the code is mostly stolen from here,
# but hat isn't really true anymore, as I stole from him and from Sebastian
# Wenzler.
#
# Critical change, this is xchat only. The irssi modifications had me crashing
# xchat most of the time, I'll make an irssi version of this script in the near
# future.
#
# So, nothing really new, just code clean up. For the hdd temperature checking
# you have to install a small utility hddtemp which can be found here:
# http://www.guzu.net/linux/hddtemp.php
# You have to have a SMART capable hard drive though.
#
# I did remove coloured output. Only colour you'll  see is the memory usage "graph".
#
# BTW: If you're looking for the old version, I lost it, sorry :|
#
#
# You can find the original script at: http://drunk.at/sick/download/sysinfo.pl
#
# ----------------------------GNU/GPL-----------------------------
# 
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
# ---
# Please see the file ./gpl.txt for the full license
#

my $VERSION = "2.0";


### SETTINGS HERE ###

#-- SET TO ONE FOR COLOR --#
# SET TO ONE IF YOU WANT COLOR!
my $color = 0;

# MAXIMUM ALLOWED TEXT LENGTH ON THE SERVER
my $maxtext = 500;

# S.M.A.R.T. HDD
my $SMARTDRIVE = "/dev/hda";




### YOU DON'T HAVE CHANGE ANYTHING BELOW ###

my $UNDERL_S = "\037";
my $UNDERL_E = "\037";
my $TITLE_S = "\002";
my $TITLE_E = "\002";
my $ALERT_S = "\002";
my $NORMAL_S = "";
my $ALERT_E = "\002";
my $NORMAL_E = "";

use strict;

BEGIN {
	use vars '$xchat';
	eval q {
		IRC::get_info(1);
	};
	$xchat = !$@;
}

my $procloc = "/proc";

if ( $color ) {
	$ALERT_E = "\003";
	$NORMAL_E = "\003";
	$ALERT_S = "\0034";
	$NORMAL_S = "\0033";
}

sub file_executable
{
	my $command = shift;
	my @directories=split(/:/, $ENV{'PATH'} );
	for (@directories) {
		if ( -x "$_/$command" ) { return 1; }
	}
	return 0;
}

# All available modules.

my @modules = qw /
	uname
	distro
	cpu
	mem
	hddtemp
	diskspace
	uptime
	load
	procs
	graphic
	screen
	nvidia
	netinfo
	sensors
/;

sub uname
{
	open (X, "${procloc}/version");
	my $UNAME = <X>;
	close (X);

	$UNAME =~ s/^(\S+) \S+ (\S+) .*\n$/$1 $2/;
	return "${TITLE_S}uname:${TITLE_E} ".$UNAME." ";
}

sub distro {
	my $DIST = "";
	$DIST = `cat /etc/*-version 2> /dev/null`;
	chop $DIST;
	$DIST = `cat /etc/*-release 2> /dev/null` if $DIST eq "";
	chop $DIST;
	return "${TITLE_S}Distro:${TITLE_E} " . (($DIST) ? $DIST : "Unknown") . " ";
}

sub cpu
{  
	my $NUM = 0;
	my $MIPS = 0;
	my ($MODEL,$SYSTEM);
	my $CPU = 0;

	open (X, "${procloc}/cpuinfo");
	while (<X>) {
		if (/^(cpu model|model name).*: (.*)\n$/) {
			$MODEL = $2;
			$NUM += 1;
		} elsif (/^system type.*: (.*)\n$/) {
			$SYSTEM = $1;
		} elsif (!$CPU && /^cpu MHz.*: (.*)\n$/) {
			$CPU = $1;
		} elsif (/^bogomips.*: (.*)\n$/i) {
			$MIPS += $1;
		}
	}
	close (X);

	#--SUPPORT FOR MULTIPLE PROCS--#
	if ($NUM == 2 ) { $MODEL="Dual $MODEL"; }
	if ($NUM == 4 ) { $MODEL="Quad $MODEL"; }

	$MODEL = $SYSTEM . " " . $MODEL;

	return "${TITLE_S}CPU:${TITLE_E}$MODEL $CPU MHz ${TITLE_S}Bogomips:${TITLE_E} $MIPS ";
}

sub mem
{
	my($MEMTOTAL,$MEMFREE);
	open(X, "${procloc}/meminfo") or $MEMTOTAL = 1;
	while(<X>){
		chomp;
		if(/^MemTotal:\s+(\d+)/){
			$MEMTOTAL = sprintf("%.0f",$1/1024);
		} elsif(/^MemFree:\s+(\d+)/){
			$MEMFREE = sprintf("%.0f",$1/1024);
		} elsif(/^Buffers:\s+(\d+)/){
			$MEMFREE += sprintf("%.0f",$1/1024);
		} elsif(/^Cached:\s+(\d+)/){
			$MEMFREE += sprintf("%.0f",$1/1024);
		}
	}
	
	close(X);

	#--PERCENTAGE OF MEMORY FREE--#
	my $MEMPERCENT = sprintf("%.1f",(100/${MEMTOTAL}*${MEMFREE}));

	#--BARGRAPH OF MEMORY FREE--#
	my $FREEBAR = int(${MEMPERCENT}/10);
	my $MEMBAR;
	my $x;

	$MEMBAR = "${TITLE_S}\[${NORMAL_S}";

	for ($x = 0;$x < 10; $x++) {
		if ( $x == $FREEBAR ) { $MEMBAR .= "${ALERT_S}"; }
		$MEMBAR .= "\|";
	}
	$MEMBAR .= "${ALERT_E}]${TITLE_E}";
	return "${TITLE_S}Mem:${TITLE_E} ${MEMFREE}/${MEMTOTAL}M $MEMBAR ";
}

sub diskspace
{
	#--DISKSPACE--#
	my $HDD = 0;
	my $HDDFREE = 0;
	my $SCSI = 0;
	my $SCSIFREE = 0;

	for (`df 2>/dev/null`) {
		if (/^\/dev\/(ida\/c[0-9]d[0-9]p[0-9]|[sh]d[a-z][0-9]+)\s+(\d+)\s+\d+\s+(\d+)\s+\d+%/) {
			$HDD += $2;
			$HDDFREE += $3;
		}
		if (/^\/dev\/(ida\/c[0-9]d[0-9]p[0-9]|sd[a-z][0-9]+)\s+(\d+)\s+\d+\s+(\d+)\s+\d+%/) {
			$SCSI += $2;
			$SCSIFREE += $3;
		}
	}

	my $ALL = $HDD;
	$HDDFREE = sprintf("%.02f", $HDDFREE / 1048576)."G";
	$HDD = sprintf("%.02f", $HDD / 1048576)."G";
	return "${TITLE_S}Diskspace:${TITLE_E} $HDD ${TITLE_S}Free:${TITLE_E} $HDDFREE ";
}

sub diskspace
{
	my $HDD = 0;
	my $HDDFREE = 0;
	my $SCSI = 0;
	my $SCSIFREE = 0;

	for (`df 2>/dev/null`) {
		if (/^\/dev\/(ida\/c[0-9]d[0-9]p[0-9]|[sh]d[a-z][0-9]+)\s+(\d+)\s+\d+\s+(\d+)\s+\d+%/) {
			$HDD += $2;
			$HDDFREE += $3;
		}
		if (/^\/dev\/(ida\/c[0-9]d[0-9]p[0-9]|sd[a-z][0-9]+)\s+(\d+)\s+\d+\s+(\d+)\s+\d+%/) {
			$SCSI += $2;
			$SCSIFREE += $3;
		}
	}

	my $ALL = $HDD;
	$HDDFREE = sprintf("%.02f", $HDDFREE / 1048576)."G";
	$HDD = sprintf("%.02f", $HDD / 1048576)."G";
	return "${TITLE_S}Diskspace:${TITLE_E} $HDD ${TITLE_S}Free:${TITLE_E} $HDDFREE ";
}

sub procs
{
	opendir(PROC, "${procloc}");
	my $PROCS = scalar grep(/^\d/,readdir PROC);
	return "${TITLE_S}Procs:${TITLE_E} $PROCS ";
}

sub uptime
{
	#--UPTIME--#
	open (X, "${procloc}/uptime");
	my $up2 = "";
	my $uptime = <X>;
	close (X);
	$uptime =~ s/(\d+\.\d+)\s\d+\.\d+/$1/;

	my $years = sprintf ("%.d",$uptime/31536000) || 0;
	my $yearbase = sprintf ($years * 31536000);
	my $weeks = sprintf ("%.d",($uptime - $yearbase)/6048000) || 0;
	my $weekbase = sprintf ($weeks * 6048000);
	my $days = sprintf ("%.d",($uptime - $yearbase - $weekbase)/86400) || 0;
	my $daybase = sprintf ($days * 86400);
	my $hours = sprintf ("%.d",($uptime - $yearbase - $weekbase - $daybase)/3600) || 0;
	my $hourbase = sprintf ($hours * 3600);
	my $mins = sprintf ("%.d",($uptime - $yearbase - $weekbase - $daybase - $hourbase)/60) || 0;
	my $minbase = sprintf ($mins * 60);
	my $secs = sprintf ("%.d",($uptime - $yearbase - $weekbase - $daybase - $hourbase - $minbase)) ||0;

	if ($years){$up2 .= $years =~ /^1$/ ? "$years yr " : "$years yrs ";}
	if ($weeks){$up2 .= $weeks =~ /^1$/ ? "$weeks wk " : "$weeks wks ";}
	if ($days){$up2 .= $days =~ /^1$/ ? "$days day " : "$days days ";}
	if ($hours){$up2 .= $hours =~ /^1$/ ? "$hours hr " : "$hours hrs ";}
	if ($mins){$up2 .= $mins =~/^[01]$/ ? "$mins min " : "$mins mins ";}

	$up2 .= $secs =~ /^[01]$/ ? "$secs sec" : "$secs secs";
	return "${TITLE_S}Uptime:${TITLE_E} $up2 ";
}

sub load()
{
	if (open (X, "${procloc}/loadavg")) {
		my $LOADAVG = <X>;
		close (X);
		$LOADAVG =~ s/^((\d+\.\d+\s){3}).*\n$/$1/;
		return "${TITLE_S}Load:${TITLE_E} $LOADAVG ";
	}
}

sub graphic()
{
	#--GRAPHICSCARD--#

	my $VGA = "unknown";
	if (file_executable("lspci") == 1) {
		for (`lspci 2>/dev/null`) {
			if (/VGA compatible controller:\s(.*)$/) { $VGA = $1; }
		}
	}
	elsif ( -e "${procloc}/pci" ) {
		open(X, "${procloc}/pci") ;
		while(<X>){
			chomp;
			if (/VGA compatible controller:\s(.*)\.$/){
			$VGA = $1; }
		}
	close(X);
	}

	return "${TITLE_S}Graphic:${TITLE_E} ${VGA} ";
}

sub screen
{
	#--SCREEN RESOLUTION--#
 
	my ($DEPTH,$RES);
	if (file_executable("xdpyinfo")) {
		for(`xdpyinfo 2>/dev/null`) {
			if(/\s+dimensions:\s+(\S+)/) {
				$RES = $1;
			} elsif(/\s+depth:\s+(\S+)/) {
				$DEPTH = $1;
			}
		}
		if ($DEPTH) { return "${TITLE_S}Screen:${TITLE_E} $RES ($DEPTH bpp) "; }
	}
}

sub nvidia
{
	my $NVCLOCK;
	if (file_executable("nvclock") == 1) {
		for (`nvclock -s 2>/dev/null`) {
			if (/^C.*ore speed:\s+(\d+\.\d+\sMHz)$/) { $NVCLOCK = $1; }
		}
	return "${TITLE_S}Corespeed:${TITLE_E} $NVCLOCK";
    }
}

sub netinfo
{
	my $route = "";
	my $netdev = "";
	my $NETDEVICE = "lo";

	open(X, "${procloc}/net/route") or $route = "NA";
	while(<X>){
		chomp;
		if (/^(.*?)\s+\d+\s+.*\s+0003\s+\d\s+/) { $NETDEVICE = $1; }
	}

	close(X);

	my $PACKIN;
	my $PACKOUT;

	if (open(X, "${procloc}/net/dev")) {
		while(<X>) {
			chomp;
			if (/^(\s+)?$NETDEVICE/) {
				/^\s+(.*?):(\s+|)(\d+)\s+\d+\s+\d+\s+\d+\s+\d+\s+\d+\s+\d+\s+\d+\s+(\d+)\s+/;
				$PACKIN = sprintf("%.2f",$3 / 1048576);
				$PACKOUT = sprintf("%.2f",$4 / 1048576);
			}
		}
		close(X);
		if($PACKIN < 1024) { $PACKIN .= "M"; } else { $PACKIN = sprintf("%.02f", $PACKIN / 1024)."G"; }
		if($PACKOUT < 1024) { $PACKOUT .= "M"; } else { $PACKOUT = sprintf("%.02f", $PACKOUT / 1024)."G"; }
		return "${TITLE_S}Netinfo:${TITLE_E} ${TITLE_S}$NETDEVICE${TITLE_E}: In:${TITLE_E} $PACKIN ${TITLE_S}Out:${TITLE_E} $PACKOUT";
	}
}

sub sensors
{
	my $SENSOR1 = "NA";
	my $SENSOR2 = "NA";
	my $SENSOR3 = "NA";
	my $SENSOR4 = "NA";
	if ( -e "${procloc}/sys/dev/sensors" && file_executable("sensors") == 1) {
		for (`sensors 2>/dev/null`){
			if (/^[tT]emp2.*:\s+(.*(\s|.|)[FC])\s+\(.*\)(\s+ALARM)?/) {
				if (!$2) { $SENSOR1 = "${NORMAL_S} $1${NORMAL_E}"; } 
				else { $SENSOR1 = "${ALERT_S} $1${ALERT_E}"; }
			} elsif (/^[tT]emp1.*:\s+(.*(\s|.|)[FC])\s+\(.*\)(\s+ALARM)?/) {
				if (!$2) { $SENSOR2 = "${NORMAL_S} $1${NORMAL_E}"; } 
				else { $SENSOR2 = "${ALERT_S} $1${ALERT_E}"; }
			} elsif (/^fan1:\s+(\d+\sRPM)\s+\(.*\)(\s+ALARM)?/) {
				if (!$2) { $SENSOR3 = "${NORMAL_S} $1${NORMAL_E}"; } 
				else { $SENSOR3 = "${ALERT_S} $1${ALERT_E}"; }
			} elsif (/^fan2:\s+(\d+\sRPM)\s+\(.*\)(\s+ALARM)?/) {
				if (!$2) { $SENSOR4 = "${NORMAL_S} $1${NORMAL_E}"; } 
				else { $SENSOR4 = "${ALERT_S} $1${ALERT_E}"; }
			}
	}

	return "${TITLE_S}CPU:${TITLE_E}$SENSOR1 ${TITLE_S}Fan:${TITLE_E}$SENSOR3 ${TITLE_S}Case:${TITLE_E}$SENSOR2 ${TITLE_S}Fan:${TITLE_E}$SENSOR4 ";
}

sub hddtemp
{
	my $HDDTEMP;
	if ( file_executable("hddtemp") == 1) {
		for (`hddtemp $SMARTDRIVE 2>/dev/null`) {
			if (/^\/dev\/[sh]da:\s+(.*):\s+(.*)$/) {
				$HDDTEMP = $2;
			}
		}
	return "${TITLE_S}HDD:${TITLE_E} $HDDTEMP "; 
	}
}

sub print_help
{
	my $modlist = "";
	my $len = @modules;
	my $c = 0;
	foreach my $arg(@modules) {
		if($c == ($len - 1)) {
			$modlist .= "and $arg.";
		} elsif($c == ($len - 2)) {
			$modlist .= "$arg ";
		} else {
			$modlist .= "$arg, ";
		}
		$c++;
	}
	IRC::print ("Usage: /sys [-h] [-p] [<module>] [<modules>] ...");
    IRC::print ("-h: help");
    IRC::print ("-p: Print public! (/say in current channel)");
    IRC::print ("\002Available modules:\002 $modlist");
}

sub display_sys_info_ {
	my $args = shift;
	my $a = 0;
	my $temp;
	my @lines;
	my $count = 0;
	my $title = "${UNDERL_S}SysInfo:${UNDERL_E} ";
	my $output;

	if ($args =~ m/-h/) {
		print_help();
		return 1;
	} 

	$lines[$count] = $title;
   
	foreach my $arg (@modules) {
		if ($args eq "" || $args =~ m/^-p$/ || $args =~ m/$arg/) {
			$a = 1;
			$temp = eval $arg;
			$count++ if length ($lines[$count]) > $maxtext;
			$lines[$count] .= $temp;
		}
	}
   
	if ($a == 0) {
		return 1;
	}

	$output = 1 if ($args !~ m/-p/);
	if ($xchat && $lines[0] ne $title) {
		if ($output) {
			IRC::print ($_) for @lines;
		} else {
			IRC::command ($_) for @lines;
		}
	}

	return 1;

	}
}

#--END OF SUB--#

if($xchat) {
	IRC::register("Sysinfo", "${VERSION}.0", "System info script", "System info script");
	IRC::print ("Loading mistery's \0034sysinfo\003 script (original by sick boy)");
	print_help();
	IRC::add_command_handler("sys", "display_sys_info_");
} else {
	display_sys_info();
}

