X-Git-Url: http://dxcluster.org/gitweb/gitweb.cgi?a=blobdiff_plain;f=perl%2FDXProt.pm;h=0280793756c7556972f435bd897e64769adbe5ae;hb=43d1c9f4ff26d0ee9afbb54e7fb90701a9d4e694;hp=936ba90a251b4872542b8539861a4e9cdb2be79e;hpb=88665a2bed3b9ec9e97237938a95a045b2a21bb4;p=spider.git diff --git a/perl/DXProt.pm b/perl/DXProt.pm index 936ba90a..02807937 100644 --- a/perl/DXProt.pm +++ b/perl/DXProt.pm @@ -27,6 +27,7 @@ use Local; use DXDb; use AnnTalk; use Geomag; +use WCY; use Time::HiRes qw(gettimeofday tv_interval); use strict; @@ -36,7 +37,6 @@ use vars qw($me $pc11_max_age $pc23_max_age $allowzero $decode_dk0wcy); $me = undef; # the channel id for this cluster -$decode_dk0wcy = undef; # if set use this callsign to decode announces from the EU WWV data beacon $pc11_max_age = 1*3600; # the maximum age for an incoming 'real-time' pc11 $pc23_max_age = 1*3600; # the maximum age for an incoming 'real-time' pc23 @@ -81,7 +81,6 @@ sub init sub new { my $self = DXChannel::alloc(@_); - $self->{'sort'} = 'A'; # in absence of how to find out what sort of an object I am return $self; } @@ -106,6 +105,7 @@ sub start # get the INPUT filters (these only pertain to Clusters) $self->{inspotfilter} = Filter::read_in('spots', $call, 1); $self->{inwwvfilter} = Filter::read_in('wwv', $call, 1); + $self->{inwcyfilter} = Filter::read_in('wcy', $call, 1); $self->{inannfilter} = Filter::read_in('ann', $call, 1); # set unbuffered and no echo @@ -156,7 +156,7 @@ sub normal # process PC frames my ($pcno) = $field[0] =~ /^PC(\d\d)/; # just get the number return unless $pcno; - return if $pcno < 10 || $pcno > 51; + return if $pcno < 10 || $pcno > 99; # dump bad protocol messages unless it is a PC29 if ($line =~ /\%[0-9A-F][0-9A-F]/o && $pcno != 29) { @@ -222,12 +222,13 @@ sub normal } # are any of the crucial fields invalid? - if ($field[2] =~ /[a-z]/ || $field[6] =~ /[a-z]/ || $field[7] =~ /[a-z]/) { - dbg('chan', "Spot contains lower case callsigns, rejected"); + if ($field[2] =~ /(?:^\s*$|[a-z])/ || $field[6] =~ /(?:^\s*$|[a-z])/ || $field[7] =~ /(?:^\s*$|[a-z])/) { + dbg('chan', "Spot contains lower case callsigns or blanks, rejected"); return; } # do some de-duping + $field[5] =~ s/^\s+//; # take any leading blanks off if (Spot::dup($field[1], $field[2], $d, $field[5])) { dbg('chan', "Duplicate Spot ignored\n"); return; @@ -242,6 +243,20 @@ sub normal # you should be able to route on any of these # + # fix up qra locators of known users + my $user = DXUser->get_current($spot[4]); + if ($user) { + my $qra = $user->qra; + unless ($qra && DXBearing::is_qra($qra)) { + my $lat = $user->lat; + my $long = $user->long; + if (defined $lat && defined $long) { + $user->qra(DXBearing::lltoqra($lat, $long)); + $user->put; + } + } + } + # local processing my $r; eval { @@ -260,6 +275,7 @@ sub normal if ($pcno == 12) { # announces # announce duplicate checking + $field[3] =~ s/^\s+//; # remove leading blanks if (AnnTalk::dup($field[1], $field[2], $field[3])) { dbg('chan', "Duplicate Announce ignored\n"); return; @@ -278,13 +294,6 @@ sub normal # send it $self->send_announce($line, @field[1..6]); - - if ($decode_dk0wcy && $field[1] eq $decode_dk0wcy) { - my ($hour, $k, $next, $a, $r, $sfi, $alarm) = $field[3] =~ /^Aurora Beacon\s+(\d+)UTC,\s+Kiel\s+K=(\d+),.*ed\s+K=(\d+),\s+A=(\d+),\s+R=(\d+),\s+SFI=(\d+),.*larm:\s+(\w+)/; - $alarm = ($alarm =~ /^Y/i) ? ', Aurora in DE' : ''; - my $wwv = Geomag::update($main::systime, $hour, $sfi, $a, $k, "R=$r, Next K=$next$alarm", $decode_dk0wcy, $field[5], $r) if $sfi && $r; - } - } else { $self->route($field[2], $line); } @@ -601,7 +610,12 @@ sub normal $self->send(pc35($main::mycall, $field[2], "$main::mycall:your attempt is logged, Tut tut tut...!")); } } else { - $self->route($field[1], $line); + my $ref = DXUser->get_current($field[1]); + if ($ref && $ref->is_clx) { + route($field[1], pc84($field[2], $field[1], $field[2], $field[3])); + } else { + $self->route($field[1], $line); + } } return; } @@ -615,7 +629,12 @@ sub normal delete $rcmds{$field[2]} if !$dxchan; } } else { - $self->route($field[1], $line); + my $ref = DXUser->get_current($field[1]); + if ($ref && $ref->is_clx) { + route($field[1], pc85($field[2], $field[1], $field[2], $field[3])); + } else { + $self->route($field[1], $line); + } } return; } @@ -649,6 +668,8 @@ sub normal my ($lat, $long) = DXBearing::stoll($field[3]); $user->lat($lat); $user->long($long); + my $qra = $user->qra || DXBearing::lltoqra($lat, $long); + $qra = DXBearing::lltoqra($lat, $long) unless DXBearing::is_qra($qra); } elsif ($field[2] == 4) { $user->homenode($field[3]); } @@ -694,7 +715,7 @@ sub normal my $s = sprintf "%.2f", $t; my $ave = sprintf "%.2f", $tochan ? ($tochan->{pingave} || $t) : $t; $dxchan->send($dxchan->msg('pingi', $field[2], $s, $ave)) - } elsif ($dxchan->is_ak1a) { + } elsif ($dxchan->is_node) { if ($tochan) { $tochan->{nopings} = 2; # pump up the timer push @{$tochan->{pingtime}}, $t; @@ -715,15 +736,102 @@ sub normal } return; } + + if ($pcno == 73) { # WCY broadcasts + + # do some de-duping + my $d = cltounix($field[1], sprintf("%02d18Z", $field[2])); + if (($pcno == 23 && $d < $main::systime - $pc23_max_age) || $d > $main::systime + 1500 || $field[2] < 0 || $field[2] > 23) { + dbg('chan', "WCY Date ($field[1] $field[2]) out of range"); + return; + } + @field = map { unpad($_) } @field; + if (WCY::dup($d,@field[3..7])) { + dbg('chan', "Dup WCY Spot ignored\n"); + return; + } + + my $wcy = WCY::update($d, @field[2..12]); + + my $rep; + eval { + $rep = Local::wwv($self, @field[1..12]); + }; + # dbg('local', "Local::wcy error $@") if $@; + return if $rep; + + # broadcast to the eager world + send_wcy_spot($self, $line, $d, @field[2..12]); + return; + } + + if ($pcno == 84) { # remote commands (incoming) + if ($field[1] eq $main::mycall) { + my $ref = DXUser->get_current($field[2]); + my $cref = DXCluster->get($field[2]); + Log('rcmd', 'in', $ref->{priv}, $field[2], $field[4]); + unless ($field[3] =~ /rcmd/i || !$cref || !$ref || $cref->mynode->call ne $ref->homenode) { # not allowed to relay RCMDS! + if ($ref->{priv}) { # you have to have SOME privilege, the commands have further filtering + $self->{remotecmd} = 1; # for the benefit of any command that needs to know + my $oldpriv = $self->{priv}; + $self->{priv} = $ref->{priv}; # assume the user's privilege level + my @in = (DXCommandmode::run_cmd($self, $field[4])); + $self->{priv} = $oldpriv; + for (@in) { + s/\s*$//og; + $self->send(pc85($main::mycall, $field[2], $field[3], "$main::mycall:$_")); + Log('rcmd', 'out', $field[2], $_); + } + delete $self->{remotecmd}; + } else { + $self->send(pc85($main::mycall, $field[2], $field[3], "$main::mycall:sorry...!")); + } + } else { + $self->send(pc85($main::mycall, $field[2], $field[3],"$main::mycall:your attempt is logged, Tut tut tut...!")); + } + } else { + my $ref = DXUser->get_current($field[1]); + if ($ref && $ref->is_clx) { + $self->route($field[1], $line); + } else { + route($field[1], pc34($field[2], $field[1], $field[3])); + } + } + return; + } + + if ($pcno == 85) { # remote command replies + if ($field[1] eq $main::mycall) { + my $dxchan = DXChannel->get($field[3]); + if ($dxchan) { + $dxchan->send($field[4]); + } else { + my $s = $rcmds{$field[2]}; + if ($s) { + $dxchan = DXChannel->get($s->{call}); + $dxchan->send($field[4]) if $dxchan; + delete $rcmds{$field[2]} if !$dxchan; + } + } + } else { + my $ref = DXUser->get_current($field[1]); + if ($ref && $ref->is_clx) { + $self->route($field[1], $line); + } else { + route($field[1], pc35($field[2], $field[1], $field[3])); + } + } + return; + } } - # if get here then rebroadcast the thing with its Hop count decremented (if - # there is one). If it has a hop count and it decrements to zero then don't - # rebroadcast it. - # - # NOTE - don't arrive here UNLESS YOU WANT this lump of protocol to be - # REBROADCAST!!!! - # + # if get here then rebroadcast the thing with its Hop count decremented (if + # there is one). If it has a hop count and it decrements to zero then don't + # rebroadcast it. + # + # NOTE - don't arrive here UNLESS YOU WANT this lump of protocol to be + # REBROADCAST!!!! + # unless ($self->{isolate}) { broadcast_ak1a($line, $self); # send it to everyone but me @@ -741,7 +849,7 @@ sub process my $dxchan; foreach $dxchan (@dxchan) { - next unless $dxchan->is_ak1a(); + next unless $dxchan->is_node(); next if $dxchan == $me; # send a pc50 out on this channel @@ -780,11 +888,9 @@ sub finish { my $self = shift; my $call = $self->call; - my $nopc39 = shift; + my $conn = shift; my $ref = DXCluster->get_exact($call); - $self->send_now("D", DXProt::pc39($main::mycall, $self->msg('disc1', "System Op"))) unless $nopc39; - # unbusy and stop and outgoing mail my $mref = DXMsg::get_busy($call); $mref->stop_msg($call) if $mref; @@ -836,7 +942,7 @@ sub send_dx_spot next unless $filter; } - if ($dxchan->is_ak1a) { + if ($dxchan->is_node) { next if $dxchan == $self; if ($hops) { $routeit = $line; @@ -875,11 +981,11 @@ sub send_wwv_spot my $routeit; my ($filter, $hops); - if ($dxchan->{spotfilter}) { + if ($dxchan->{wwvfilter}) { ($filter, $hops) = Filter::it($dxchan->{wwvfilter}, @_, $self->{call} ); next unless $filter; } - if ($dxchan->is_ak1a) { + if ($dxchan->is_node) { next if $dxchan == $self; if ($hops) { $routeit = $line; @@ -906,6 +1012,49 @@ sub send_wwv_spot } } +sub send_wcy_spot +{ + my $self = shift; + my $line = shift; + my @dxchan = DXChannel->get_all(); + my $dxchan; + + # send it if it isn't the except list and isn't isolated and still has a hop count + # taking into account filtering and so on + foreach $dxchan (@dxchan) { + my $routeit; + my ($filter, $hops); + + if ($dxchan->{wcyfilter}) { + ($filter, $hops) = Filter::it($dxchan->{wcyfilter}, @_, $self->{call} ); + next unless $filter; + } + if ($dxchan->is_clx || $dxchan->is_spider) { + next if $dxchan == $self; + if ($hops) { + $routeit = $line; + $routeit =~ s/\^H\d+\^\~$/\^H$hops\^\~/; + } else { + $routeit = adjust_hops($dxchan, $line); # adjust its hop count by node name + next unless $routeit; + } + if ($filter) { + $dxchan->send($routeit) if $routeit; + } else { + $dxchan->send($routeit) unless $dxchan->{isolate} || $self->{isolate}; + } + } elsif ($dxchan->is_user && $dxchan->{wcy}) { + my $buf = "WCY de $_[10] <$_[1]> : K=$_[4] expK=$_[5] A=$_[3] R=$_[6] SFI=$_[2] SA=$_[7] GMF=$_[8] Au=$_[9]"; + $buf .= "\a\a" if $dxchan->{beep}; + if ($dxchan->{state} eq 'prompt' || $dxchan->{state} eq 'convers') { + $dxchan->send($buf); + } else { + $dxchan->delay($buf); + } + } + } +} + # send an announce sub send_announce { @@ -942,7 +1091,7 @@ sub send_announce ($filter, $hops) = Filter::it($dxchan->{annfilter}, @_, $self->{call} ); next unless $filter; } - if ($dxchan->is_ak1a && $_[1] ne $main::mycall) { # i.e not specifically routed to me + if ($dxchan->is_node && $_[1] ne $main::mycall) { # i.e not specifically routed to me next if $dxchan == $self; if ($hops) { $routeit = $line; @@ -1107,6 +1256,7 @@ sub broadcast_list } next if $sort eq 'ann' && !$dxchan->{ann}; next if $sort eq 'wwv' && !$dxchan->{wwv}; + next if $sort eq 'wcy' && !$dxchan->{wcy}; next if $sort eq 'wx' && !$dxchan->{wx}; $s =~ s/\a//og unless $dxchan->{beep}; @@ -1194,13 +1344,32 @@ sub addping # add a rcmd request to the rcmd queues sub addrcmd { - my ($from, $to, $cmd) = @_; + my ($self, $to, $cmd) = @_; + my $r = {}; - $r->{call} = $from; + $r->{call} = $self->{call}; $r->{t} = $main::systime; $r->{cmd} = $cmd; - route(undef, $to, pc34($main::mycall, $to, $cmd)); $rcmds{$to} = $r; + + my $ref = DXCluster->get_exact($to); + if ($ref && $ref->dxchan && $ref->dxchan->is_clx) { + route(undef, $to, pc84($main::mycall, $to, $self->{call}, $cmd)); + } else { + route(undef, $to, pc34($main::mycall, $to, $cmd)); + } +} + +sub disconnect +{ + my $self = shift; + my $nopc39 = shift; + + if ($self->{conn} && !$nopc39) { + $self->send_now("D", DXProt::pc39($main::mycall, $self->msg('disc1', "System Op"))); + } + + $self->SUPER::disconnect; } 1; __END__