#!/usr/bin/perl
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
# bos720 src/bos/usr/bin/cdat/helpers/push_file.pl 1.2 
#  
# Licensed Materials - Property of IBM 
#  
# COPYRIGHT International Business Machines Corp. 2010,2011 
# All Rights Reserved 
#  
# US Government Users Restricted Rights - Use, duplication or 
# disclosure restricted by GSA ADP Schedule Contract with IBM Corp. 
#  
# IBM_PROLOG_END_TAG 
# @(#)90    1.2  src/bos/usr/bin/cdat/helpers/push_file.pl, cdat, bos720 7/14/11 20:29:57
use warnings;
use strict;
use Net::FTP;
use File::Basename;	# needed for basename

use lib '/usr/lib/cdat/';
use cdat;

#
# Constants.
#
my $SCP = '/usr/bin/scp';
my $SSH_TIMEOUT = 2;

######################################################################
# Function:	usage
# Purpose:	Display usage.
# Tasks:	Print usage and exit.
# Input:	None
# Output:	None
######################################################################
sub usage
{
    print(STDERR "Usage: push_file SourceFile TargetFile\n");
    print(STDERR "       push_file SourceFile ... TargetDirectory\n");
    exit(1);
}

######################################################################
# Function:	ftp_put_file
# Purpose:	Upload a file or directory using FTP.
# Tasks:	Upload a file or directory using FTP.
# Input:	Net::FTP handle, local file name, remote destination,
#		whether destination is a directory or not
# Output:	0 if success, 1 otherwise
######################################################################
sub ftp_put_file
{
    my ($ftp, $file, $dest, $isdir) = @_;
    my $rc;

    my $base = basename($file);

    # determine whether filename is a file or directory
    if (-d $file) {
        # filename is a directory
        if (!$isdir) {
	    print(STDERR "cannot upload directory, destination is a file\n");
	    return 1;
	}

	print("Creating directory $dest/$base\n");
	if (!$ftp->mkdir("$dest/$base")) {
	    print(STDERR "cannot create directory $dest/$base\n");
	    return 1;
	}
	# Recursively call ourselves for each directory entry
	my $dirh;	# must use a local dir handle here, not DIR!
	if (!opendir($dirh, $file)) {
	    print(STDERR "cannot list $file content\n");
	    return 1;
	}
	while (defined(my $elem = readdir($dirh))) {
	    next if ($elem eq '.' || $elem eq '..');
	    # call ourserlves recursively
	    if (ftp_put_file($ftp, "$file/$elem", "$dest/$base", 1)) {
		return 1;
	    }
	}
	closedir($dirh);

    } else {
	# filename is a file, upload it
        if ($isdir) {
	    print("Copying $file to $dest/$base\n");
	    $rc = $ftp->put($file, "$dest/$base");
        } else {
	    print("Copying $file to $dest\n");
	    $rc = $ftp->put($file, $dest);
        }
        if (!$rc) {
	    print(STDERR "could not upload file $file\n");
	    return 1;
        }
    }
    return 0;
}

######################################################################
# Function:	ftp_put
# Purpose:	Upload files/directories using FTP.
# Tasks:	Connect via FTP to the specified remote node using the
#		specified login and upload files and directories.
# Input:	user, host name, local files, remote destination
# Output:	None
######################################################################
sub ftp_put
{
    my ($hosts, $user, $hostname, $sources, $dest) = @_;
    my ($rc, $isdir);

    my $passwd = $hosts->{$hostname}{users}{$user};
    if (!defined($passwd)) {
        $passwd = cdat::get_password("Enter password for \"$user\" user: ");
    }
    if (!defined($passwd)) {
        print(STDERR "No password to connect to $user\@$hostname\n");
        exit(1);
    }

    my $ftp = Net::FTP->new($hostname);
    if (!defined($ftp)) {
	print(STDERR "Cannot open FTP connection to $hostname\n");
        exit(1);
    }
    $rc = $ftp->login($user, $passwd);
    if (!$rc) {
	print(STDERR "FTP to $hostname failed: ".$ftp->message);
        exit(1);
    }

    # check whether destination exists and is a directory or not
    if ($ftp->cwd($dest)) {
	$isdir = 1;
    } else {
	$isdir = 0;
    }

    # If there is more than 1 local file, check that destination
    # exists and is a directory.
    if (@$sources > 1 && !$isdir) {
	print(STDERR "Destination directory \"$dest\" not found.\n");
	exit(1);
    }

    # Transfer files in binary mode
    $ftp->binary();

    foreach my $file (@$sources) {
	last if ftp_put_file($ftp, $file, $dest, $isdir);
    }

    # Close FTP session
    $ftp->quit();
}

######################################################################
# Function:	scp_put
# Purpose:	Upload files/directories using SCP.
# Tasks:	Connect via SSH to the specified remote node using the
#		specified login and upload files and directories.
# Input:	user, host name, local files, remote destination
# Output:	None
######################################################################
sub scp_put
{
    my ($hosts, $user, $hostname, $sources, $dest) = @_;

    system("$SCP -i $ENV{HOME}/.ssh/id_rsa -o UserKnownHostsFile=$ENV{HOME}/.ssh/known_hosts -o StrictHostKeyChecking=yes -q -r @$sources $user\@$hostname:$dest");
    if ($? != 0) {
	print(STDERR "scp command failed.\n");
        exit(1);
    }
}

######################################################################
# Function:	main
# Purpose:	Entry point of the push_file command.
# Tasks:	Upload the specified files/directories to the
#		specified remote node using either SCP or FTP.
# Input:	user, host name, node type, local files,
#		remote destination
# Output:	None
######################################################################
sub main
{
    usage() if (@ARGV < 2);

    my $user = $ENV{CDAT_USER};
    my $hostname = $ENV{CDAT_HOST};
    my $type = $ENV{CDAT_TYPE};
    my $dest = pop @ARGV;
    # @ARGV now only contains the local files

   if (!defined($user) || !defined($hostname) || !defined($type)) {
       printf(STDERR "Bad environment\n");
       exit(1);
   }

    my %hosts;
    cdat::read_host_db(\%hosts);

    my $protocol = $hosts{$hostname}{protocol};
    if (!defined($protocol)) {
        if ( -x $SCP && cdat::check_remote_protocol($hostname, 'ssh')) {
            $protocol = "ssh";
        } elsif (cdat::check_remote_protocol($hostname, 'exec')) {
            $protocol = "exec";
        } else {
            $protocol = "telnet";
        }
    }

    print("Uploading ".join(', ', @ARGV)." to $type $hostname using ");
    if ($protocol eq "ssh") {
	print("scp\n");
        scp_put(\%hosts, $user, $hostname, \@ARGV, $dest);
    } else {
	print("ftp\n");
	ftp_put(\%hosts, $user, $hostname, \@ARGV, $dest);
    }
}

main;