#!/usr/bin/perl -w
use Getopt::Long;
use lib "/opt/vyatta/share/perl5/";

use strict;
use IO::Prompt;

my ($show, $delete, $updateone);
my @copy;
my @update;

GetOptions(
    "show=s"        => \$show,
    "delete=s"      => \$delete,
    "update=s{2}"   => \@update,
    "updateone=s"   => \$updateone,
    "copy=s{2}"     => \@copy
);

if (defined $show){
    show($show);
}
if (defined $delete){
    delete_file($delete);
}
if (@update){
    update(@update);
}
if (defined($updateone)){
    update($updateone, "running");
}
if (@copy){
    copy(@copy);
}

sub conv_file {
    my $file = " ";
    my $filein = pop(@_);
    $file = $filein;
    my $topdir;
    if ($file =~ /(.+?):\/\/(.*)/){
        $topdir = $1;
        $file = $2;
    } elsif ($file =~ /^\//) {
        $topdir = "running";
    } else {
        print "File: $filein not found \n";
        exit 1;
    }
    if ($topdir eq "running") {
        $file = "/$file";
    } elsif (lc($topdir) eq 'disk-install') {
        $file = "/lib/live/mount/persistence/$file";
    } elsif (grep { lc($topdir) eq $_ } ("ftp", "tftp", "http", "https", "scp", "sftp")) {
        $file = $filein;
        $topdir = 'url';
    } else {
        if (!-d "/lib/live/mount/persistence/boot/$topdir/rw"){
            print "Image $topdir not found!\n";
            exit 1;
        }
        $file = "/lib/live/mount/persistence/boot/$topdir/rw/$file";
    }
    return ($topdir, $file);
}

sub conv_file_to_rel {
    my ($topdir, $filename) = @_;
    if ($topdir eq "running"){
        $filename =~ s?/?$topdir://?;
    } elsif ($topdir eq "disk-install") {
        $filename =~ s?/lib/live/mount/persistence/?$topdir://?;
    } else {
        $filename =~ s?/lib/live/mount/persistence/boot/$topdir/rw/?$topdir://?;
    }
    return $filename;
}

sub delete_file {
    my ($file) = @_;
    (my $topdir, $file) = conv_file($file);
    if ($topdir eq 'url'){
        print "Cannot delete files from a url\n";
        exit 1;
    }
    if (-d $file){
        my $print_dir = conv_file_to_rel($topdir,$file);
        if (y_or_n("Do you want to erase the entire $print_dir directory?")){
            system("rm -rf $file");
            print("Directory erased\n");
        }
    } elsif (-f $file) {
        my $print_file = conv_file_to_rel($topdir,$file);
        if (y_or_n("Do you want to erase the $print_file file?")){
            system("rm -rf $file");
            print("File erased\n");
        }
    }
}

sub url_copy {
    my ($from, $to) = @_;
    my ($f_topdir, $t_topdir);
    ($f_topdir, $from) = conv_file($from);
    ($t_topdir, $to) = conv_file($to);
    if ($t_topdir eq 'url' && $f_topdir eq 'url'){
        print "Cannot copy a url to a url\n";
        exit 1;
    } elsif($t_topdir eq 'url') {
        if (-d $from){
            print "Cannot upload an entire directory to url\n";
            exit 1;
        } elsif ($to =~ /http/){
            print "Cannot upload to http url\n";
            exit 1;
        }
        upload($from, $to);
    } elsif ($f_topdir eq 'url') {
        if (-d $to){
            $from =~ /.*\/(.*)/;
            my $from_file = $1;
            $to = "$to/$from_file";
            if (-f "$to") {
                if (!y_or_n("This file exists; overwrite if needed?")){
                    exit 0;
                }
            }
        }
        friendly_download($from, $to);
    }
    exit 0;
}

sub copy {
    my ($from, $to) = @_;
    my ($f_topdir, $t_topdir);
    ($f_topdir, $from) = conv_file($from);
    if ($f_topdir eq 'url'){
        url_copy($from, $to);
    }
    ($t_topdir, $to) = conv_file($to);
    if ($t_topdir eq 'url'){
        url_copy($from, $to);
    }
    $from =~ /.*\/(.*)/;
    my $from_file = $1;
    if (-d $from && -e $to && !(-d $to)){
        print "Cannot copy a directory to a file.\n";
        return 1;
    } elsif (-f $to  || (-d $to && -f "$to/$from_file")) {
        if (y_or_n("This file exists; overwrite if needed?")){
            rsync($from, $to);
        }
    } elsif (-d $to && -d $from){
        if (y_or_n("This directory exists; would you like to merge?")){
            rsync($from, $to);
        }
    } else {
        rsync($from, $to);
    }
}

sub update {
    my ($to, $from) = @_;
    my ($t_topdir, $f_topdir);
    ($f_topdir, $from) = conv_file("$from://");
    if ($f_topdir eq 'url'){
        print "Cannot clone from a url\n";
        exit 1;
    }
    ($t_topdir, $to) = conv_file("$to://");
    if ($t_topdir eq 'running'){
        print "Cannot clone to running\n";
        exit 1;
    }
    if ($t_topdir eq 'disk-install'){
        print "Cannot clone to disk-install\n";
        exit 1;
    }
    if ($t_topdir eq 'url'){
        print "Cannot clone to a url\n";
        exit 1;
    }
    my $print_from = conv_file_to_rel($f_topdir, $from);
    my $print_to = conv_file_to_rel($t_topdir, $to);
    my $msg = "WARNING: This is a destructive copy of the /config directories\n".
              "This will erase all data in the ".$print_to."config directory\n".
              "This data will be replaced with the data from ".$print_from."config\n".
              "The current config data will be backed up in ".$print_to."config.preclone\n".
              "Do you wish to continue?";
    if (y_or_n("$msg")){
        system("rm -rf $to/config.preclone");
        system("mv $to/config $to/config.preclone") if (-d "$to/config");
        my $confdir="config";
        $confdir="opt/vyatta/etc/config" if ($f_topdir eq "disk-install");
        if (rsync("$from/$confdir", $to) > 0){
            print "Clone Failed!\nRestoring old config\n";
            system("mv $to/config.preclone $to/config");
        }
    }
}

sub rsync {
    my ($from,$to) = @_;
    system("rsync -a --progress --exclude '.wh.*' $from $to");
    return $?;
}

sub upload {
    my ($from, $to) = @_;
    system("python3 -c 'from vyos.remote import upload; upload(\"$from\", \"$to\")'")
}

sub download {
    my ($from, $to) = @_;
    system("python3 -c 'from vyos.remote import download; download(\"$to\", \"$from\")'");
}

sub friendly_download {
    my ($from, $to) = @_;
    system("python3 -c 'from vyos.remote import friendly_download; friendly_download(\"$to\", \"$from\")'");
}

sub y_or_n {
    my ($msg) = @_;
    my $process_client = $ENV{'VYATTA_PROCESS_CLIENT'};
    if (defined $process_client){
        return 1 if ($process_client =~ /gui2_rest/);
    }
    print "$msg (Y/N): ";
    my $input = <>;
    return 1 if ($input =~ /Y|y/);
    return 0;
}

sub show {
    my ($topdir, $file) = conv_file(pop(@_));
    my $output = "";
    if ($topdir eq 'url'){
        print "Cannot show files from a url\n";
        exit 1;
    }
    if (-d $file) {
        print "########### DIRECTORY LISTING ###########\n";
        system("ls -lGph  --group-directories-first $file");
    } elsif (-T $file) {
        print "########### FILE INFO ###########\n";
        my $filename = conv_file_to_rel($topdir, $file);
        print "File Name: $filename\n";
        print "Text File: \n";
        my $lsstr = `ls -lGh $file`;
        parsels($lsstr);
        print "  Description:\t";
        system("file -sb $file");
        print "\n########### FILE DATA ###########\n";
        system("cat $file");
    } elsif ($file =~ /.*\.pcap/){
        print "########### FILE INFO ###########\n";
        my $filename = conv_file_to_rel($topdir, $file);
        print "File Name: $filename\n";
        print "Binary File: \n";
        my $lsstr = `ls -lGh $file`;
        parsels($lsstr);
        print "  Description:\t";
        system("file -sb $file");
        print "\n########### FILE DATA ###########\n";
        system("sudo tshark -r $file | less");
    } elsif (-B $file) {
        print "########### FILE INFO ###########\n";
        my $filename = conv_file_to_rel($topdir, $file);
        print "File Name: $filename\n";
        print "Binary File: \n";
        my $lsstr = `ls -lGh $file`;
        parsels($lsstr);
        print "  Description:\t";
        system("file -sb $file");
        print "\n########### FILE DATA ###########\n";
        system("hexdump -C $file| less");
    } else {
        my $filename = conv_file_to_rel($topdir, $file);
        print "File: $filename not found\n";
    }
}

sub parsels {
    my $lsout = pop(@_);
    my @ls = split(' ', $lsout);
    print "  Permissions: $ls[0]\n";
    print "  Owner:\t$ls[2]\n";
    print "  Size:\t\t$ls[3]\n";
    print "  Modified:\t$ls[4] $ls[5] $ls[6]\n";
}