package Client::System;
use Inventory;
use Logic::Ethers;
use strict;
use Client;

# 
# works with System1/maserati/Unity
#

sub inventory {
  my($q) = @_;
 
  my $inv = Inventory->readInventory();

  print Client->http_OK();

  print $inv->toXML();

}

#
# Initialize/Set up directories/permission
# for the Web server/UI as this one is running 
# as noaccess as is not allowed to perform
# these steps.
#
sub init {
  system("/usr/bin/ln -s /opt/SUNWstade/DATA/Download/ /var/opt/webconsole/webapps/storade/Download");
  system("/usr/bin/ln -s /var/crash /var/opt/webconsole/webapps/storade/Crash");
  # even if we redirect http request from 'storade' to 'se6920ui', Lockhart seems to check
  # first if the file is present before doing a request for the file
  # so create links to the se6920ui directories to avoid this problem.
  system("/usr/bin/ln -s /var/opt/webconsole/webapps/se6920ui/html/en/help/ /var/opt/webconsole/webapps/storade/html/en/help");
  system("/usr/bin/ln -s /var/opt/webconsole/webapps/se6920ui/html/fr/help/ /var/opt/webconsole/webapps/storade/html/fr/help");
  system("/usr/bin/ln -s /var/opt/webconsole/webapps/se6920ui/html/ja/help/ /var/opt/webconsole/webapps/storade/html/ja/help");
  system("/usr/bin/ln -s /var/opt/webconsole/webapps/se6920ui/html/ko/help/ /var/opt/webconsole/webapps/storade/html/ko/help");
  system("/usr/bin/ln -s /var/opt/webconsole/webapps/se6920ui/html/zh_CN/help/ /var/opt/webconsole/webapps/storade/html/zh_CN/help");
  system("/usr/bin/ln -s /var/opt/webconsole/webapps/se6920ui/html/zh_TW/help/ /var/opt/webconsole/webapps/storade/html/zh_TW/help");
  print Client->http_OK();
  print "OK";
}

sub trays {
  my($q) = @_;
  my($renv, $devs) = PDM::ConfigFile->read();
  my %D;
  print Client->http_OK();
  my $summary;
  foreach my $d (@$devs) {
     $D{$d->{name}} = $d;
     if ($d->{type} eq "se2") {
       $summary = "$d->{type}:$d->{key}";
     }
  }

  print "<SYSTEM>\n";
  print " <SYSTEM_ID>$renv->{cust_no}</SYSTEM_ID>\n";
  print " <SUMMARY>$summary</SUMMARY>\n";
  print " <RACK ID=\"0\">\n";
  my $tray_max = 12;
  my $offset = 0;
  if ($renv->{solution_model} eq "6940"){
     $tray_max = 14;
     $offset = 2;
  }
  print "   <TRAY_MAX>$tray_max</TRAY_MAX>\n";

  my($id, $t, $rack);
  my $lastrack = "0";
  my $tray = 1 + $offset;
  my $hostid = System->hostid();
  my $order;

  $id++;
  $order = 12 + $offset;
  print "   <TRAY NO=\"$id\">\n";
  print "     <NAME>sp</NAME>\n";
  print "     <KEY>sp:$hostid</KEY>\n";
  print "     <ORDER>$order</ORDER>\n";
  print "     <DISPLAYTYPE>Service Processor</DISPLAYTYPE>\n";
  print "     <TRAYID>SP Tray</TRAYID>\n";
  print "     <RACK>0</RACK>\n";
  print "   </TRAY>\n";

  if ($renv->{solution_model} eq "6940"){

     $id++;
     $order = 11 + $offset;
     foreach my $d0 (sort keys %D) {
        my $d = $D{$d0};
        if ($d->{type} eq "ntc") {
          print "   <TRAY NO=\"$id\">\n";
          print "     <NAME>$d->{name}</NAME>\n";
          print "     <IP>$d->{ipno}</IP>\n";
          print "     <KEY>ntc:$d->{key}</KEY>\n";
          print "     <ORDER>$order</ORDER>\n";
          print "     <TRAYID>NTC Tray</TRAYID>\n";
          print "     <DISPLAYTYPE>NTC Tray</DISPLAYTYPE>\n";
          print "     <RACK>0</RACK>\n";
          print "   </TRAY>\n";
        }
     }



     $id++;
     $order = 10 + $offset;
     print "   <TRAY NO=\"$id\">\n";
     print "     <NAME>e-switch</NAME>\n";
     print "     <ORDER>$order</ORDER>\n";
     print "     <TRAYID>Ethernet Tray</TRAYID>\n";
     print "     <DISPLAYTYPE>Ethernet SWITCH</DISPLAYTYPE>\n";
     print "     <RACK>0</RACK>\n";
     print "   </TRAY>\n";

     my $power_order = 1;
     foreach my $d0 (sort keys %D) {
        my $d = $D{$d0};
        if ($d->{type} eq "pseq") {
	  next if($d->{name} !~ /psq0/); #Skip power of other racks.
          $id++;
          print "   <TRAY NO=\"$id\">\n";
          print "     <NAME>$d->{name}</NAME>\n";
          #print "     <IP>$d->{ipno}</IP>\n";
          #print "     <KEY>$summary</KEY>\n";
          print "     <KEY>pseq:$d->{key}</KEY>\n";

          print "     <ORDER>$power_order</ORDER>\n";
          print "     <TRAYID>Power Sequencer</TRAYID>\n";
          print "     <DISPLAYTYPE>Power Sequencer</DISPLAYTYPE>\n";
          print "     <RACK>0</RACK>\n";
          print "   </TRAY>\n";
	  $power_order++;

        }
     }

  }else{
     $id++;
     print "   <TRAY NO=\"$id\">\n";
     print "     <NAME>spatray</NAME>\n";
     print "     <ORDER>11</ORDER>\n";
     print "     <KEY>spatray:spatray</KEY>\n";
     print "     <TRAYID>SPA Tray</TRAYID>\n";
     print "     <DISPLAYTYPE>SPA Tray</DISPLAYTYPE>\n";
     print "     <RACK>0</RACK>\n";
     print "   </TRAY>\n";

     $id++;
     print "   <TRAY NO=\"$id\">\n";
     print "     <NAME>hub</NAME>\n";
     print "     <ORDER>10</ORDER>\n";
     print "     <TRAYID>HUB Tray</TRAYID>\n";
     print "     <DISPLAYTYPE>Ethernet HUB</DISPLAYTYPE>\n";
     print "     <RACK>0</RACK>\n";
     print "   </TRAY>\n";



  }

  foreach my $d0 (sort keys %D) {
      my $d = $D{$d0};
      if ($d->{type} eq "dsp") {
          $id++;
	  $order = 9 + $offset;
          print "   <TRAY NO=\"$id\">\n";
          print "     <NAME>$d->{name}</NAME>\n";
          print "     <IP>$d->{ipno}</IP>\n";
          print "     <KEY>dsp:$d->{key}</KEY>\n";
          print "     <ORDER>$order</ORDER>\n";
          print "     <TRAYID>DSP Tray</TRAYID>\n";
          print "     <DISPLAYTYPE>Data Services Platform</DISPLAYTYPE>\n";
          print "     <RACK>0</RACK>\n";
          print "   </TRAY>\n";
      }
  }
  my $racktray = 1;
  foreach my $d0 (sort keys %D) {
      my $d = $D{$d0};
      next if (index(",6140,6020,6120,t3,csm200,", ",$d->{type},") < 0);
      my $n = $d->{name};
      $n =~ /array(\d+)/;
      $rack = substr($1,0,1);
      $rack = 0 if(!$rack);
      if ($rack ne $lastrack) {
          print " </RACK>\n";
          $lastrack = $rack;
	  $tray = ($rack*$tray_max) + 1;
	  $racktray = 1;
          print " <RACK ID=\"$rack\">\n";
          print "   <TRAY_MAX>$tray_max</TRAY_MAX>\n";
	  if ($renv->{solution_model} eq "6940"){
	    # Must add in Power Sequencers for this rack
	    $id++;
	    my $ps0 = "psq${rack}0";
	    my $ps1 = "psq${rack}1";
            print "   <TRAY NO=\"$id\">\n";
            print "     <NAME>$ps0</NAME>\n";
            #print "     <IP>$d->{ipno}</IP>\n";
            print "     <KEY>$summary</KEY>\n";
            print "     <ORDER>$tray</ORDER>\n";
            print "     <TRAYID>Power Sequencer</TRAYID>\n";
            print "     <DISPLAYTYPE>Power Sequencer</DISPLAYTYPE>\n";
            print "     <RACK>$rack</RACK>\n";
            print "   </TRAY>\n";
	    $tray++;
	    $racktray++;
	    $id++;

	    print "   <TRAY NO=\"$id\">\n";
            print "     <NAME>$ps1</NAME>\n";
            #print "     <IP>$d->{ipno}</IP>\n";
            print "     <KEY>$summary</KEY>\n";
            print "     <ORDER>$tray</ORDER>\n";
            print "     <TRAYID>Power Sequencer</TRAYID>\n";
            print "     <DISPLAYTYPE>Power Sequencer</DISPLAYTYPE>\n";
            print "     <RACK>$rack</RACK>\n";
            print "   </TRAY>\n";
	    $tray++;
	    $racktray++;
          }
      }
      my $tray_cnt = $d->{units}||1;
      for ($t=1; $t <= $tray_cnt; $t++) {
          $id++;
          print "   <TRAY NO=\"$id\">\n";
          print "     <NAME>$d->{name}</NAME>\n";
          print "     <IP>$d->{ipno}</IP>\n";
          print "     <KEY>$d->{type}:$d->{key}</KEY>\n";
          print "     <TRAYID>Cabinet $rack Tray $racktray</TRAYID>\n";
          print "     <ORDER>$tray</ORDER>\n";
          print "     <DISPLAYTYPE>Storage Array</DISPLAYTYPE>\n";
          print "     <RACK>$rack</RACK>\n";
          print "     <UNIT>u$t</UNIT>\n";
          print "   </TRAY>\n";
          $tray++;
	  $racktray++;
      }
  }
  print "  </RACK>\n";
  print "</SYSTEM>\n";

}

sub ejectCD {
  my($q) = @_;

  if (-x "/usr/bin/eject") {
    print Client->http_OK();

    my $com = "/usr/bin/eject";
    my $rc = `$com 2>&1`;

    print "<COMMAND>\n";
    print "  <VALUE>$com</VALUE>\n";
    print "  <RESULT>$rc</RESULT>\n";
    print "</COMMAND>\n";

  } else {
     print Client->error("xml", 202, "Cannot execute command");
  }

}

################################################
#  CORE FILES
################################################

#
# A HUGE hack to handle dsp core files
# which include special characters
#
sub processCoreFiles {
  my $dir = "/var/crash/dsp00";
  opendir(DIR,$dir);
  my (@filenames) = readdir(DIR);
  for (@filenames) {
    my $a = $_;

    # Bug 6300081
    # see http://www.unicode.org/charts/

    # dsp core files seem to include the unicode
    # characters below. Remove them, otherwise
    # the XML parser will complain and we will also
    # have problems deleting these files!

    $a =~ s/[\x04]//g;
    $a =~ s/[\x18]//g;
    $a =~ s/[\xDC]//g;
    $a =~ s/[\xBB]//g; 
    my $f1 = $dir."/".$_;
    my $f2 = $dir."/".$a;

    rename($f1, $f2);
  }
}

sub coreList {
  my($q) = @_;

  &processCoreFiles();

  print Client->http_OK();
  require Service::Core;
  my $L = Service::Core::core_list();

  # make the directory rx by other than root
  # since Lockhart runs as noaccess and we want 
  # to enable direct access from Lockhart.
  foreach my $e (@$L) {
     my($id, $relative, $dev, $time, $path) = @$e;
     my $dir = "/var/crash/".$dev;
     system("/usr/bin/chmod a+rx $dir");
  }

  print "<COREFILES>\n";
  foreach my $e (@$L) {
     my($id, $relative, $dev, $time, $path) = @$e;
     $id = Client->xmlEncode($id);
     $relative = Client->xmlEncode($relative);
     $dev = Client->xmlEncode($dev);
     $path = Client->xmlEncode($path);
     print <<EOF;
  <CORE>
    <FILE>$id</FILE>
    <RELATIVE>$relative</RELATIVE>
    <DEVICE>$dev</DEVICE>
    <TIME>$time</TIME>
    <NAME>$path</NAME>
  </CORE>
EOF
  }

  print "</COREFILES>\n";
}

#
#  System::coreDelete&file=<filename>
#
sub coreDelete {
  my($q) = @_;

  require Service::Core;
  my $base = Service::Core->coreBase();
  
  if ($q->{file} && substr($q->{file}, 0, length($base)) eq $base) {
     print Client->http_OK();
     unlink $q->{file};
     my $file = Client->xmlEncode($q->{file});
     print "<DELETED>$file</DELETED>\n";

  } else {
     print Client->error("xml", 301, "Invalid core file: $q->{file}");
  }
}


###################################################
# SOLUTION EXTRACT
###################################################
#
sub extractStart {
  my($q) = @_;
  my $pass = $q->{password} ; # optional
  require Service::Extract;
  if (Service::Extract::start($q)) {
     print Client->http_OK();
     print "<STARTED>Solution Extract</STARTED>";
  } else {
     print Client->error("xml", 302, "Error: Solution Extract already running");
  }
}

sub extractList {
  my($q) = @_;
  require Service::Extract;
  my $L = Service::Extract::list();

  print Client->http_OK();
  print "<EXTRACTS>\n";
  print Client->xmlHashList("EXTRACT", $L);
  print "</EXTRACTS>\n";
}

#
#  extractDelete&file=<download_url>
#
sub extractDelete {
  my($q) = @_;
  require Service::Extract;
  my $D = System->get_home() . "/DATA";
  if (-f "${D}$q->{file}") {
     print Client->http_OK();
     system("/usr/bin/rm -rf ${D}$q->{file}");
     # if the directory has been expanded, delete it too
     my $index = rindex($q->{file}, ".tar");
     my $dir = substr($q->{file},0,$index);
     my $log = $dir . ".txt";
     $log =~ s/extract_/log_/;

     my $dir1 = "/var/opt/SUNWstade/DATA$dir";
     system("/usr/bin/rm -rf $dir1");
     # remove the log file
     system("/usr/bin/rm -rf ${D}$log");

     print "<DELETED>$q->{file}</DELETED>\n";
  } else {
     print Client->error("xml", 303, "Cannot delete $q->{file}: $!");
  }
}


sub logfile {
  my($q) = @_;
  print Client->http_OK();

  my $file = "log_$q->{file}.txt";

  if ($q->{file} eq "Extract_log") {
    # this is the default log file. Check it the file is being build first
    # if cannot find it, use the standard one.
    my $logFile;
    # check if a file is being build.
    my $D1 = System->get_home() . "/DATA/Download/Solution";
    opendir(O, $D1);
    my @hd = readdir(O); closedir(O);
    foreach my $currentFile (@hd) {
      if (-d "$D1/$currentFile") {
        print $currentFile."\n";
        # test if the current log file exists.
        if (-f "$D1/$currentFile/extract_log.txt") {
          $logFile = "$currentFile/extract_log.txt";
        }
      }
    }
    if (!defined($logFile)) {
      $logFile = "Extract_log.txt";
    }
    $file = $logFile;
  }

  open(O, System->get_home() . "/DATA/Download/Solution/$file");
  my @l = <O>;
  close(O);
  print join("", @l);
}

#
# List the content of a given extract
# if the extract has not been expanded, untar it first.
#
sub extractContentList {
  my($q) = @_;
  print Client->http_OK();
  my $D = System->get_home() . "/DATA";
  if (-f "$D/$q->{id}") {
    # tar file exist
    my $DIR1 = $D ."/Download/Solution";
    my $file = $D.$q->{id};
    chdir($DIR1);

    my $index = rindex($file, ".tar");
    my $DIR2 = substr($file,0,$index);

    if (-d "$DIR2") {
    } else {
      system("tar xf $file");
    }

    # cd in this directory
    chdir($DIR2);

    my @ALL = &dodir($DIR2);
    my $length = length($D);
    print "<FILES>\n";
    foreach my $f (@ALL) {
      $index = index($f, $D);
      $f = substr($f,$length);
      $f = Client->xmlEncode($f);
      print "  <FILE>$f</FILE>\n";
    }
    print "</FILES>\n";
    # cd back to top level, otherwise won't beable to delete this directory
    # later on.
    chdir($DIR1);

  } else {
    # error, tar file does not exist
    print "<ERROR>tar file does not exist</ERROR>\n";
  }
}

sub ether {
  my($q) = @_;
  print Client->http_OK();

  my $H = Logic::Ethers->readHosts("192.168");
  my (@array, @L);
  open(0, "/etc/hosts");
  print "<DEVICES>\n";
  foreach my $ip (sort keys %$H) {
    print "  <DEVICE>\n";
    print "    <IP>$ip</IP>\n";
    my $el = $H->{$ip};
    print "    <NAME>$el->[0]</NAME>\n";
    print "    <MAC>$el->[1]</MAC>\n";
    print "  </DEVICE>\n";
  }
  print "</DEVICES>\n";
  close(0);
}

sub updateEther {
  my($q) = @_;
  print Client->http_OK();

  my ($error, $new);
  my %E = &readEther();
    `/usr/sbin/pntadm -R 192.168.0.0`;
    `/usr/sbin/pntadm -C 192.168.0.0`;
  foreach my $el (sort %$q) {
    next if (substr($el,0,3) ne "et_");
    my $name = substr($el, 3);
    my $et = $q->{$el};
    $et = uc(Util->trim($et));
    if (!$et) {
      delete $E{$name};
      next;
    }
    if (!Logic::Ethers->valid($et)) {
      $error = "INVALID";
    } else {
      $new .= "$et\t$name\n";
      my $mac = $et;
      $mac =~ s/\://g;
      my $name = Util->name2ip($name);
      if ($el =~ /psq/){
        `/opt/SUNWsespsw/bin/admin_dhcp_client -A -i $name -m $mac -B y`;
      } else {
        `/opt/SUNWsespsw/bin/admin_dhcp_client -A -i $name -m $mac -B n`;
      }
      delete $E{$name};
    }
  }
  if (!$error) {
    foreach my $el (keys %E) {
      $new .= "$E{$el}\t$el\n";
    }
    open(O, ">/etc/ethers");
    print O $new;
    close(O);
    print "<STATUS>OK</STATUS>\n";
  } else {
    print "<STATUS>$error</STATUS>\n";
  }
}

sub readEther {
  my (%E,$l);
  open(O, "/etc/ethers");
  while ($l = <0>) {
    my($et, $name) = split(/\s+/, $l);
    $E{$name} = $et;
  }
  close(O);
  return %E;
}


sub spatray {

  my $FIREWALL =  "/opt/SUNWsespfw/bin/get_version";
  my $NTC_V    =  "/opt/SUNWsespnc/bin/get_version";
  my($ntc_version, $fire_version);

  if (-x $FIREWALL) {
     $fire_version = `$FIREWALL`; chomp($fire_version);
     $fire_version =~ s/"//g;
  }
  if (-x $NTC_V) {
     $ntc_version  = `$NTC_V`;    chomp($ntc_version);
  }

  my $out = "<REPORT>\n";
  $out .= " <CONTENT>\n";

  $out .= "   <FRU>\n";
  $out .= "     <COMPONENT ID=\"ntc\">\n";
  $out .= "     <VALUE ID=\"vendor\">Lantronix</VALUE>\n";
  $out .= "     <VALUE ID=\"serialNo\">spcomp1</VALUE>\n";
  $out .= "     <VALUE ID=\"model\">scs400</VALUE>\n";
  $out .= "     <VALUE ID=\"revision\">$ntc_version</VALUE>\n";
  $out .= "     </COMPONENT>\n";

  $out .= "     <COMPONENT ID=\"firewall\">\n";
  $out .= "       <VALUE ID=\"vendor\">NetGear</VALUE>\n";
  $out .= "       <VALUE ID=\"serialNo\">spcomp2</VALUE>\n";
  $out .= "       <VALUE ID=\"model\">rp114</VALUE>\n";
  $out .= "       <VALUE ID=\"revision\">$fire_version</VALUE>\n";
  $out .= "     </COMPONENT>\n";
  $out .= "   </FRU>\n";

  $out .= " </CONTENT>\n";
  $out .= "</REPORT>\n";

  print Client->http_OK;
  print $out;
}


#
# Returns all the files in a current directory
# (Recursively, traverse all the subdirectories)
#
sub dodir {
  my($dir,$nlink) = @_;
  my($dev,$ino,$mode,$subcount);

  ($dev,$ino,$mode,$nlink) = stat('.') unless $nlink;

  # Get the list of files in the current directory

  my @ALL;

  opendir(DIR,'.') || die "Cannot open $dir";
  my(@filenames) = readdir(DIR);
  close(DIR);

  if ($nlink == 2) { # This dir has no subdirectories
    for (@filenames) {
      next if $_ eq '.';
      next if $_ eq '..';
      my $name = "$dir/$_";
      #print "$name\n";
      push(@ALL, $name);
    }
  } else {           # This dir has subdirectories
    $subcount = $nlink - 2;
    for (@filenames) {
      next if $_ eq '.';
      next if $_ eq '..';
      my $name = "$dir/$_";

      # do not print the directories
      if (-d $name) {
      } else {
        push(@ALL, $name);
        #print "$name\n";
      }

      next if $subcount == 0; # Seen all the subdirs
      
      # Get link count and check for directoriness.

      ($dev,$ino,$mode,$nlink) = lstat($_);
      next unless -d _;

      # It really is a directory, so do it recursively.

      chdir $_ || die "Cannot cd to $name";
      my @SUB = &dodir($name,$nlink);
      push(@ALL, @SUB);
      chdir '..';
      --$subcount;
    }
  }
  return (@ALL);
  
}


1;


