#!/usr/bin/perl
#< Interactive shell demonstration script
# This script can be used to create console interfaces to your scripts and applications

# Current functionality has been incorporated for a RHEL4 AS box, and will grab system
# information, as well as send mail. Possibilities for this kind of script are
# limitless.

use strict;
use warnings;
use Net::SMTP;

our $DEBUG = 0;

our %keywords = ( "help",               "",
                 "sysinfo",            "",
                 "mail",               "",
                 "test",               "",
                 "quit",               "" );

our $prompt = '$> ';

sub print_err {
  # print_err expects two arguments
  if ( scalar(@_) != 2 ) {
     printf( "Incorrect usage of print_err()\n" );
  } else {
     my $error_type = $_[0];
     my $error_data = $_[1];
     SWITCH: for ( $error_type ) {
        /NOT_IMPL/  && do {
                       printf( STDERR "Error (%s) - Command not implemented: %s\n", $error_type, $error_data );
                       last;
                    };
        /ARG_ERR/  && do {
                       printf( STDERR "Error (%s) - Incorrect number of arguments for command: %s\n", $error_type,
                               $error_data );
                       last;
                    };
        /NON_NUM/  && do {
                       printf( STDERR "Error (%s) - Numeric argument expected: %s\n", $error_type,
                               $error_data );
                       last;
                    };
        /UNK_OPT/  && do {
                       printf( STDERR "Error (%s) - Unknown option: %s\n", $error_type,
                               $error_data );
                       last;
                    };
        /NOT_EXEC/  && do {
                       printf( STDERR "Error (%s) - %s: Cannot execute\n", $error_type,
                               $error_data );
                       last;
                    };
        /NOT_FOUND/ && do {
                       printf( STDERR "Error (%s) - %s: File not found\n", $error_type,
                               $error_data );
                       last;
                    };
        printf( STDERR "Error: Unknown error type (%s)\nError text: %s\n", $error_type, $error_data );
     }
  }
}

sub display_help {
 # the test command will remain undocumented here
print <<END
---------------
Command Summary
---------------

help            - Display this help message
mail            - Interactive mailer (single recipient only)
sysinfo         - System Information (sysinfo -h for usage information)
quit            - Exit the shell

END
}

sub sysinfo_help {
    print <<END_OF_SYSINFO_HELP
-----------------------
sysinfo Command Summary
-----------------------

If the output scrolls off your terminal, try
<sysinfo command here> | pager

sysinfo cpu              - Display CPU information
sysinfo disk             - Display disk utilisation information
sysinfo mem              - Display memory infromation
sysinfo interfaces       - Show network interface confuration
sysinfo hostname         - Display system hostname
sysinfo routing          - Display kernel routing table
sysinfo uptime           - Display system load and uptime
sysinfo [help|-h|--help] - Display this help message

END_OF_SYSINFO_HELP
}

sub display_sysinfo {
 my ( @cmd_array ) = @_;
 if ( !defined( $cmd_array[1] ) ||
      ( defined( $cmd_array[1] ) && ( $cmd_array[1] eq "help" || $cmd_array[1] eq "-h" || $cmd_array[1] eq "--help"  ) ) ) {
    &sysinfo_help();
 } else {
    if ( !defined ( $cmd_array[1] ) ) {
       # sysinfo with no arguments
    } elsif ( $cmd_array[1] eq "hostname" ) {
      my $hostname_cmd = "/bin/hostname";
      if ( ! -e "$hostname_cmd" ) {
         print_err( "NOT_FOUND", "$hostname_cmd" );
      } elsif ( ! -x "$hostname_cmd" ) {
         print_err( "NOT_EXEC", "$hostname_cmd" );
      } else {
         system( "$hostname_cmd" );
      }
    } elsif ( $cmd_array[1] eq "cpu" ) {
       my $cpu_cmd = "/usr/sbin/x86info";
       if ( ! -e "$cpu_cmd" ) {
          print_err( "NOT_FOUND", "$cpu_cmd" );
       } elsif ( ! -x "$cpu_cmd" ) {
          print_err( "NOT_EXEC", "$cpu_cmd" );
       } else {
          if ( defined($cmd_array[2]) && defined($cmd_array [3]) &&
               $cmd_array[2] eq "|" && $cmd_array[3] eq "pager" ) {
             my $pager = "/bin/more";
             if ( ! -e "$pager" ) {
                print_err( "NOT_FOUND", "$pager" );
             } elsif ( ! -x "$pager" ) {
                print_err( "NOT_EXEC", "$pager" );
             } else {
                system( "$cpu_cmd | $pager" );
             }
          } else {
             system( "$cpu_cmd" );
          }
       }
    } elsif ( $cmd_array[1] eq "mem" ) {
       my $mem_cmd = "/usr/bin/free";
       if ( ! -e "$mem_cmd" ) {
          print_err( "NOT_FOUND", "$mem_cmd" );
       } elsif ( ! -x "$mem_cmd" ) {
          print_err( "NOT_EXEC", "$mem_cmd" );
       } else {
          $mem_cmd .= " -m";
          if ( defined($cmd_array[2]) && defined($cmd_array [3]) &&
               $cmd_array[2] eq "|" && $cmd_array[3] eq "pager" ) {
             my $pager = "/bin/more";
             if ( ! -e "$pager" ) {
                print_err( "NOT_FOUND", "$pager" );
             } elsif ( ! -x "$pager" ) {
                print_err( "NOT_EXEC", "$pager" );
             } else {
                system( "$mem_cmd | $pager" );
             }
          } else {
             system( "$mem_cmd" );
          }
       }
    } elsif ( $cmd_array[1] eq "disk" ) {
       my $disk_cmd = "/bin/df";
       if ( ! -e "$disk_cmd" ) {
          print_err( "NOT_FOUND", "$disk_cmd" );
       } elsif ( ! -x "$disk_cmd" ) {
          print_err( "NOT_EXEC", "$disk_cmd" );
       } else {
          $disk_cmd .= " -h";
          if ( defined($cmd_array[2]) && defined($cmd_array [3]) &&
               $cmd_array[2] eq "|" && $cmd_array[3] eq "pager" ) {
             my $pager = "/bin/more";
             if ( ! -e "$pager" ) {
                print_err( "NOT_FOUND", "$pager" );
             } elsif ( ! -x "$pager" ) {
                print_err( "NOT_EXEC", "$pager" );
             } else {
                system( "$disk_cmd | $pager" );
             }
          } else {
             system( "$disk_cmd" );
          }
       }
    } elsif ( $cmd_array[1] eq "uptime" ) {
       my $up_cmd = "/usr/bin/uptime";
       if ( ! -e "$up_cmd" ) {
          print_err( "NOT_FOUND", "$up_cmd" );
       } elsif ( ! -x "$up_cmd" ) {
          print_err( "NOT_EXEC", "$up_cmd" );
       } else {
          if ( defined($cmd_array[2]) && defined($cmd_array [3]) &&
               $cmd_array[2] eq "|" && $cmd_array[3] eq "pager" ) {
             my $pager = "/bin/more";
             if ( ! -e "$pager" ) {
                print_err( "NOT_FOUND", "$pager" );
             } elsif ( ! -x "$pager" ) {
                print_err( "NOT_EXEC", "$pager" );
             } else {
                system( "$up_cmd | $pager" );
             }
          } else {
             system( "$up_cmd" );
          }
       }
    } elsif ( $cmd_array[1] eq "interfaces" ) {
       my $net_cmd = "/sbin/ifconfig";
       if ( ! -e "$net_cmd" ) {
          print_err( "NOT_FOUND", "$net_cmd" );
       } elsif ( ! -x "$net_cmd" ) {
          print_err( "NOT_EXEC", "$net_cmd" );
       } else {
          $net_cmd .= " -a";
          if ( defined($cmd_array[2]) && defined($cmd_array [3]) &&
               $cmd_array[2] eq "|" && $cmd_array[3] eq "pager" ) {
             my $pager = "/bin/more";
             if ( ! -e "$pager" ) {
                print_err( "NOT_FOUND", "$pager" );
             } elsif ( ! -x "$pager" ) {
                print_err( "NOT_EXEC", "$pager" );
             } else {
                system( "$net_cmd | $pager" );
             }
          } else {
             system( "$net_cmd" );
          }
       }
    } elsif ( $cmd_array[1] eq "routing" ) {
       my $route_cmd = "/bin/netstat";
       if ( ! -e "$route_cmd" ) {
          print_err( "NOT_FOUND", "$route_cmd" );
       } elsif ( ! -x "$route_cmd" ) {
          print_err( "NOT_EXEC", "$route_cmd" );
       } else {
          $route_cmd .= " -rn";
          if ( defined($cmd_array[2]) && defined($cmd_array [3]) &&
               $cmd_array[2] eq "|" && $cmd_array[3] eq "pager" ) {
             my $pager = "/bin/more";
             if ( ! -e "$pager" ) {
                print_err( "NOT_FOUND", "$pager" );
             } elsif ( ! -x "$pager" ) {
                print_err( "NOT_EXEC", "$pager" );
             } else {
                system( "$route_cmd | $pager" );
             }
          } else {
             system( "$route_cmd" );
          }
       }
    } else {
       &sysinfo_help();
    }
 }
}

# test_command() - this is a simple demonstration of how a command could be handled....
# "two" arguments may be passed - -t and a numeric argument, e.g.
# test -t 30
sub test_command {
  # Single argument, an erray, will be passed
  my ( @cmd_array ) = @_;
  if ( $DEBUG ) {
     printf( "--(DEBUG)--> \@cmd_array contains %d elements\n", scalar(@cmd_array) );
  }
  if ( scalar(@cmd_array) != 3 ) {
     print_err( "ARG_ERR", "test" );
  } else {
     if ( $cmd_array[1] eq "-t" ) {
        my $testarg = $cmd_array[2];
        if ( $testarg !~ /^[0-9]+/ ) {
           print_err( "NON_NUM", "test -t $testarg" );
        } else {
           printf( "test command called with -t and a timeout of %d\n", $testarg );
        }
     } else {
           print_err( "UNK_OPT", "Unknown option $cmd_array[1]" );
     }
  }
}

sub send_mail {
  if ( scalar(@_) != 1 ) {
     print_err( "ARG_ERR", "mail" );
  } else {
     printf( "-- Enter SMTP Gateway: " );
     chomp( my $smtp_gateway = <STDIN> );
     if ( "$smtp_gateway" =~ /^[\s]*$/ ) {
        printf( STDERR "--> No SMTP Gateway specified. Aborting...\n" ) && return;
     }
     printf( "-- Enter HELO String: " );
     chomp( my $hello = <STDIN> );
     if ( "$hello" =~ /^[\s]*$/ ) {
        printf( STDERR "--> No HELO String specified. Aborting...\n" ) && return;
     }
     printf( "-- Enter Sender Address: " );
     chomp( my $mail_from = <STDIN> );
     if ( "$mail_from" =~ /^[\s]*$/ ) {
        printf( STDERR "--> No Sender Address specified. Aborting...\n" ) && return;
     }
     printf( "-- Enter Recipient Address: " );
     chomp( my $mail_to = <STDIN> );
     if ( "$mail_to" =~ /^[\s]*$/ ) {
        printf( STDERR "--> No Recipient Address specified. Aborting...\n" ) && return;
     }
     my $smtp = Net::SMTP->new( "$smtp_gateway",
                                Hello => "$hello",
                                Timeout => 30,
                                Debug => "$DEBUG",
                              ) or die "Error: Cannot create mail object: $!";
    $smtp->mail("$mail_from");
    $smtp->to("$mail_to");
    $smtp->data();
    printf( "-- Enter Subject: " );
    chomp( my $subject = <STDIN> );
    # We allow empty subject lines
    $smtp->datasend("Subject: $subject\n");
    # No need CC nor BCC
    printf( "-- Enter your message. After last line of input, enter a period \".\"\n" );
    printf( "-- by itself on the final line, and hit enter\n" );
    my $input_string = "";
    while ( 1 ) {
       chomp( $input_string = <STDIN> );
       if ( $input_string =~ /^\.$/ ) {
          $smtp->dataend();
          $smtp->quit;
          printf( "-- Your message has been sent to the SMTP server.\n" );
          return;
       }
       $smtp->datasend("$input_string\n");
    }
 }
}

sub main_routine {
  printf( "%s", $prompt );
  while ( <> ) {
     chomp( my $input = $_ );
     # translate tab to space
     $input =~ s/\t/ /g;
     # squash duplicate spaces
     $input =~ tr/ //s;
     # remove leading spaces
     $input =~ s/^[ ]*//;
     # and traling spaces
     $input =~ s/[ ]*$//;
     if ( $DEBUG ) {
        printf( STDERR "--(DEBUG)--> %s\n", $input );
     }
     my @input_array = split( /[ ]/, $input );
     my $input_command = $input_array[0];
     printf( "%s", $prompt) and next if ( !defined($input_command) );
     if ( !defined($keywords{$input_command}) ) {
        my $error_data="$input_command";
        print_err( "NOT_IMPL", $error_data );
     }
     SWITCH: for ( $input_command ) {
         /test/        && do {
                          &test_command( @input_array );
                          last;
                       };
         /sysinfo/     && do {
                          &display_sysinfo( @input_array );
                          last;
                       };
         /mail/        && do {
                          &send_mail( @input_array );
                          last;
                       };
         /help/        && do {
                          &display_help();
                          last;
                       };
         /quit/        && do {
                          return;
                          last;
                       };
     }
     printf( "%s", $prompt );
  }
}

&main_routine();

exit 0