#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); } } }