package Util::Http;
#<copyright>
# ----------------------------------------------------------
# Sun Proprietary/Confidential Code
# Copyright 2001, Sun Microsystems, Inc. All rights reserved.
# ----------------------------------------------------------
#</copyright>

#  $Name: bld61_002 $ 
#  $Id: Http.pm,v 1.12 2006/01/25 18:46:30 mckenney Exp $
#   runit          : GET=runit
#   runss          : GET=RUNSS , command must be in ras_remote.list
#   getPID         : GET=PROCE    # get process info
#   appendFile     : PUT=saveA    
#   saveFile       : PUT=saveF    # copy string to a file on slave
#   fileExist      : GET=EXIST
#   readFile       : GET=FILER
#   createFile     : GET=CREAT
#   fileSize       : GET=FILEA
#   readFileDelete : get a file from a slave and delete on the slave
#   sendFile       : copy file to a slave
#   receiveFile    : copy file from a slave
#   deleteFile     : GET=DELET&file=

#   getCommand     : GET=<command>  # get  from a perl function
#   postCommand    : GET=<command>  # post to a perl function

#   cgiCommand     : rascgi
#   remoteCommand  :
#   get_remoteCommand :

#   memfrob     : N/U

use Debug;
use LWP::UserAgent;

# $val = $Util::Http->post(page, $text, 20, $arg);
# ($err, $val) = $Util::Http->post(page, $text, {timeout => 20} );

$ERROR = "";

sub post {
  my($self, $page, $post, $to, $arg) = @_;
  my ($proxy);

  $proxy   = $arg->{proxy} ;
  my $password = $arg->{password};

  $to = 30 if (!$to);
  $ERROR = undef;

  my($ua) = new LWP::UserAgent;
  if ($to =~ /\d+/) {
    $ua->timeout($to); 
  }
  my $header = new HTTP::Headers;

  if ($password) {
     $header->authorization_basic(split(/\:/, $password));
     $header->user_agent("storade_7654");
  }

  $ua->agent("storade_7654");
  $ua->proxy('http' => $proxy) if ($proxy);

  my($req) = new HTTP::Request(POST => $page, $header);
  $req->content_type('application/x-www-form-urlencoded');
  $post .= "\n";
  $req->content($post);
  my($res) = $ua->simple_request($req);

  if ($res->is_success) {
    if (wantarray) {
       return (undef, $res->content);
    } else {
       return $res->content;
    }
  } else {
    $ERROR = $res->status_line;
    $ERROR =~ s/chunk \d+//;
    if (wantarray) {
       return ($ERROR, undef);
    } else {
       return undef;
    }
  }
}
## This routine will try to find the host ip address using the rasagent.conf file
sub find_host_ip_from_conf{
  my($host) = @_;

  my($renv, $devs, $hosts,$notifs) = PDM::ConfigFile->read();

  foreach my $h (@$hosts) {
      if (lc($h->{hostname}) eq lc($host)) {
         return $h->{ipno};
      }
  }
  # Didn't match on full name try first part of name
  foreach my $h (@$hosts) {
      my $ix = index($h->{hostname}, ".");
      if($ix > 0){
        my $short = substr($h->{hostname}, 0, $ix);
        if (lc($short) eq lc($host)) {
         return $h->{ipno};
	}
      }
  }

  return undef;
}

#  ($err, $text) = Util::Html->get($url, $to);
#  $text = = Util::Html->get($url, $to);
#   if (!defined($text)) {
#      print $Util::Html::ERROR;
#

# progress is a callback

sub get {
  my($self, $page,$timeout, $arg) = @_;
  if ($page !~ /localhost/){
    if ($page =~ /\:\/\/([^\:\/]+)/){
      my $host= $1;
      if ($page =~ /\:\/\/guest@([^\:\/]+)/){
        $host = $1;
      }
      $host_ip = find_host_ip_from_conf($host);
      if($host_ip){
         $page =~ s/$host/$host_ip/;
      }else{
         use Socket;
         $i = inet_aton($host);
         if (!defined $i)  {
           my $host_ip = Util->name2ip($host);
           $page =~ s/$host/$host_ip/;
         }
      }
    }
  }
  my $progress = $arg->{progress};
  my $password = $arg->{password};
  Debug->print3("Http->get: $page");

  my($ua) = new LWP::UserAgent;
  $timeout = 30 if (!$timeout);
  if ($timeout =~ /\d+/) {
    $ua->timeout($timeout) ;
  }
  $ERROR = undef;
  my $header = new HTTP::Headers;
  if ($password) {
     $header->authorization_basic(split(/\:/, $password));
     $header->user_agent("storade_7654");
  }
  $ua->agent("storade_7654");

#  $ua->proxy('http' => "http://cache-brm.Central.Sun.COM:8080");

  my($req) = new HTTP::Request(GET => $page, $header);

  my $res = $ua->request($req, $progress);

  if ($res->is_success) {
    my $content;
    $content = $res->content();
    Debug->snapshot("Http->get(to=$timeout): $page");
    Debug->snapshot1($content);
    if (wantarray) {
       return (undef, $content, $res);
    } else {
       return $content;
    }
  } else {
    $ERROR = $res->status_line;
    Debug->snapshot("Http->get(to=$timeout): $page\nError: " . $res->code . " " .  $res->status_line);
    if (wantarray) {
       return ($ERROR, undef);
    } else {
       return undef;
    }
  }
}

sub memfrob($) {
   return(join("", map { chr( (ord($_) ^ 42) + 0) } (split(//, shift))));
}


#
#  command is relative to /opt/SUNWstade/bin
#
sub remoteCommand {
  my($class, $host, $command, $to) = @_;

  $command = Util->encode($command);
  my $url = Util->makeUrl($host, "?GET=Util::Http::remoteCommand&command=$command", $to);
  return Util::Http->get($url, $to);

}

#  Util::Http->remoteCommand($host, $command);
#
sub get_remoteCommand {
  my($q) = @_;

  print Html->text_header();
  print "OK\n";
  close STDIN; close STDOUT; close STDERR;
  my $command = $q->{command};
  system(System->get_home() . "/bin/$command&");
}

#  Util::Http->runit($q->{host}, "/bin/rasagent -d2&");
#  command cannot include redirection, but can end in '&' to run in
#  background

sub runit {
  my($class, $host, $command, $to, $progress) = @_;
  my $url = Util->makeUrl($host, "?GET=RUNIT&comm=$command", $to);
  return Util::Http->get($url, $to, {progress => $progress} );
}

sub runss {
  my($class, $host, $command, $to, $password) = @_;
  $command .= "+" if (index($command, " ") < 0);
  $password = "peer:peer" if (!$password);
  my $url = Util->makeUrl($host, "?GET=RUNSS&comm=$command", $to);
  return Util::Http->get($url, $to, {password => $password } );
}

# command executed in shell by rashstart, should include redirection
# always run in background, no return-code

sub runshell {
  my($class, $host, $command, $to, $progress) = @_;
  my $url = Util->makeUrl($host, "?GET=RUNSY&comm=$command", $to);
  return Util::Http->get($url, $to, {progress => $progress} );
}

sub cgiCommand {
  my($class, $host, $command, $to, $progress) = @_;

  my $url = Util->makeUrl($host, "rascgi?GET=$command", $to);
  return Util::Http->get($url, $to, {progress => $progress});
}

# answered by rashttp in 2.4
sub goCommand {
  my($class, $host, $command, $to, $arg) = @_;

  my $url = Util->makeUrl($host, "/rashttp?GO=$command", $to);
  return Util::Http->get($url, $to, $arg);
}

# answered by xfer in 2.4
sub getCommand {
  my($class, $host, $command, $to, $arg) = @_;
  if ($arg->{try_rashttp}) {
    my $url = Util->makeUrl($host, "storade/rashttp?GET=$command", $to);
    my @rc = Util::Http->get($url, $to, $arg);
    if (!$rc[0]) {
      return wantarray ? @rc : $rc[1];
    }
  }
  my $url = Util->makeUrl($host, "?GET=$command", $to);
  return Util::Http->get($url, $to, $arg);
}

sub postCommand {
  my($class, $host, $command, $data, $to) = @_;

  my $url = Util->makeUrl($host, "?GET=$command", $to);
  return Util::Http->post($url, $data,  $to);
}


sub getPID {
  my($class, $host, $pid, $to, $arg) = @_;
  my $url;
  if ($arg->{try_rashttp}) {
     $url = Util->makeUrl($host, "storade/rashttp?GET=PROCE&file=$pid", $to);
  }else{
     $url = Util->makeUrl($host, "?GET=PROCE&file=$pid", $to);
  }
  return Util::Http->get($url, $to);
}
  
sub appendFile {
  my($class, $host, $file, $data, $to) = @_;

  my($url) = Util->makeUrl($host, "?PUT=saveA&file=$file", $to);

  return Util::Http->post($url, $data, $to);
}

sub saveFile {
  my($class, $host, $file, $data, $to, $arg) = @_;

  my($url) = Util->makeUrl($host, "?PUT=saveF&file=$file", $to);

  return Util::Http->post($url, $data, $to, $arg);
}

sub fileExist {
  my($class, $host, $file, $to)  = @_;
  
  my $url = Util->makeUrl($host, "?GET=EXIST&file=$file", $to);
  return Util::Http->get($url, $to);
}

#
# copy a file from the master if needed
# relative to DATA
#
sub copyFromMaster {
  my($class, $file) = @_;
  my($master) = Util->findMaster();
  $ERROR = undef;
  return 1 if (!$master);

  my $F = System->get_home() . "/DATA/$file.time";

  my ($err, $age) =  Util::Http->fileAge($master, $file);
   if ($err) {
      Debug->err(TEXT => "copyFromMaster: cannot read age of $file on $master");
      $ERROR = "Cannot read age of $file";
      return undef;
   }
   my $last_age;
   if (open(O, $F)) {
      $last_age = <O>; close(O);
   }
   if ($age > $last_age) {  # update slave
      my ($err, $out) = Util::Http->readFile($master, $file);
      if ($err || length($out) < 50) {
        $ERROR = "Error reading rasagent.conf: $err";
        return undef;
      }
      if (open(W, ">" . System->get_home() . "/DATA/$file")) {
        print W $out;
        close(W);
        open(O, ">$F"); print O $age; close(O); # save new age
      } else {
        $ERROR = "Cannot open $file";
        return undef;
      }
   }
   return 1;
}



sub fileAge {
  my($class, $host, $file, $to)  = @_;
  
  my $url = Util->makeUrl($host, "?GET=FILEA&file=$file", $to);
  my ($err, $age) = Util::Http->get($url, $to);

  if ($age =~ /Age=(\d+)/) {
     $age = $1;
  } elsif (!$err) {
     $err = "Cannot retrieve age of $file: $age";
     $age = undef;
  }
  return wantarray? ($err, $age) : $age;
}


sub createFile {
  my($class, $host, $file, $to)  = @_;
  
  my $url = Util->makeUrl($host, "?GET=CREAT&file=$file", $to);
  return Util::Http->get($url, $to);
}


sub readFile {
  my($class, $host, $file, $to, $arg)  = @_;
  
  if ($arg->{try_rashttp}) {
    my $url = Util->makeUrl($host, "storade/rashttp?GET=FILER&file=$file", $to);
    my @rc = Util::Http->get($url, $to);
    if (!$rc[0]) {
      return wantarray ? @rc : $rc[1];
    }
  }
  my $url = Util->makeUrl($host, "?GET=FILER&file=$file", $to);
  return Util::Http->get($url, $to);
}

# move the file and then read it.
sub readFileDelete {
  my($class, $host, $file, $to)  = @_;
  
  my $url = Util->makeUrl($host, "?GET=FILED&file=$file", $to);
  return Util::Http->get($url, $to);
}

# send file, same location

sub sendFile {
  my($class, $host, $file, $to, $arg)  = @_;
  my $data;
  $ERROR = undef;
  my($url) = Util->makeUrl($host, "?PUT=saveF&file=$file", $to);
  if (open(O,System->get_home() . "/DATA/$file")) {
    while ($l = <O>) {
      $data .= $l;
    } 
    close(O);
    return Util::Http->post($url, $data, $to, $arg);
  } else {
    $ERROR = "setFile: $!";
    return undef;
  }
}

# receive file, same location

sub receiveFile {
  my($class, $host, $file, $to, $arg)  = @_;
  $ERROR = undef;
  my $url;
  if ($arg->{try_rashttp}) {
    $url = Util->makeUrl($host, "storade/rashttp?GET=FILER&file=$file", $to);
  }else{
     $url = Util->makeUrl($host, "?GET=FILER&file=$file", $to);
  }
  my ($err,$data) = Util::Http->get($url, $to);

  if (!$err) {
    open(O, ">" . System->get_home() . "/DATA/$file");
    print O $data;
    close(O);
  } else {
    $ERROR = $err;
    return undef;
  }
  return $data;
}

# delete remote file

sub deleteFile {
  my($class, $host, $file, $to)  = @_;
  
  my $url = Util->makeUrl($host, "?GET=DELET&file=$file", $to);
  return Util::Http->get($url, $to);
}



1;

