#ver 0.06 (C)Cyr use strict; use warnings; use diagnostics; use IO::Socket; use Convert::ASN1; #use Data::Dumper; use Carp; use POSIX; my $CSTAapdu; my $socket; my %calls; sub decode_msg_header { my $bin = shift; my $len = unpack( 'n', $bin ); return $len; } sub encode_msg_header { my $len = shift; 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); $socket->write($pdu); # my $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 $pdu = receive_stuff(); my $hexdata = convert_to_hex($pdu); if ( $hexdata =~ /A2 03 02 01 01/ ) { print "rejected-permanent\n"; exit 0; } #SystemStatus Request $pdu = receive_stuff(); my $out = $CSTAapdu->decode($pdu); my $invokeID = $out->{svcRequest}->{invokeID}; SystemStatusResult($invokeID); } sub open_csta_socket { my $host = shift; my $port = shift; $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 ) { # фрагмент пакета my $header2; my $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 ); my $len = decode_msg_header($header); $nbytes = $socket->sysread( $pdu, $len ); if ( $nbytes < $len ) { # фрагмент пакета my $pdu2; my $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 SystemStatusResult { my $invokeID = shift; my $pdu = $CSTAapdu->encode( { svcResult => { invokeID => $invokeID, result => { serviceID => 211, serviceResult => { noData => 1 } } } } ); send_pdu($pdu); # send SystemStatus Result } sub playOGM { my $ogmId = shift; if ( !$ogmId ) { $ogmId = 10 } my $connectionID = shift; my $pdu = $CSTAapdu->encode( { svcRequest => { invokeID => 11, serviceID => 51, serviceArgs => { privateData => { private => { kmeResourceControl => { ogmStart => { connection => $connectionID, ogmId => $ogmId } } } } } } } ); send_pdu($pdu); } sub numberOfMsgPort { #EscapeArgument.privateData.private.kmeSystemData.getSystemData.request my $pdu = $CSTAapdu->encode( { svcRequest => { invokeID => 8, serviceID => 51, serviceArgs => { privateData => { private => { kmeSystemData => { getSystemData => { request => { systemData => 18 } } } } } } } } ); send_pdu($pdu); while (1) { $pdu = receive_stuff(); my $out = $CSTAapdu->decode($pdu); if ( defined $out->{svcRequest}->{serviceArgs}->{privateData}->{private} ->{kmeSystemData}->{systemDataLinkedReply}->{sysData} ->{numberOfMsgPort} ) { my $MsgPorts = $out->{svcRequest}->{serviceArgs}->{privateData}->{private} ->{kmeSystemData}->{systemDataLinkedReply}->{sysData} ->{numberOfMsgPort}; return $MsgPorts; } } } sub answer { my $callerID = shift; my $connectionID = shift; my $MsgPorts = numberOfMsgPort(); #берём трубку my $pdu = $CSTAapdu->encode( { svcRequest => { invokeID => 10, serviceID => 2, serviceArgs => { callToBeAnswered => $connectionID } } } ); send_pdu($pdu); my $callID = $connectionID->{both}->{callID}; print "answered callID:", $callID, " callerID:", $callerID, "\n"; my $numberOfFreePort = $MsgPorts->{numberOfFreePort}; print "numberOfFreePort:", $numberOfFreePort, "\n"; if ( !$numberOfFreePort ) { my $pdu = $CSTAapdu->encode( { svcRequest => { invokeID => 13, serviceID => 5, serviceArgs => { connectionToBeCleared => $connectionID } } } ); send_pdu($pdu); print "connection callID:", $callID, " cleared\n"; next; } my $digits = [ split( '', $callerID ) ]; $calls{$callID} = $digits; print "digits in the array:", scalar @{ $calls{$callID} }, "\n"; my $digit = shift @{ $calls{$callID} }; playOGM( $digit, $connectionID ); } # parse ASN.1 desciptions my $asn = Convert::ASN1->new; $asn->prepare_file('d:\111\asn_perl\kxtde.asn') or die "prepare: ", $asn->error; my %serviceArgs = ( 2 => 'AnswerCallArgument', 5 => 'ClearConnectionArgument', 21 => 'CSTAEventReportArgument', 51 => 'EscapeArgument', # 10=> 'MakeCallArgument', 71 => 'MonitorStartArgument', 211 => 'SystemStatusArg' ); foreach ( keys %serviceArgs ) { $asn->registertype( 'serviceArgs', $_, $asn->find( $serviceArgs{$_} ) ); } my %serviceResults = ( 51 => 'EscapeResult', # 10=> 'MakeCallResult', 71 => 'MonitorStartResult', 211 => 'SystemStatusRes' ); foreach ( keys %serviceResults ) { $asn->registertype( 'serviceResult', $_, $asn->find( $serviceResults{$_} ) ); } $CSTAapdu = $asn->find('CSTAapdu'); csta_connect( { 'host' => '192.168.0.101', 'port' => 33333 } ); my $Number = 177; # ! ICD номер my $MsgPorts = numberOfMsgPort(); print "numberOfMsgPort:", $MsgPorts->{numberOfMsgPort}, "\n"; #EscapeArgument.privateData.private.kmeSystemData.setSystemData my $pdu = $CSTAapdu->encode( { svcRequest => { invokeID => 9, serviceID => 51, serviceArgs => { privateData => { private => { kmeSystemData => { setSystemData => { acdQueue => { device => { deviceIdentifier => { dialingNumber => $Number } }, attribute => { acdMode => 1 } } } } } } } } } ); send_pdu($pdu); #EscapeArgument.privateData.private.kmeSystemData.setSystemData $pdu = $CSTAapdu->encode( { svcRequest => { invokeID => 9, serviceID => 51, serviceArgs => { privateData => { private => { kmeSystemData => { setSystemData => { acdQueue => { device => { deviceIdentifier => { dialingNumber => $Number } }, attribute => { ctiWaitTime => 20 } } } } } } } } } ); send_pdu($pdu); #monitor $pdu = $CSTAapdu->encode( { svcRequest => { invokeID => 9, serviceID => 71, serviceArgs => { monitorObject => { deviceObject => { deviceIdentifier => { dialingNumber => $Number } } }, requestedMonitorFilter => {} } } } ); send_pdu($pdu); while (1) { $pdu = receive_stuff(); #Convert::ASN1::asn_dump($pdu); my $out = $CSTAapdu->decode($pdu); # $Data::Dumper::Indent=1; # $Data::Dumper::Pair=' '; # $Data::Dumper::Quotekeys=0; # $Data::Dumper::Varname='CSTAapdu'; #print Dumper($out); if ( defined $out->{svcRequest} ) { my $serviceID = $out->{svcRequest}->{serviceID}; my $invokeID = $out->{svcRequest}->{invokeID}; my $serviceArgs = $out->{svcRequest}->{serviceArgs}; if ( $serviceID == 21 ) { if ( defined $serviceArgs->{eventSpecificInfo}->{callControlEvents} ->{delivered} ) { my $connectionID = $serviceArgs->{eventSpecificInfo}->{callControlEvents} ->{delivered}->{connection}; if ( defined $serviceArgs->{eventSpecificInfo} ->{callControlEvents}->{delivered}->{callingDevice} ->{deviceIdentifier}->{deviceIdentifier}->{dialingNumber} ) { my $callerID = $serviceArgs->{eventSpecificInfo}->{callControlEvents} ->{delivered}->{callingDevice}->{deviceIdentifier} ->{deviceIdentifier}->{dialingNumber}; answer( $callerID, $connectionID ); } elsif ( $serviceArgs->{eventSpecificInfo}->{callControlEvents} ->{delivered}->{extensions}->{privateData}[0]->{private} ->{kmeAdditionalData}->{device}->{deviceIdentifier} ->{other} ) { my $callerID = $serviceArgs->{eventSpecificInfo}->{callControlEvents} ->{delivered}->{extensions}->{privateData}[0]->{private} ->{kmeAdditionalData}->{device}->{deviceIdentifier} ->{other}; substr( $callerID, 0, 1 ) = ""; answer( $callerID, $connectionID ); } else { print "not number\n" } } elsif ( $serviceArgs->{eventSpecificInfo}->{callControlEvents} ->{transferred} ) { my $callID = $serviceArgs->{eventSpecificInfo}->{callControlEvents} ->{transferred}->{transferredConnections}[0]->{newConnection} ->{both}->{callID}; my $oldCallID = $serviceArgs->{eventSpecificInfo}->{callControlEvents} ->{transferred}->{primaryOldCall}->{both}->{callID}; $calls{$callID} = $calls{$oldCallID}; delete $calls{$oldCallID}; print "transferred: new callID:", $callID, "\n"; } elsif ( defined $serviceArgs->{eventSpecificInfo}->{vendorSpecEvents} ->{privateEvent}->{privateData}->{private}->{kmePrivateEvent} ->{ogmStatus} ) { my $ogmStatus = $serviceArgs->{eventSpecificInfo}->{vendorSpecEvents} ->{privateEvent}->{privateData}->{private}->{kmePrivateEvent} ->{ogmStatus}; print "ogmPortNumber:", $ogmStatus->{ogmPortNumber}->{deviceIdentifier} ->{deviceNumber} & 0xFFFF; print " ogmId:", $ogmStatus->{ogmId}; if ( $ogmStatus->{state} ) { print " state:stop\n"; my $connectionID = $ogmStatus->{connection}; my $callID = $connectionID->{both}->{callID}; if ( scalar @{ $calls{$callID} } ) { print "digits in the array:", scalar @{ $calls{$callID} }, "\n"; my $digit = shift @{ $calls{$callID} }; playOGM( $digit, $connectionID ); } else { delete $calls{$callID}; # кладём трубку my $pdu = $CSTAapdu->encode( { svcRequest => { invokeID => 13, serviceID => 5, serviceArgs => { connectionToBeCleared => $connectionID } } } ); send_pdu($pdu); print "connection callID:", $callID, " cleared\n"; } } else { print " state:start\n" } } } elsif ( $serviceID == 211 ) { # if SystemStatus Request SystemStatusResult($invokeID); } } }