X-Git-Url: http://dxcluster.org/gitweb/gitweb.cgi?a=blobdiff_plain;f=perl%2FDXProt.pm;h=65ad93f930a1bcb164ea623c1fe4f15be8ed19a1;hb=8e45a3dac2e136dc0c9d6f1e78f8c048a8d7ba21;hp=b2978b5c330110f3eb4d9d757867ee602d277749;hpb=3ebd2e180d7315ffd9a2c0eaed558238b6c6bed3;p=spider.git diff --git a/perl/DXProt.pm b/perl/DXProt.pm index b2978b5c..65ad93f9 100644 --- a/perl/DXProt.pm +++ b/perl/DXProt.pm @@ -24,32 +24,29 @@ use DXProtout; use DXDebug; use Filter; use Local; - -use Carp; +use DXDb; +use AnnTalk; +use Geomag; +use WCY; +use Time::HiRes qw(gettimeofday tv_interval); use strict; -use vars qw($me $pc11_max_age $pc23_max_age $pc11_dup_age $pc23_dup_age - %spotdup %wwvdup $last_hour %pings %rcmds - %nodehops @baddx $baddxfn $pc12_dup_age - %anndup $allowzero $pc12_dup_lth $decode_dk0wcy); +use vars qw($me $pc11_max_age $pc23_max_age + $last_hour %pings %rcmds + %nodehops @baddx $baddxfn + $allowzero $decode_dk0wcy $send_opernam); $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 -$pc11_dup_age = 24*3600; # the maximum time to keep the spot dup list for -$pc23_dup_age = 24*3600; # the maximum time to keep the wwv dup list for -$pc12_dup_age = 12*3600; # the maximum time to keep the ann dup list for -$pc12_dup_lth = 72; # the length of ANN text to save for deduping -%spotdup = (); # the pc11 and 26 dup hash -%wwvdup = (); # the pc23 and 27 dup hash -%anndup = (); # the PC12 dup hash + $last_hour = time; # last time I did an hourly periodic update %pings = (); # outstanding ping requests outbound %rcmds = (); # outstanding rcmd requests outbound %nodehops = (); # node specific hop control @baddx = (); # list of illegal spotted callsigns + $baddxfn = "$main::data/baddx.pl"; sub init @@ -63,21 +60,13 @@ sub init confess $@ if $@; # $me->{sort} = 'M'; # M for me - # now prime the spot duplicates file with today's and yesterday's data + # now prime the spot and wwv duplicates file with data my @today = Julian::unixtoj(time); - my @spots = Spot::readfile(@today); - @today = Julian::sub(@today, 1); - push @spots, Spot::readfile(@today); - for (@spots) { - my $dupkey = "$_->[0]$_->[1]$_->[2]$_->[3]$_->[4]"; - $spotdup{$dupkey} = $_->[2]; + for (Spot::readfile(@today), Spot::readfile(Julian::sub(@today, 1))) { + Spot::dup(@{$_}[0..3]); } - - # now prime the wwv duplicates file with just this month's data - my @wwv = Geomag::readfile(time); - for (@wwv) { - my $dupkey = "$_->[1].$_->[2]$_->[3]$_->[4]"; - $wwvdup{$dupkey} = $_->[1]; + for (Geomag::readfile(time)) { + Geomag::dup(@{$_}[1..5]); } # load the baddx file @@ -92,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; } @@ -108,8 +96,8 @@ sub start # remember type of connection $self->{consort} = $line; $self->{outbound} = $sort eq 'O'; - $self->{priv} = $user->priv; - $self->{lang} = $user->lang; + $self->{priv} = $user->priv || 1; # other clusters can always be 'normal' users + $self->{lang} = $user->lang || 'en'; $self->{isolate} = $user->{isolate}; $self->{consort} = $line; # save the connection type $self->{here} = 1; @@ -117,20 +105,37 @@ 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 $self->send_now('B',"0"); $self->send_now('E',"0"); + # ping neighbour node stuff + my $ping = $user->pingint; + $ping = 5*60 unless defined $ping; + $self->{pingint} = $ping; + $self->{nopings} = $user->nopings || 2; + $self->{pingtime} = [ ]; + $self->{pingave} = 0; + # send initialisation string - if (!$self->{outbound}) { + unless ($self->{outbound}) { $self->send(pc38()) if DXNode->get_all(); $self->send(pc18()); + $self->{lastping} = $main::systime; + } else { + # remove from outstanding connects queue + @main::outstanding_connects = grep {$_->{call} ne $call} @main::outstanding_connects; + $self->{lastping} = $main::systime + $self->pingint / 2; } $self->state('init'); $self->pc50_t(time); + # send info to all logged in thingies + $self->tell_login('loginn'); + Log('DXProt', "$call connected"); } @@ -151,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) { @@ -172,7 +177,7 @@ sub normal # is it for me or one of mine? my $call = ($field[5] gt ' ') ? $field[5] : $field[2]; - if ($call eq $main::mycall || grep $_ eq $call, get_all_user_calls()) { + if ($call eq $main::mycall || grep $_ eq $call, DXChannel::get_all_user_calls()) { # yes, it is my $text = unpad($field[3]); @@ -210,23 +215,6 @@ sub normal return; } - # strip off the leading & trailing spaces from the comment - my $text = unpad($field[5]); - - # store it away - my $spotter = $field[6]; - $spotter =~ s/-[\@\d]+$//o; # strip off the ssid from the spotter - - # do some de-duping - my $freq = $field[1] - 0; - my $dupkey = "$freq$field[2]$d$text$spotter"; - if ($spotdup{$dupkey}) { - dbg('chan', "Duplicate Spot ignored\n"); - return; - } - - $spotdup{$dupkey} = $d; - # is it 'baddx' if (grep $field[2] eq $_, @baddx) { dbg('chan', "Bad DX spot, ignored"); @@ -234,12 +222,19 @@ 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; } - my @spot = Spot::add($freq, $field[2], $d, $text, $spotter, $field[7]); + my @spot = Spot::add($field[1], $field[2], $d, $field[5], $field[6], $field[7]); # # @spot at this point contains:- @@ -248,6 +243,49 @@ 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; + } + } + + # send a remote command to a distant cluster if it is visible and there is no + # qra locator and we havn't done it for a month. + + unless ($user->qra) { + my $node; + my $to = $user->homenode; + my $last = $user->lastoper || 0; + if ($send_opernam && $main::systime > $last + $DXUser::lastoperinterval && $to && ($node = DXCluster->get_exact($to)) ) { + my $cmd = "forward/opernam $spot[4]"; + # send the rcmd but we aren't interested in the replies... + if ($node && $node->dxchan && $node->dxchan->is_clx) { + route(undef, $to, pc84($main::mycall, $to, $main::mycall, $cmd)); + } else { + route(undef, $to, pc34($main::mycall, $to, $cmd)); + } + if ($to ne $field[7]) { + $to = $field[7]; + $node = DXCluster->get_exact($to); + if ($node && $node->dxchan && $node->dxchan->is_clx) { + route(undef, $to, pc84($main::mycall, $to, $main::mycall, $cmd)); + } else { + route(undef, $to, pc34($main::mycall, $to, $cmd)); + } + } + $user->lastoper($main::systime); + $user->put; + } + } + } + # local processing my $r; eval { @@ -266,13 +304,11 @@ sub normal if ($pcno == 12) { # announces # announce duplicate checking - my $text = substr(uc unpad($field[3]), 0, $pc12_dup_lth); - my $dupkey = $field[1].$field[2].$text.$field[4].$field[6]; - if ($anndup{$dupkey}) { + $field[3] =~ s/^\s+//; # remove leading blanks + if (AnnTalk::dup($field[1], $field[2], $field[3])) { dbg('chan', "Duplicate Announce ignored\n"); return; } - $anndup{$dupkey} = $main::systime; if ($field[2] eq '*' || $field[2] eq $main::mycall) { @@ -287,13 +323,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); - } - } else { $self->route($field[2], $line); } @@ -510,17 +539,15 @@ sub normal my $i = unpad($field[5]); my ($r) = $field[6] =~ /R=(\d+)/; $r = 0 unless $r; - my $dupkey = "$d.$sfi$k$i"; - if ($wwvdup{$dupkey}) { - dbg('chan', "Dup WWV Spot ignored\n"); + if (($pcno == 23 && $d < $main::systime - $pc23_max_age) || $d > $main::systime + 1500 || $field[2] < 0 || $field[2] > 23) { + dbg('chan', "WWV Date ($field[1] $field[2]) out of range"); return; } - if (($pcno == 23 && $d < $main::systime - $pc23_max_age) || $d > $main::systime + 900 || $field[2] < 0 || $field[2] > 23) { - dbg('chan', "WWV Date ($field[1] $field[2]) out of range"); + if (Geomag::dup($d,$sfi,$k,$i,$field[6])) { + dbg('chan', "Dup WWV Spot ignored\n"); return; } - $wwvdup{$dupkey} = $d; - $field[6] =~ s/-\d+$//o; # remove spotter's ssid + $field[7] =~ s/-\d+$//o; # remove spotter's ssid my $wwv = Geomag::update($d, $field[2], $sfi, $k, $i, @field[6..8], $r); @@ -612,7 +639,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; } @@ -624,9 +656,18 @@ sub normal my $dxchan = DXChannel->get($s->{call}); $dxchan->send($field[3]) if $dxchan; delete $rcmds{$field[2]} if !$dxchan; + } else { + # send unsolicited ones to the sysop + my $dxchan = DXChannel->get($main::myalias); + $dxchan->send($field[3]) 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; } @@ -638,7 +679,7 @@ sub normal } if ($pcno == 39) { # incoming disconnect - $self->disconnect(); + $self->disconnect(1); return; } @@ -660,21 +701,19 @@ sub normal my ($lat, $long) = DXBearing::stoll($field[3]); $user->lat($lat); $user->long($long); + $user->qra(DXBearing::lltoqra($lat, $long)) unless $user->qra && DXBearing::is_qra($user->qra); } elsif ($field[2] == 4) { $user->homenode($field[3]); } + $user->lastoper($main::systime); # to cut down on excessive for/opers being generated $user->put; last SWITCH; } if ($pcno == 43) { last SWITCH; } - if ($pcno == 37 || $pcno == 44 || $pcno == 45 || $pcno == 46 || $pcno == 47) { - if ($field[1] eq $main::mycall) { - ; - } else { - $self->route($field[1], $line); - } + if ($pcno == 37 || $pcno == 44 || $pcno == 45 || $pcno == 46 || $pcno == 47 || $pcno == 48) { + DXDb::process($self, $line); return; } @@ -699,29 +738,139 @@ sub normal # it's a reply, look in the ping list for this one my $ref = $pings{$field[2]}; if ($ref) { - my $r = shift @$ref; - my $dxchan = DXChannel->get($r->{call}); - $dxchan->send($dxchan->msg('pingi', $field[2], atime($main::systime), $main::systime - $r->{t})) if $dxchan; + my $tochan = DXChannel->get($field[2]); + while (@$ref) { + my $r = shift @$ref; + my $dxchan = DXChannel->get($r->{call}); + next unless $dxchan; + my $t = tv_interval($r->{t}, [ gettimeofday ]); + if ($dxchan->is_user) { + 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_node) { + if ($tochan) { + $tochan->{nopings} = 2; # pump up the timer + push @{$tochan->{pingtime}}, $t; + shift @{$tochan->{pingtime}} if @{$tochan->{pingtime}} > 6; + my $st; + for (@{$tochan->{pingtime}}) { + $st += $_; + } + $tochan->{pingave} = $st / @{$tochan->{pingtime}}; + } + } + } } } - } else { # route down an appropriate thingy $self->route($field[1], $line); } 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[4] =~ /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[4])); + } + } + 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 { + # send unsolicited ones to the sysop + my $dxchan = DXChannel->get($main::myalias); + $dxchan->send($field[4]) 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[4])); + } + } + 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!!!! + # - if (!$self->{isolate}) { + unless ($self->{isolate}) { broadcast_ak1a($line, $self); # send it to everyone but me } } @@ -737,13 +886,24 @@ 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 if ($t >= $dxchan->pc50_t + $DXProt::pc50_interval) { - $dxchan->send(pc50()); + $dxchan->send(pc50(scalar DXChannel::get_all_users)); $dxchan->pc50_t($t); + } + + # send a ping out on this channel + if ($dxchan->{pingint} && $t >= $dxchan->{pingint} + $dxchan->{lastping}) { + if ($dxchan->{nopings} <= 0) { + $dxchan->disconnect; + } else { + addping($main::mycall, $dxchan->call); + $dxchan->{nopings} -= 1; + $dxchan->{lastping} = $t; + } } } @@ -751,18 +911,9 @@ sub process my $val; my $cutoff; if ($main::systime - 3600 > $last_hour) { - $cutoff = $main::systime - $pc11_dup_age; - while (($key, $val) = each %spotdup) { - delete $spotdup{$key} if $val < $cutoff; - } - $cutoff = $main::systime - $pc23_dup_age; - while (($key, $val) = each %wwvdup) { - delete $wwvdup{$key} if $val < $cutoff; - } - $cutoff = $main::systime - $pc12_dup_age; - while (($key, $val) = each %anndup) { - delete $anndup{$key} if $val < $cutoff; - } + Spot::process; + Geomag::process; + AnnTalk::process; $last_hour = $main::systime; } } @@ -774,6 +925,7 @@ sub finish { my $self = shift; my $call = $self->call; + my $conn = shift; my $ref = DXCluster->get_exact($call); # unbusy and stop and outgoing mail @@ -795,7 +947,13 @@ sub finish # now broadcast to all other ak1a nodes that I have gone broadcast_ak1a(pc21($call, 'Gone.'), $self) unless $self->{isolate}; - + + # I was the last node visited + $self->user->node($main::mycall); + + # send info to all logged in thingies + $self->tell_login('logoutn'); + Log('DXProt', $call . " Disconnected"); $ref->del() if $ref; } @@ -821,7 +979,7 @@ sub send_dx_spot next unless $filter; } - if ($dxchan->is_ak1a) { + if ($dxchan->is_node) { next if $dxchan == $self; if ($hops) { $routeit = $line; @@ -836,9 +994,9 @@ sub send_dx_spot $dxchan->send($routeit) unless $dxchan->{isolate} || $self->{isolate}; } } elsif ($dxchan->is_user && $dxchan->{dx}) { - my $buf = Spot::formatb($_[0], $_[1], $_[2], $_[3], $_[4]); + my $buf = Spot::formatb($dxchan->{user}->wantgrid, $_[0], $_[1], $_[2], $_[3], $_[4]); $buf .= "\a\a" if $dxchan->{beep}; - if ($dxchan->{state} eq 'prompt' || $dxchan->{state} eq 'convers') { + if ($dxchan->{state} eq 'prompt' || $dxchan->{state} eq 'talk') { $dxchan->send($buf); } else { $dxchan->delay($buf); @@ -860,11 +1018,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; @@ -882,7 +1040,50 @@ sub send_wwv_spot } elsif ($dxchan->is_user && $dxchan->{wwv}) { my $buf = "WWV de $_[6] <$_[1]>: SFI=$_[2], A=$_[3], K=$_[4], $_[5]"; $buf .= "\a\a" if $dxchan->{beep}; - if ($dxchan->{state} eq 'prompt' || $dxchan->{state} eq 'convers') { + if ($dxchan->{state} eq 'prompt' || $dxchan->{state} eq 'talk') { + $dxchan->send($buf); + } else { + $dxchan->delay($buf); + } + } + } +} + +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 'talk') { $dxchan->send($buf); } else { $dxchan->delay($buf); @@ -927,7 +1128,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; @@ -946,7 +1147,7 @@ sub send_announce next if $target eq 'SYSOP' && $dxchan->{priv} < 5; my $buf = "$to$target de $_[0]: $text"; $buf .= "\a\a" if $dxchan->{beep}; - if ($dxchan->{state} eq 'prompt' || $dxchan->{state} eq 'convers') { + if ($dxchan->{state} eq 'prompt' || $dxchan->{state} eq 'talk') { $dxchan->send($buf); } else { $dxchan->delay($buf); @@ -1006,7 +1207,10 @@ sub route my ($self, $call, $line) = @_; my $cl = DXCluster->get_exact($call); if ($cl) { # don't route it back down itself - return if ref $self && $call eq $self->{call}; + if (ref $self && $call eq $self->{call}) { + dbg('chan', "Trying to route back to source, dropped"); + return; + } my $hops; my $dxchan = $cl->{dxchan}; if ($dxchan) { @@ -1024,7 +1228,7 @@ sub broadcast_ak1a { my $s = shift; # the line to be rebroadcast my @except = @_; # to all channels EXCEPT these (dxchannel refs) - my @dxchan = get_all_ak1a(); + my @dxchan = DXChannel::get_all_ak1a(); my $dxchan; # send it if it isn't the except list and isn't isolated and still has a hop count @@ -1041,7 +1245,7 @@ sub broadcast_all_ak1a { my $s = shift; # the line to be rebroadcast my @except = @_; # to all channels EXCEPT these (dxchannel refs) - my @dxchan = get_all_ak1a(); + my @dxchan = DXChannel::get_all_ak1a(); my $dxchan; # send it if it isn't the except list and isn't isolated and still has a hop count @@ -1060,7 +1264,7 @@ sub broadcast_users my $sort = shift; # the type of transmission my $fref = shift; # a reference to an object to filter on my @except = @_; # to all channels EXCEPT these (dxchannel refs) - my @dxchan = get_all_users(); + my @dxchan = DXChannel::get_all_users(); my $dxchan; my @out; @@ -1089,11 +1293,12 @@ 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}; - if ($dxchan->{state} eq 'prompt' || $dxchan->{state} eq 'convers') { + if ($dxchan->{state} eq 'prompt' || $dxchan->{state} eq 'talk') { $dxchan->send($s); } else { $dxchan->delay($s); @@ -1101,43 +1306,6 @@ sub broadcast_list } } -# -# gimme all the ak1a nodes -# -sub get_all_ak1a -{ - my @list = DXChannel->get_all(); - my $ref; - my @out; - foreach $ref (@list) { - push @out, $ref if $ref->is_ak1a; - } - return @out; -} - -# return a list of all users -sub get_all_users -{ - my @list = DXChannel->get_all(); - my $ref; - my @out; - foreach $ref (@list) { - push @out, $ref if $ref->is_user; - } - return @out; -} - -# return a list of all user callsigns -sub get_all_user_calls -{ - my @list = DXChannel->get_all(); - my $ref; - my @out; - foreach $ref (@list) { - push @out, $ref->call if $ref->is_user; - } - return @out; -} # # obtain the hops from the list for this callsign and pc no @@ -1196,37 +1364,61 @@ sub load_hops return 0; } -# remove leading and trailing spaces from an input string -sub unpad -{ - my $s = shift; - $s =~ s/^\s+|\s+$//; - return $s; -} # add a ping request to the ping queues sub addping { my ($from, $to) = @_; - my $ref = $pings{$to}; - $ref = $pings{$to} = [] if !$ref; + my $ref = $pings{$to} || []; my $r = {}; $r->{call} = $from; - $r->{t} = $main::systime; + $r->{t} = [ gettimeofday ]; route(undef, $to, pc51($to, $main::mycall, 1)); push @$ref, $r; + $pings{$to} = $ref; } # 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; +} + +# +# send a talk message to this thingy +# +sub talk +{ + my ($self, $from, $to, $via, $line) = @_; + + $line =~ s/\^/\\5E/g; # remove any ^ characters + $self->send(DXProt::pc10($from, $to, $via, $line)); + Log('talk', $self->call, $from, $via?$via:$main::mycall, $line); } 1; __END__