#!/usr/bin/perl

use IO::Socket::INET;
use Getopt::Std;
use Digest::MD5;

$VERSION = '0.35';
$PROTO_LEVEL = 1;

# Get options
getopts( 'p:P:A:', \%opts );

$what = shift( @ARGV );
$server = shift( @ARGV );

if( ! defined( $server ) )
{
	$script = $0;
	$script =~ s#^.*/##;
	die( "Usage:\n" .
		"$script [-A(y|n|d)] [-p PORT] [-P user%password] package server\n" .
		" -A  Ask before updating file, y/n/d is default\n" .
		"\n" .
		" ** note: user/pass not implemented\n" .
		"\n" );
}

$port = $opts{ p } || 1232;

print "Connecting to $server:$port\n";
$sock = IO::Socket::INET -> new( PeerAddr => $server,
					PeerPort => $port
				);

if( ! $sock )
{
	die( "Unable to connect\n" );
}

# Announce our package, and get ok
say( $what, $PROTO_LEVEL );
getok();

print "Connected!\n";

# Now the main loop.  The server will send a filename, we need to reply with
# the MD5.  It will then either reply with OK if we're good, or
# size,XXX if we need to read a file and save it under the filename
# If the filename is undefined, then exit (done)
while( 1 )
{
	@l = getjoo();

	$what = $l[ 0 ];
	if( $what eq "file" )
	{
		process_file( $l[ 1 ] );
	}elsif( $what eq "dir" )
	{
		# Just make the dir
		if( ! -d $l[ 1 ] )
		{
			print "Creating directory: $l[1]\n";
			system( "mkdir", "-p", $l[ 1 ] );
		}else
		{
			print "Directory $l[1]... Dir OK\n";
		}
	}elsif( $what eq "perm" )
	{
		@stat = stat( $l[ 1 ] );
		if( $stat[ 2 ] != $l[ 2 ] )
		{
			print "Stats do not match: " . $stat[2] . "/" . $l[2] . "\n";
			chmod $l[ 2 ], $l[ 1 ];
			print "   stats fixed\n";
		}
	}elsif( $what eq "end" )
	{
		print "End success\n";
		exit;
	}else
	{
		print "Unknown op: $what\n";
	}
}



sub getjoo
{
	my $l;
	
	$l = $sock -> getline();

	if( $l !~ /^joo:/ )
        {
		# Lost connection or protocol error
		print "Lost connection or protocol error: $l\n";
		exit;
	}

	chomp( $l );
	$l =~ s/^joo://;
	return( split( /\t/, $l ) );
}

sub say
{
	$sock -> print( "joo:" . join( "\t", @_ ) . "\n" );
}

sub getok
{
	my @l = getjoo();
	if( $l[ 0 ] ne "OK" )
	{
		print "Error, expected ok: @l\n";
		exit;
	}
}

sub process_file
{
	my $filename = shift;
	my( @l, $dgst, $file, $md5, $write, $tempfile);

	print "Checking $filename...  ";

	# Make an MD5
	$dgst = Digest::MD5 -> new();
	open( MD5, $filename );
	$dgst -> addfile( MD5 );
	$md5 = $dgst -> hexdigest();
	close( MD5 );

	say( $md5 );

	@l = getjoo();

	# OK, now if it said OK go on, else get a file
	if( $l[ 0 ] eq "size" )
	{
		# Get file, argv1 is the size to read
		print "MD5 signature rejected\n";

		$size = $l[ 1 ];
		print "New file is $size bytes, transferring\n";

		$sock -> read( $file, $size );

		$tempfile = $filename . ".tmp.$$.bangkorg";

		open( OUT, ">$tempfile" );
		print OUT $file;
		close( OUT );

		if( ( $opts{ A } ) && ( -f $filename ) )
		{
			# Skip asking if file doesn't exist
			$write = -1;
				

			while( $write == -1 )
			{
				print "Overwrite file? [y]es/[n]o/[d]iff  ($opts{A})> ";
				chomp( $key = <STDIN> );

				if( ! $key )
				{
					$key = $opts{ A };
				}

				if( $key =~ /^y/i )
				{
					$write = 1;
				}elsif( $key =~ /^d/i )
				{
					# Diff
					system( "diff -c $filename $tempfile" );
					$write = -1;
				}else
				{
					$write = 0;
				}
			}
		}else
		{
			if( ! -f $filename )
			{
				print " --> NEW FILE!\n";
			}

			$write = 1;
		}

		if( $write )
		{
			print "Writing file...\n";
			open( OUT, ">$filename" );
			print OUT $file;
			close( OUT );
		}else
		{
			print "NOT WRITING\n";
		}

		# Unlink the temp file
		unlink( "$tempfile" );
	}else
	{
		print "File OK\n";
	}
}
