#!/usr/bin/env perl

use Expect;
use Term::ReadKey;

$ENV{LC_ALL} = "C";

while( 1 )
{
	my $crt = @ARGV[0];
	if( $crt eq "" )
	{
		last;
	}
	my($sw) = $crt =~ m/^-(.*)$/;
	if( defined( $sw ) )
	{
		last;
	}
	if( $src eq "" )
	{
		$src = $crt;
	}
	else
	{
		if( $dst eq "" )
		{
			$dst = $crt;
		}
		else
		{
			print "Ambiguous destination.\n";
			exit( 1 );
		}
	}
	shift(@ARGV);
}


sub merge 
{
	open( IN3, "< $_[0]" );
	open( IN4, "< $_[1]" );
	open( OUT, "> $_[2]" );

	$on = "";
	while( $line4 = <IN4> )
	{
		my($nn, $ns, $nt) = $line4 =~ m/^(.*\\)(.*\\)(.*)$/;
		chop( $nn );
		chop( $ns );
		while( $nn gt $on )
		{
			if( $line3 = <IN3> )
			{
				($on, $os, $ot) = $line3 =~ m/^(.*\\)(.*\\)(.*)$/;
				chop( $on );
				chop( $os );
				next;
			}
			else
			{
				chop( $nn );
				print OUT "$nn\n";
				while( $line4 = <IN4> )
				{
					my($nn, ,) = $line4 =~ m/^(.*\\)(.*\\)(.*)$/;
					chop( $nn );
					chop( $nn );
					print OUT "$nn\n";
				}
				close( IN3 );
				close( IN4 );
				close( OUT );
				return;
			}
		}
		if( $nn eq $on )
		{
			if( $nn ne " " )
			{
				if( ($ns != $os) || ($nt > $ot) )
				{
					chop( $nn );
					print OUT "$nn\n";
				}
			}
		}
		else
		{
			chop( $nn );
			print OUT "$nn\n";
		}
	}
	close( IN3 );
	close( IN4 );
	close( OUT );
}


(my $srcuh, $srcfile) = $src =~ m/(.*:)(.*)/;
if( $srcuh eq "" )
{
	$srcfile = $src;
	$srcuser = "";
	$srchost = "";
}
else
{
	chop( $srcuh );
	($srcuser, $srchost) = $srcuh =~ m/(.*@)(.*)/;
	if( ($srcuser eq "") && ($srchost eq "") )
	{
		$srchost = $srcuh;
	}
	else
	{
		chop( $srcuser );
	}
}

if( $srcfile eq "" )
{
	print "No source file !?\n";
	exit( 1 );
}

(my $srcfiled, $srcfilep) = $srcfile =~ m/(.*\/)(.*)/;
if( $srcfiled eq "" )
{
	$srcfiled = ".";
	$srcfilep = $srcfile;
}
if( $srcfilep eq "" )
{
	$srcfilep = ".";
	$pp = "P";
}
else
{
	$pp = "p";
}

(my $dstuh, $dstfile) = $dst =~ m/^(.*:)(.*)$/;
if( $dstuh eq "" )
{
        $dstfile = $dst;
        $dstuser = "";
        $dsthost = "";
}
else
{
        chop( $dstuh );
        ($dstuser, $dsthost) = $dstuh =~ m/^(.*@)(.*)$/;
        if( ($dstuser eq "") && ($dsthost eq "") )
        {
                $dsthost = $dstuh;
        }
        else
        {
                chop( $dstuser );
        }
}

if( $dstfile eq "" )
{
	$dstfile = ".";
}

my $cdate = time();
my $ffile="/tmp/".$cdate;
my $nfile=$ffile.".n";
my $ofile=$ffile.".o";
my $lfile=$ffile.".l";

if( ($dsthost eq "") && ($dstuser eq "") )
{
	my $res = qx( cd $dstfile 2>&1 && find $srcfilep -printf "%$pp \\\\\\%s\\\\\\%T@\n" 2>/dev/null | sort >$ofile );
	if( $res ne "" )
	{
		die $res;
	}
}
else
{
	$cmd = "bbftp @ARGV -p 1 -e \"pipe cd $dstfile && find $srcfilep -printf \\\"%$pp \\\\\\\\\\\\%s\\\\\\\\\\\\%T@\n\\\"\" $dsthost 2>/dev/null | sort >$ofile";
	if( $dstuser ne "" )
	{
		$cmd =~ s/2>/-u $dstuser 2>/;
	}
	$command = Expect->spawn( $cmd ) or die "Couldn't start program: $!\n";
	while( $command->expect( 30, -re => 'assword' ) )
	{
	        ReadMode('noecho');
	        $dstpassword = ReadLine(0);
	        ReadMode('normal');
	        print $command $dstpassword;
	}
	while( 1 )
	{
	        $command->expect( 0 );
	        $es = $command->exitstatus();
	        if( defined( $es ) )
	        {
	                last;
	        }
	        sleep 1;
	}
}

sub finis
{
	unlink( $ofile );
	unlink( $nfile );
	unlink( $lfile );
	unlink( $ffile );

	if( !defined( $_[1] ) )
	{
		die $_[0];
	}
	else
	{
		exit( $_[0] ne "0" ? 1 : 0 );
	}
}

if( ($srchost eq "") && ($srcuser eq "") )
{
        my $res = qx( cd $srcfiled 2>&1 && find $srcfilep -printf "%$pp \\\\\\%s\\\\\\%T@\n" 2>/dev/null | sort >$nfile );
        if( $res ne "" )
        {
		finis( $res );
        }
}
else
{
        $cmd = "bbftp @ARGV -p 1 -e \"pipe cd $srcfiled && find $srcfilep -printf \\\"%$pp \\\\\\\\\\\\%s\\\\\\\\\\\\%T@\n\\\"\" $srchost 2>/dev/null | sort >$nfile";
        if( $srcuser ne "" )
        {
                $cmd =~ s/2>/-u $srcuser 2>/;
        }
        $command = Expect->spawn( $cmd ) or finis( "Couldn't start program: $!\n" );
        while( $command->expect( 30, -re => 'assword' ) )
        {
                ReadMode('noecho');
                $srcpassword = ReadLine(0);
                ReadMode('normal');
                print $command $srcpassword;
        }
        while( 1 )
        {
                $command->expect( 0 );
                $es = $command->exitstatus();
                if( defined( $es ) )
                {
                        last;
                }
                sleep 1;
        }
}

merge( $ofile, $nfile, $lfile );

if( $srchost eq "" )
{
	rename( $lfile, $ffile );
	chmod( $ffile, "+r" );
}
else
{
	$cmd = "cat $lfile | bbftp @ARGV -p 1 -e  \"pipe cat >$ffile\" $srchost 2>/dev/null";
	if( $srcuser ne "" )
	{
		$cmd =~ s/2>/-u $srcuser 2>/;
	}
	$command = Expect->spawn( $cmd ) or finis( "Couldn't start program: $!\n" );
	if( defined( $srcpassword ) )
	{
	        $command->log_stdout( 0 );
		if( $command->expect( 30, -re => 'assword' ) )
		{
	        	print $command $srcpassword;
		}
		$command->log_stdout( 1 );
	}
	while( 1 )
	{
	        $command->expect( 0 );
	        $es = $command->exitstatus();
	        if( defined( $es ) )
	        {
	                last;
	        }
	        sleep 1;
	}
}

if( ($srchost eq "") && ($srcuser eq "") )
{
	if( ($dsthost eq "") && ($dstuser eq "") )
	{
		my $out = qx( tar --totals --no-recursion -C $srcfiled --files-from=$ffile -c | tar --totals -v -x -C $dstfile );
		print $out;
	}
	else
	{
		$cmd = "tar --totals -v --no-recursion -C $srcfiled --files-from=$ffile -c | bbftp @ARGV -e \"pipe tar --totals -C $dstfile -x\" $dsthost";
		if( $dstuser ne "" )
		{
			$cmd = $cmd." -u $dstuser";
		}
		$command = Expect->spawn( $cmd ) or finis( "Couldn't start program: $!\n" );
		if( defined( $dstpassword ) )
		{
		        $command->log_stdout( 0 );
			if( $command->expect( 30, -re => 'assword' ) )
			{
		        	print $command $dstpassword;
			}
			$command->log_stdout( 1 );
		}
		while( 1 )
		{
		        $command->expect( 0 );
		        $es = $command->exitstatus();
		        if( defined( $es ) )
		        {
		                last;
		        }
		        sleep 1;
		}
	}
}
else
{
	if( ($dsthost eq "") && ($dstuser eq "") )
	{
		$cmd = "bbftp @ARGV -e \"pipe tar --totals --no-recursion -C $srcfiled --files-from=$ffile -c\" $srchost | tar --totals -v -x -C $dstfile";
		if( $srcuser ne "" )
		{
			$cmd =~ s/\|/-u $srcuser \|/;
		}
		$command = Expect->spawn( $cmd ) or finis( "Couldn't start program: $!\n" );
		if( defined( $srcpassword ) )
		{
		        $command->log_stdout( 0 );
			if( $command->expect( 30, -re => 'assword' ) )
			{
		        	print $command $srcpassword;
			}
			$command->log_stdout( 1 );
		}
		while( 1 )
		{
		        $command->expect( 0 );
		        $es = $command->exitstatus();
		        if( defined( $es ) )
		        {
		                last;
		        }
		        sleep 1;
		}
	}
	else
	{
		my $pfile=$ffile.".p";
		qx( mkfifo $pfile );

		$cmd1 = "bbftp @ARGV -e \"pipe tar --totals --no-recursion -C $srcfiled --files-from=$ffile -c\" $srchost >$pfile";
		if( $srcuser ne "" )
		{
			$cmd1 =~ s/\|/-u $srcuser \|/;
		}

		$cmd2 = "bbftp @ARGV -e \"pipe tar --totals -x -C $dstfile\" $dsthost <$pfile";
		if( $dstuser ne "" )
		{
			$cmd2 =~ s/</-u $dstuser </;
		}

		$command1 = Expect->spawn( $cmd1 ) or finis( "Couldn't start program: $!\n" );
		if( defined( $srcpassword )  )
		{
			$command1->log_stdout( 0 );
			if( $command1->expect( 30, -re => 'assword' ) )
                	{
                        	print $command1 $srcpassword;
                	}
			$command1->log_stdout( 1 );
		}

		$command2 = Expect->spawn( $cmd2 ) or finis( "Couldn't start program: $!\n" ) ;
		if( defined( $dstpassword )  )
		{
			$command2->log_stdout( 0 );
			if( $command2->expect( 30, -re => 'assword' ) )
			{
				print $command2 $dstpassword;
			}
			$command2->log_stdout( 1 );
		}

		while( 1 )
                {
                        $command1->expect( 0 );
                        $es1 = $command1->exitstatus();
                        $command2->expect( 0 );
                        $es2 = $command2->exitstatus();
                        if( defined( $es1 ) && defined( $es2 ) )
                        {
				$es = $es1 + $es2;
                                last;
                        }
                        sleep 1;
                }
		unlink( $pfile );
	}
}

finis( $es, "yes!" );
