use POSIX;
use Carp;
#use Data::Dumper;
use IO::Socket;
sub decode_msg_header {
	my $bin = shift;
	my $len = unpack('n', $bin);
	return $len;
}
sub encode_msg_header {
	my $len = shift;
#	print("len: [$len]\n"); 
	die "Message larger than allowed!" unless ($len <= 240);
	my $bin = pack('n', $len);
	return $bin;
}
sub convert_to_hex {
	my $pdu = $_[0];
	my $hexdata = unpack('H*', $pdu);
	$hexdata =~ tr/a-z/A-Z/;
	$hexdata =~ s/(..)/$1 /g;
	$hexdata =~ s/ $//g;
	return $hexdata;
}
sub send_pdu {
	my $pdu = $_[0];
	my $header = encode_msg_header(length($pdu));
	$socket->write($header); 
	$headerdata = convert_to_hex($header);
#	print("SENT HEADER: [$headerdata]\n");
	$socket->write($pdu);
	$hexdata = convert_to_hex($pdu);
#	print("SENT:    [$hexdata]\n"); 
} 
sub csta_connect {
	my %args = %{$_[0]}; 
	open_csta_socket($args{host}, $args{port});
	# A-ASSOCIATE Request
	my $pdu = "602380020780A10706052B0C00815ABE14281206072B0C00821D8148A007A0050303000800";
        $pdu = pack('H*', $pdu);
	send_pdu($pdu);
	# A-ASSOCIATE Result 
	receive_stuff();
} 
sub open_csta_socket {
	my $host = shift;
	my $port = shift;
#	print("trying to open a connection to $host on port $port\n");
	$socket = new IO::Socket::INET(
        PeerAddr => $host,
        PeerPort => $port,
		Blocking => 1,
		Proto => 'tcp') || die "Error creating socket: $!\n";
	$socket->autoflush(1);
	print("opened a connection to $host on port $port\n");
}	
sub receive_stuff {
	my $header = '';
	my $pdu = '';
	my $nbytes = $socket->sysread($header, 2);
	if ($nbytes==1) { # фрагмент пакета
#		print("RECEIVED fragment".chr(7)."\n");
		$nbytes2= $socket->sysread($header2, 1);
		$header = $header.$header2;
		$nbytes = 2;
	} 
	croak "Didn't receive the specified amount of data (2 bytes)!\n".chr(7) unless ($nbytes == 2);
#	print("Received 2 bytes, assuming it's a data length\n");
	my $len = decode_msg_header($header);
#	print("Waiting for [$len] bytes of ASN1 data now\n");
	$nbytes = $socket->sysread($pdu, $len);
	if ($nbytes<$len) { # фрагмент пакета
#		print("RECEIVED fragment".chr(7)."\n");
		$nbytes2= $socket->sysread($pdu2, $len-$nbytes);
		$pdu = $pdu.$pdu2;
		$nbytes = $nbytes + $nbytes2;
	}  
	croak "Didn't receive the specified amount of data ($len bytes)!\n".chr(7) unless ($nbytes == $len);
	my $hexdata = convert_to_hex($pdu);
#	print("RECEIVED:[$hexdata]\n");
	return $pdu;
}
sub main_loop {
	while (1) {
		my $pdu = receive_stuff();
		my $hexdata = convert_to_hex($pdu);
		# If SystemStatus Request
		if ($hexdata =~/A1 0C 02 01 .. 02 02 00 D3 30 03 0A 01 02/) {
			# SystemStatus Response
			my $pdu = "A20B0201".substr($hexdata, 12, 2)."3006020200D30500";
			$pdu = pack('H*', $pdu);
			send_pdu($pdu);
			}
		# If SystemStatus Request 2
		elsif ($hexdata =~/A1 0D 02 02 .. .. 02 02 00 D3 30 03 0A 01 02/){
			# SystemStatus Response 2
			my $pdu = "A20C0202".substr($hexdata, 12, 2).substr($hexdata, 15, 2)."3006020200D30500";
			$pdu = pack('H*', $pdu);
			send_pdu($pdu);
			}
		# if localConnectionInfo=alerting and cause=newCall|distributed
		elsif ($hexdata =~m/4E 01 02 0A 01 [12]6/) {
			# звонок от
			if ($hexdata =~m/61 .. 30 .. 80 /) {
				$num = hex(substr($', 0, 2));
				$str = substr($', 3, $num*3);
				$str =~s/\s//g;
				$CallerID=pack ("H*", $str); 				
		    } else {
				$CallerID="CO".substr($hexdata, length($hexdata)-2, 2);
		    }
			# звонок кому
			if ($hexdata =~m/63 .. 30 .. 80 /) {
				$num = hex(substr($', 0, 2));
				$str = substr($', 3, $num*3);
				$str =~s/\s//g;
				$CalledID=pack ("H*", $str);
			}
			print strftime("%H:%M:%S ", localtime);
			print("Call to:$CalledID from:$CallerID\n");
		}
	}
}
sub MonitorStart{
	my $ext = shift;
	$ext =~s/(.)/sprintf("%02x",ord($1))/eg;
	my $pdu = "A111020178020147300930058003".$ext."A000";
	$pdu = pack('H*', $pdu);
	send_pdu($pdu);
	$pdu = receive_stuff();
}
csta_connect({'host'=>'192.168.0.101', 'port'=>33333});
for ($ext_num = 101; $ext_num <=156; $ext_num++){
	MonitorStart($ext_num);
}
main_loop();