#! /usr/bin/perl -w
# pd100_get2.pl - a client for bsti pd100 ip cameras
# modified by Patrick Salecker
# added support for my camera and login password
# original version: http://217.20.164.161/pd100_get.pl.txt
#----------------
use strict;
use Socket;
use IO::Handle;

our ($typacket, $dopacket);

my ($pipe, $host, $port, $password, $proto, $iaddr, $paddr, $pid, $buf, $client_hash, $dsize, $file_to_save, $interval, $jpgcode);

# settings
$host = "192.168.1.102";
$port = 80;
$password ="";
$file_to_save="image.jpg";
$interval=.1;

#############################################################
# IF $typacket == 0x4f
# dopacket:
# -> - to camera
# <- - from camera
#############################################################
#t/f hex explanation
# -> 00 - reset camera's config for logged user
# <- 01 - show camera's mac address
# -> 02 - login info sending to camera
# <- 03 - login answer from camera (access/deny)
# -> 10 - clearing something ????
# <- 16 - answer to "10", maybe cleared ????
# -> 04 - something setup asking ????
# <- 11 - some code sended (answer)
# <- 05 - again something sended
##############################################################
#$typacket == 0x56
##############################################################
# -> 00 - send code gotted from 05 in 0x04f setup (see upper)
##############################################################
#$typacket == 0x4f
##############################################################
# -> 07 - clearing something (or say "start")
##############################################################
#$typacket == 0x56
##############################################################
# <- 01 - sending data
##############################################################

sub makepacket {
	my $data = $_[0];
	my $strsize=length($data);
	my $dsize=$strsize/2;
	$strsize = $strsize+46;
	return pack("H".$strsize,"4d4f5f".$typacket.unpack("H2",pack("i",$dopacket))."00000000000000000000".unpack("H8",pack("i",$dsize)).unpack("H8",pack("i",$dsize)).$data);
}

sub countpacketdata {
	my $buf = $_[0];
	# debug
	#my $data="4d4f5f4f01000000000000000000001b0000001b00000000003130333637353432333243410000000001000000000600000e";
	#$buf=pack("H100",$data);
	#print $buf;
	
	if ($buf =~ m/^\x4d\x4f\x5f(.)(.)\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00(.{4})(.{4}).*/){
		$typacket = unpack("H2",$1);
		$dopacket = unpack("c",$2);
		my $psize=  unpack("v",$3);
		my $psizecheck=  unpack("v",$4);
		if ($psize == $psizecheck){
			return $psize;
		} else {
			return 0;
		}
	} else {
		return 0;
	}
}

# initialize host and port
$proto = getprotobyname('tcp');
# get the port address
$iaddr = inet_aton($host);
$paddr = sockaddr_in($port, $iaddr);

socketpair(CHILD, PARENT, AF_UNIX, SOCK_STREAM, PF_UNSPEC) or  die "socketpair: $!";
CHILD->autoflush(1);
PARENT->autoflush(1);

if($pid = fork()) { # Parent
    print "parent\n";
    close PARENT;

    # create the socket, connect to the port
    socket(SOCK_CTRL, PF_INET, SOCK_STREAM, $proto) or die "socket: $!";
    binmode(SOCK_CTRL);
    connect(SOCK_CTRL, $paddr) or die "connect: $!";
    
    $typacket="4f";
    $dopacket=0;
    
    $buf=makepacket("");
    send(SOCK_CTRL, $buf, 0);
    read(SOCK_CTRL,$buf,23);
	
    $dsize=countpacketdata($buf); # $dopacket & $typacket - changed too!!
	
    #debug
    #print $dsize."\n-\n";
    #print $typacket."\n-\n";
    #print $dopacket."\n-\n";
    
    read(SOCK_CTRL,$buf,$dsize);
    if ($dopacket==1){
        print "Connected to MAC:".substr($buf,2,12)."\n";
    } else {
        print "Connected, but don't know MAC!\n";
    }
	$dopacket=2;
	
    # login to camera (just "admin", no password)
    #$buf=makepacket("61646d696e00000000000000000000000000000000bb76cbb7dd");
	# login to camera (just "admin", "test")
    #$buf=makepacket("61646D696E00382E312E31003074657374000000000000000000");
	$buf=makepacket("61646D696E0000000000000000".unpack("H*", $password)."0" x (26-(length($password)*2)));
	
    send(SOCK_CTRL, $buf, 0);
    read(SOCK_CTRL,$buf,23);
    $dsize=countpacketdata($buf); # $dopacket & $typacket - changed too!!
	
    read(SOCK_CTRL,$buf,$dsize);
    if ((unpack("H6",$buf) eq "000002") && ($dopacket==3)){
        print "login OK!\n";
    } else {
        print "ERROR: wrong login or packet cmd\n";
    }
    
    $dopacket=16;
    
    $buf=makepacket("");
    send(SOCK_CTRL, $buf, 0);
    read(SOCK_CTRL,$buf,23);
    $dsize=countpacketdata($buf); # $dopacket & $typacket - changed too!!
    read(SOCK_CTRL,$buf,$dsize);
    
    if (($dopacket==22) && (unpack("H2",$buf) eq "00")){
        print "Answer to \"0x10\" OK!\n";
    } else {
		if ($dopacket==22) {
			print "Answer to \"0x10\" NOT OK!\n";
		} else {
			print "No answer to \"0x10\"!\n";
		}
    }
    
    $dopacket=4;
    
    $buf=makepacket("02");
    send(SOCK_CTRL, $buf, 0);
    # 1-st packer recv
	
	#skip useless data
    read(SOCK_CTRL,$buf,23);
    $dsize=countpacketdata($buf); # $dopacket & $typacket - changed too!!
    read(SOCK_CTRL,$buf,$dsize);
	
	read(SOCK_CTRL,$buf,23);
	$dsize=countpacketdata($buf);
	read(SOCK_CTRL,$buf,$dsize);
	
    if ($dopacket==17){
	print "Answer to \"0x04\" give: 0x".unpack("H".length($buf)*2,$buf)."\n";
    }
    
    # 2-nd packer recv
    read(SOCK_CTRL,$buf,23);
    $dsize=countpacketdata($buf); # $dopacket & $typacket - changed too!!
    read(SOCK_CTRL,$buf,$dsize);
    
    if ($dopacket==05){
		#print "And: 0x".unpack("H".length($buf)*2,$buf)." - too (hash to 2-nd socket)!\n";
		#################################################################################
		# picture socket code
		#################################################################################
		$client_hash=substr(unpack("H".length($buf)*2,$buf),4);
		print CHILD $client_hash."\n";
		print "Sended client hash to file:".$client_hash." ".length($client_hash)."\n";
		
		####################################
		# say to control socket "start"!
		$typacket="4f";
		$dopacket=7;
		$buf=makepacket("00000000");
		send(SOCK_CTRL, $buf, 0);
		####################################

		#################################################################################
    }
    
    for (;;){
		# 2-nd packer recv
		read(SOCK_CTRL,$buf,23);
		$dsize=countpacketdata($buf); # $dopacket & $typacket - changed too!!
		#read(SOCK_CTRL,$buf,$dsize);
		if ($dopacket=="-1"){
			print time()." Send keep-alive: ".$dopacket."\n";
			$buf=makepacket("");
			send(SOCK_CTRL, $buf, 0);
			# 1-st packer recv
		
		} else {
			print "Control received: 0x".unpack("H".length($buf)*2,$buf)." - unknown data!\n";
		}
	}
	
	waitpid($pid,0);
	
	####################################
	# say to control socket "stop"!
	$typacket="4f";
	$dopacket=6;
	$buf=makepacket("");
	send(SOCK_CTRL, $buf, 0);
	####################################
	
	close(SOCK_CTRL) or die "close: $!"; 
	close CHILD;

} elsif(defined $pid) { # Child
	print "children\n";
	close CHILD;
	chomp($buf = <PARENT>);
	print "getting hash\n";
	print $buf."<- got user hash\n";

	$typacket="56";
	$dopacket=0;
	$buf=makepacket($buf);
	
	socket(SOCK_GET, PF_INET, SOCK_STREAM, $proto) or die "socket: $!";
	binmode(SOCK_GET);
	connect(SOCK_GET, $paddr) or die "connect: $!";
	send(SOCK_GET, $buf, 0);
        
	####################################
	# loop for image gets
	do {
		read(SOCK_GET,$buf,23);
		$dsize=countpacketdata($buf); # $dopacket & $typacket - changed too!!
		
		if ($dsize > 0){
			print time()." got image \n";
			read(SOCK_GET,$buf,$dsize);
			# save to file
			open(FH, ">$file_to_save.tmp") or die "Can't open $file_to_save.tmp: $!";
			$jpgcode= substr($buf,13);
			print FH $jpgcode;
			close(FH) or die "close: $!"; 
			
			rename("$file_to_save.tmp", "$file_to_save");
			#sleep 1;
			select(undef,undef,undef,$interval);
	    }
	} while (($typacket eq "56") && ($dsize > 0));
	####################################
	close(SOCK_GET) or die "close: $!"; 
	close PARENT;
}
