package Ocsinventory::Agent::Network;
# TODO:
#  - set the correct deviceID and olddeviceID
use strict;
use warnings;

use LWP::UserAgent;
use Socket;

use Ocsinventory::Compress;

sub new {
  my (undef, $params) = @_;

  my $self = {};
  
  $self->{accountconfig} = $params->{accountconfig}; 
  $self->{accountinfo} = $params->{accountinfo}; 
  $self->{common} = $params->{common}; 

  my $logger = $self->{logger} = $params->{logger};

  $self->{config} = $params->{config};
  my $uaserver;

  if ($self->{config}->{server} =~ /^http(|s):\/\//) {
      $self->{URI} = $self->{config}->{server};
      $uaserver = $self->{config}->{server};
      $uaserver =~ s/^http(|s):\/\///;
      $uaserver =~ s/\/.*//;
      if ($uaserver !~ /:\d+$/) {
          $uaserver .= ':443' if $self->{config}->{server} =~ /^https:/;
          $uaserver .= ':80' if $self->{config}->{server} =~ /^http:/;
      }
  } else {
      $self->{URI} = "http://".$self->{config}->{server}.$self->{config}->{remotedir};
      $uaserver = $self->{config}->{server};
  }


  $self->{compress} = new Ocsinventory::Compress ({logger => $logger});
  # Connect to server
  $self->{ua} = LWP::UserAgent->new(keep_alive => 1);
  if ($self->{config}->{proxy}) {
    $self->{ua}->proxy(['http', 'https'], $self->{config}->{proxy});
  }  else {
    $self->{ua}->env_proxy;
  }
  my $version = 'OCS-NG_unified_unix_agent_v';
  $version .= exists ($self->{config}->{VERSION})?$self->{config}->{VERSION}:'';
  $self->{ua}->agent($version);
    $self->{config}->{user}.",".
    $self->{config}->{password}."";
  $self->{ua}->credentials(
    $uaserver, # server:port, port is needed 
    $self->{config}->{realm},
    $self->{config}->{user},
    $self->{config}->{password}
  );

  bless $self;
}


sub sendXML {
  my ($self, $args) = @_;

  my $logger = $self->{logger};
  my $compress = $self->{compress};
  my $message = $args->{message};

  my $common = $self->{common};

  my $req = HTTP::Request->new(POST => $self->{URI});

  $req->header('Pragma' => 'no-cache', 'Content-type',
    'application/x-compress');

  $logger->debug ("sending XML");


  $logger->debug ("sending: ".$message);

  my $compressed = $compress->compress($message);

  if (!$compressed) {
    $logger->error ('failed to compress data');
    return;
  }

  $req->content($compressed);

  my $res = $self->{ua}->request($req);

  # Checking if connected
  if(!$res->is_success) {
    $logger->error ('Cannot establish communication : '.$res->status_line);
    return;
  }

  return $res ;

}

sub getXMLResp {

  my ($self, $res, $msgtype) = @_;
  my $logger = $self->{logger};
  my $compress = $self->{compress};

  #If no answer from OCS server
  return unless $res;

  #Reading the XML response from OCS server
  my $content = $compress->uncompress($res->content);

  if (!$content) {
    $logger->error ("Deflating problem");
    return;
  }

  my $tmp = "Ocsinventory::Agent::XML::Response::".$msgtype;
  eval "require $tmp";
  if ($@) {
      $logger->error ("Can't load response module $tmp: $@");
  }
  $tmp->import();
  my $response = $tmp->new ({
     accountconfig => $self->{accountconfig},
     accountinfo => $self->{accountinfo},
     content => $content,
     logger => $logger,
     #origmsg => $message,
     config => $self->{config},
     common => $self->{common},

  });

  return $response;
}


sub getHttpFile {
  my ($self,$uri,$filetoget,$filepath) = @_;
  my $url = "http://$uri/$filetoget";

  $self->{ua}->mirror($url,$filepath);
}

sub getHttpsFile {
  my ($self, $uri, $filetoget, $filepath ,$certfile, $installpath) = @_ ;

  my $logger = $self->{logger};
  my ($ctx, $ssl, $got);

  if ($self->{common}->can_load('Net::SSLeay')) {

    eval {
      $| = 1;
      $logger->debug('Initialize ssl layer...');

      # Initialize openssl
      if ( -e '/dev/urandom') {
        $Net::SSLeay::random_device = '/dev/urandom';
        $Net::SSLeay::how_random = 512;
      } else {
        srand (time ^ $$ ^ unpack "%L*", `ps wwaxl | gzip`);
        $ENV{RND_SEED} = rand 4294967296;
      }

      Net::SSLeay::randomize();
      Net::SSLeay::load_error_strings();
      Net::SSLeay::ERR_load_crypto_strings();
      Net::SSLeay::SSLeay_add_ssl_algorithms();

      #Create ctx object
      $ctx = Net::SSLeay::CTX_new() or die_now("Failed to create SSL_CTX $!");
      Net::SSLeay::CTX_load_verify_locations( $ctx, "$installpath/$certfile", $installpath )
      or die_now("CTX load verify loc: $!");

      # Tell to SSLeay where to find AC file (or dir)
      Net::SSLeay::CTX_set_verify($ctx, &Net::SSLeay::VERIFY_PEER,0);
      Net::SSLeay::die_if_ssl_error('callback: ctx set verify');

      my($server_name,$server_port,$server_dir);

      if($uri =~ /^([^:]+):(\d{1,5})(.*)$/){
        $server_name = $1;
        $server_port = $2;
        $server_dir = $3;
      } elsif ($uri =~ /^([^\/]+)(.*)$/) {
        $server_name = $1;
        $server_dir = $2;
        $server_port = '443';
      }

      $server_dir .= '/' unless $server_dir=~/\/$/;

      $server_name = gethostbyname ($server_name) or die;
      my $dest_serv_params  = pack ('S n a4 x8', &AF_INET, $server_port, $server_name );

      # Connect to server
      $logger->debug("Connect to server: $uri...");
      socket  (SOCKET, &AF_INET, &SOCK_STREAM, 0) or die "socket: $!";
      connect (SOCKET, $dest_serv_params) or die "connect: $!";

      # Flush socket
      select  (SOCKET); $| = 1; select (STDOUT);
      $ssl = Net::SSLeay::new($ctx) or die_now("Failed to create SSL $!");
      Net::SSLeay::set_fd($ssl, fileno(SOCKET));

      # SSL handshake
      $logger->debug('Starting SSL connection...');
      Net::SSLeay::connect($ssl);
      Net::SSLeay::die_if_ssl_error('callback: ssl connect!');

      # Get file
      my $http_request = "GET /$server_dir/$filetoget HTTP/1.0\n\n";
      Net::SSLeay::ssl_write_all($ssl, $http_request);
      shutdown SOCKET, 1;

      $got = Net::SSLeay::ssl_read_all($ssl);
      $got = (split("\r\n\r\n", $got))[1] or die;

      #Create file on disk
      open FILE, ">$filepath" or die("Cannot open info file: $!");
      print FILE $got;
      close FILE;
    };

    if($@){
      $logger->error("Error: SSL hanshake has failed");
      Net::SSLeay::free ($ssl) if $ssl;
      Net::SSLeay::CTX_free ($ctx);
      close SOCKET;
      return 0; 
    }
    else {
      $logger->debug("Success. :-)");
      Net::SSLeay::free ($ssl);
      Net::SSLeay::CTX_free ($ctx);
      close SOCKET;
    }

  } else {  	#Exit if can't load Net::SSLeay 
    return 0;
  }

  1;
}


1;
