#!/usr/bin/perl
# This is arsh, the minimalist shell
#
#   $Author: tom $  $Locker: tom $  $Date: 2000/02/19 00:08:17 $
#
#          $Log: arsh,v $
#          Revision 1.2  2000/02/19 00:08:17  tom
#          added syslog support
#
#          Revision 1.1  2000/02/18 22:21:24  tom
#          Initial revision
#
#
#
use Data::Dumper;
use Term::ReadLine;
use POSIX qw(:sys_wait_h);
use Shell qw(pwd cd touch);
use Sys::Hostname;

$term = Term::ReadLine->new("arsh");

my $OUT = $term->OUT || *STDOUT;
my ($facility,$cmd,$oldcmd,$suc,%allowed_cmd,$param,$code,$req_param,$command,$ROOT,$user);
$version = "0.1.2";
$me = "arsh[$$]";

if($ENV{"TERM"} eq "")
{
	$ENV{"TERM"} = "vt100";
}
#$ENV{"DISPLAY"} = "10.0.0.3:0";
$SIG{INT} = sub {
        $term->modifying;
        $term->delete_text;
        $attribs->{point} = $attribs->{end} = 0;
        $term->redisplay;
    };
$|=1;
open CONF, "</etc/arshrc" ;#or die "Could not open arshrc!\n";
while (<CONF>)
{
     chomp;
     if($_ !~ /^#/ && $_ !~ /^\s*$/)
     {
	 if($mode == 1)
	 {
	 	($command,$param,$code,$description) = split /\s+/, $_,4;
		#$param =~ s/\(//g;
		#$param =~ s/\)//g;
		if($param =~ /^\((.*)\)\((.*)\)$/)
		{
		    $param = $1;
		    $req_param = $2;
		}
		$param .= " "; # allow whitespaces at any time!
		$allowed_cmd{$command}->[0] = $param;
		$allowed_cmd{$command}->[2] = $req_param;
		if($code =~ /\!$/)
		{
		    chop $code;
		    $allowed_cmd{$command}->[3] = 1;
		}
		$allowed_cmd{$command}->[1] = $code;
		$description =~ s/^\(//;
		$description =~ s/\)\s*$//;
		$allowed_cmd{$command}->[3] = $description;
	 }
	 else
	 {
	     ($opt,$param) = split /\s+=\s+/, $_, 2;
	     if($opt eq "___CMD___")
	     {
		 $mode = 1;
	     }
	     else
	     {
	         $option{$opt} = $param;
	     }
	 }
     }
}
if($ARGV[0] eq "-l")
{
   $log = 1;
   eval ' 
   	use Unix::Syslog qw(:macros);
	use Unix::Syslog qw(:subs);
   ';
   undef $log if (@_);
}
#print Dumper(%allowed_cmd);
#exit;
$ROOT = $ENV{"HOME"};
if(exists $option{"root"})
{
    #system("$option{'root'} $ROOT");
}

$host = hostname();
$user = $ENV{"USER"};
$histfile = "$ROOT/.arsh_history";
$optprompt = $option{"prompt"};
$term->MinLine(undef);
$term->read_history($histfile);
$attribs = $term->Attribs;
$term->bind_key(ord "\cc", 'abort');

if($log)
{
    # initial syslog message + mise en place
    openlog($me, LOG_PID | LOG_PERROR, LOG_LOCAL0);
    $log_msg = " %s\@%s:%s %s";  
}

while(1)
{
    my $prompt;
    $dir = pwd;
    chomp $dir;
    $cdir = "\033[1;34m" . $dir . "\033[0m";
    chomp $dir;
    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
    $ctime = "\033[0m$hour:$min:$sec";
    $time = "$hour:$min:$sec";
    if($option{"prompt"})
    {
	$optprompt =~ s/\$user/$user/;
	$optprompt =~ s/\$cdir/$cdir/;
	$optprompt =~ s/\$dir/$dir/;
	$optprompt =~ s/\$time/$ctime/;
	$optprompt =~ s/\$host/$host/;
	$optprompt =~ s/\\n/\n/;
	$prompt = $optprompt;
	$optprompt = "\033[0m" . $option{"prompt"};
    }
    else
    {
	$prompt = "\$ ";
    }
    
    
    $cmd = $term->readline( $prompt);
    &exit unless (defined $cmd);
    $suc = &validate($cmd);
    print $@ if($@); 
    if($suc == 1){
	if($cmd ne $oldcmd && $cmd !~ /^\s+$/) {
	    $term->addhistory($cmd);
	    if($log)
	    {
		syslog(LOG_INFO, $log_msg, $user,$host,$dir,$cmd); 
	    }
	}
	else {
	    #$term->addhistory($cmd);
	}
	$oldcmd = $cmd;
    }
}


sub validate
{
    my($cmd,$args,$params,$legal_args);
    ($cmd,$args,$params) = split /\s+/,$_[0],3;
    if($cmd =~ /^\s*$/)
    {
	return -1;
    }
    if($params eq "" && $args ne "" && $args !~ /^\-/ && $allowed_cmd{$cmd}->[3] != 1)
    {
        # no args given consider params
	$params = $args;
	$args = "";
    }
    if(exists $allowed_cmd{$cmd})
    {
	$legal_args = $allowed_cmd{$cmd}->[0];
	if($_[0] =~ /[$option{illegal_chars}]/)
	{
	    print "$0: invalid call of \"$cmd\"\n";
	    return -1;
	}
        # print Dumper($legal_args);	
	if($args !~ /^[$legal_args]*$/ && $legal_args !~ /^\*/)
	{
	    print "$0: invalid arguments to $cmd (\"$args\")!\n";
	    return -1;
	}
	
	$args .= " " . $allowed_cmd{$cmd}->[2]; # force the required arg
        
	if($cmd eq "exit" || $cmd eq "by" || $cmd eq "logout")
	{
	    &exit;
	}
	elsif($cmd eq "cd")
	{
	    &cd($cmd,$args,$params);
	}
	elsif($cmd eq "pwd")
	{
	    print pwd;
	}
	elsif($cmd eq "echo")
	{
	    if($params =~ /^\$([A-Z0-9]+)$/)
	    {
		print $ENV{$1} . "\n";
	    }
	    else
	    {
	        print $args . $params . "\n"; 
            }
	}
	elsif($cmd eq "cat")
	{
	    open FILE, "<$params" or print "Could not open $params!\n";
	    while(<FILE>)
	    {
		print $_;
	    }
	    close FILE;
	}
	elsif($cmd eq "help")
	{
	    &help;
	}
	else
	{
            &execv($cmd,$args,$params);
	}
    }
    else
    {
	print "$0: $cmd: command not found!\n";
	return -1;
    }
    return 1;
}

sub cd
{
    #print Dumper(@_);
    my($cmd,$args,$params) = (@_);
    if($args eq "--help")
    {
	print "cd: \nusage: cd [directory ... ]\n";
    }
    if($params =~ /^\s*$/)
    {
	    $params = $ENV{"HOME"};
    }
    chdir($params);
}

sub exit
{
    $term->write_history($histfile);
    closelog;
    exit;
}

sub execv
{
    my($cmd,$args,$params) = (@_);
    system("$allowed_cmd{$cmd}->[1] $args $params");
}

sub help
{
    print "$0 version $version, license: GPL Author: scip.\n\n";
    print "available commands within $0:\n";
    print "\033[1;34m-------------------------------------------------------------\033[0m\n";
    foreach (sort keys %allowed_cmd)
    {
	print "\033[1;34m" . $_ . "\033[0m ";
	print "." x (15 - length($_));
	print " " . $allowed_cmd{$_}->[3] . "\n";
    }
    print "\033[1;34m-------------------------------------------------------------\033[0m\n";
    print "Type 'command --help' to find out more about a command\n\n"
}

