X-Git-Url: http://gb7djk.dxcluster.net/gitweb/gitweb.cgi?a=blobdiff_plain;f=perl%2FDXProtHandle.pm;h=21f94aae8a66835da46f3d33e1e0de3d64733b34;hb=9b65e70322b24190bb5f677ccedcc000ab4625d2;hp=4c7ccf4b256d869e4b6f57910d11e24a1b2214a7;hpb=7b35ba0ffde25a7ef028c82b77021bab4b010900;p=spider.git diff --git a/perl/DXProtHandle.pm b/perl/DXProtHandle.pm index 4c7ccf4b..21f94aae 100644 --- a/perl/DXProtHandle.pm +++ b/perl/DXProtHandle.pm @@ -32,8 +32,6 @@ use DXHash; use Route; use Route::Node; use Script; -use RouteDB; - use strict; @@ -43,17 +41,30 @@ use vars qw($pc11_max_age $pc23_max_age $last_pc50 $eph_restime $eph_info_restim $investigation_int $pc19_version $myprot_version %nodehops $baddx $badspotter $badnode $censorpc $allowzero $decode_dk0wcy $send_opernam @checklist - $eph_pc15_restime $pc9x_past_age $pc9x_future_age + $eph_pc15_restime $pc9x_past_age $pc9x_dupe_age $pc10_dupe_age $pc92_slug_changes $last_pc92_slug - $pc92Ain $pc92Cin $pc92Din $pc92Kin + $pc92Ain $pc92Cin $pc92Din $pc92Kin $pc9x_time_tolerance + $pc92filterdef ); -$pc9x_past_age = 62*60; # maximum age in the past of a px9x (a config record might be the only - # thing a node might send - once an hour) -$pc9x_future_age = 2*3600; # maximum age in the future ditto +$pc9x_dupe_age = 60; # catch loops of circular (usually) D records $pc10_dupe_age = 45; # just something to catch duplicate PC10->PC93 conversions -$pc92_slug_changes = 60; # slug any changes going outward for this long +$pc92_slug_changes = 60*5; # slug any changes going outward for this long $last_pc92_slug = 0; # the last time we sent out any delayed add or del PC92s +$pc9x_time_tolerance = 15*60; # the time on a pc9x is allowed to be out by this amount +$pc9x_past_age = (122*60)+ # maximum age in the past of a px9x (a config record might be the only + $pc9x_time_tolerance; # thing a node might send - once an hour and we allow an extra hour for luck) + # this is actually the partition between "yesterday" and "today" but old. + +$pc92filterdef = bless ([ + # tag, sort, field, priv, special parser + ['call', 'c', 0], + ['by', 'c', 0], + ['dxcc', 'nc', 1], + ['itu', 'ni', 2], + ['zone', 'nz', 3], + ], 'Filter::Cmd'); + # incoming talk commands sub handle_10 @@ -109,10 +120,6 @@ sub handle_10 } } - # remember a route to this node and also the node on which this user is - RouteDB::update($_[6], $self->{call}); -# RouteDB::update($to, $_[6]); - # convert this to a PC93, coming from mycall with origin set and process it as such $main::me->normal(pc93($to, $from, $via, $_[3], $_[6])); } @@ -164,13 +171,13 @@ sub handle_11 # convert the date to a unix date my $d = cltounix($_[3], $_[4]); # bang out (and don't pass on) if date is invalid or the spot is too old (or too young) - if (!$d || ($pcno == 11 && ($d < $main::systime - $pc11_max_age || $d > $main::systime + 900))) { + if (!$d || (($pcno == 11 || $pcno == 61) && ($d < $main::systime - $pc11_max_age || $d > $main::systime + 900))) { dbg("PCPROT: Spot ignored, invalid date or out of range ($_[3] $_[4])\n") if isdbg('chanerr'); return; } # is it 'baddx' - if ($baddx->in($_[2]) || BadWords::check($_[2]) || $_[2] =~ /COCK/) { + if ($baddx->in($_[2]) || BadWords::check($_[2])) { dbg("PCPROT: Bad DX spot, ignored") if isdbg('chanerr'); return; } @@ -190,11 +197,7 @@ sub handle_11 } } - # remember a route -# RouteDB::update($_[7], $self->{call}); -# RouteDB::update($_[6], $_[7]); - - my @spot = Spot::prepare($_[1], $_[2], $d, $_[5], $nossid, $_[7]); + my @spot = Spot::prepare($_[1], $_[2], $d, $_[5], $nossid, $_[7], $_[8]); # global spot filtering on INPUT if ($self->{inspotsfilter}) { my ($filter, $hops) = $self->{inspotsfilter}->it(@spot); @@ -223,7 +226,7 @@ sub handle_11 # # fix up qra locators of known users - my $user = DXUser->get_current($spot[4]); + my $user = DXUser::get_current($spot[4]); if ($user) { my $qra = $user->qra; unless ($qra && is_qra($qra)) { @@ -270,12 +273,13 @@ sub handle_11 } # local processing - my $r; - eval { - $r = Local::spot($self, @spot); - }; - # dbg("Local::spot1 error $@") if isdbg('local') if $@; - return if $r; + if (defined &Local::spot) { + my $r; + eval { + $r = Local::spot($self, @spot); + }; + return if $r; + } # DON'T be silly and send on PC26s! return if $pcno == 26; @@ -317,6 +321,12 @@ sub handle_12 return; } + # ignore PC12s from origins that use PCxx protocol + my $oref = Route::get($origin); + if ($oref->do_pc9x) { + dbg("PCPROT: PC12 rxed from PC9x node, ignored") if isdbg('chanerr'); + return; + } my $dxchan; @@ -324,10 +334,6 @@ sub handle_12 $self->send_chat(0, $line, @_[1..6]); } elsif ($_[2] eq '*' || $_[2] eq $main::mycall) { - # remember a route -# RouteDB::update($_[5], $self->{call}); -# RouteDB::update($_[1], $_[5]); - # ignore something that looks like a chat line coming in with sysop # flag - this is a kludge... if ($_[3] =~ /^\#\d+ / && $_[4] eq '*') { @@ -354,6 +360,15 @@ sub handle_12 } else { $self->route($_[2], $line); } + + # local processing + if (defined &Local::ann) { + my $r; + eval { + $r = Local::ann($self, $line, @_[1..6]); + }; + return if $r; + } } sub handle_15 @@ -399,7 +414,6 @@ sub handle_16 my $h; $h = 1 if DXChannel::get($ncall); - RouteDB::update($ncall, $self->{call}, $h); if ($h && $self->{call} ne $ncall) { dbg("PCPROT: trying to update a local node, ignored") if isdbg('chanerr'); return; @@ -450,7 +464,7 @@ sub handle_16 # reject this if we think it is a node already my $r = Route::Node::get($call); - my $u = DXUser->get_current($call) unless $r; + my $u = DXUser::get_current($call) unless $r; if ($r || ($u && $u->is_node)) { dbg("PCPROT: $call is a node") if isdbg('chanerr'); next; @@ -472,7 +486,7 @@ sub handle_16 } # add this station to the user database, if required - my $user = DXUser->get_current($ncall); + my $user = DXUser::get_current($ncall); $user = DXUser->new($call) unless $user; $user->homenode($parent->call) if !$user->homenode; $user->node($parent->call); @@ -519,8 +533,6 @@ sub handle_17 return; } - RouteDB::delete($ncall, $self->{call}); - my $uref = Route::User::get($ucall); unless ($uref) { dbg("PCPROT: Route::User $ucall not in config") if isdbg('chanerr'); @@ -555,7 +567,7 @@ sub handle_17 $parent->del_user($uref); # send info to all logged in thingies - my $user = DXUser->get_current($ncall); + my $user = DXUser::get_current($ncall); $self->tell_login('logoutu', "$ncall: $ucall") if $user && $user->is_local_node; $self->tell_buddies('logoutb', $ucall, $ncall); @@ -625,7 +637,7 @@ sub check_add_node my $call = shift; # add this station to the user database, if required (don't remove SSID from nodes) - my $user = DXUser->get_current($call); + my $user = DXUser::get_current($call); if (!$user) { $user = DXUser->new($call); $user->priv(1); # I have relented and defaulted nodes @@ -714,7 +726,6 @@ sub handle_19 # next; # } - RouteDB::update($call, $self->{call}, $dxchan ? 1 : undef); unless ($h) { if ($parent->via_pc92) { @@ -820,8 +831,6 @@ sub handle_21 # we don't need any isolation code here, because we will never # act on a PC21 with self->call in it. - RouteDB::delete($call, $self->{call}); - my $parent = Route::Node::get($self->{call}); unless ($parent) { dbg("PCPROT: my parent $self->{call} has disappeared"); @@ -934,12 +943,13 @@ sub handle_23 # note this only takes the first one it gets Geomag::update($d, $_[2], $sfi, $k, $i, @_[6..8], $r); - my $rep; - eval { - $rep = Local::wwv($self, $_[1], $_[2], $sfi, $k, $i, @_[6..8], $r); - }; - # dbg("Local::wwv2 error $@") if isdbg('local') if $@; - return if $rep; + if (defined &Local::wwv) { + my $rep; + eval { + $rep = Local::wwv($self, $_[1], $_[2], $sfi, $k, $i, @_[6..8], $r); + }; + return if $rep; + } # DON'T be silly and send on PC27s! return if $pcno == 27; @@ -1127,16 +1137,23 @@ sub handle_41 return; } + if ($call eq $main::mycall && $call eq $main::myalias) { + dbg "DXPROT: PC41 trying to update $call from outside via $origin, ignored"; + return; + } + my $chan = DXChannel::get($call); + if ($chan) { + dbg "DXPROT: PC41 trying to update online $call from outside via $origin, ignored"; + return; + } + # add this station to the user database, if required - my $user = DXUser->get_current($call); + my $user = DXUser::get_current($call); $user = DXUser->new($call) unless $user; if ($sort == 1) { if (($val =~ /spotter/i || $val =~ /self/i) && $user->name && $user->name ne $val) { dbg("PCPROT: invalid name") if isdbg('chanerr'); - if ($main::mycall eq 'GB7DJK' || $main::mycall eq 'GB7BAA' || $main::mycall eq 'WR3D') { - DXChannel::broadcast_nodes(pc41($_[1], 1, $user->name)); # send it to everyone including me - } return; } $user->name($val); @@ -1217,13 +1234,12 @@ sub handle_50 my $call = $_[1]; - RouteDB::update($call, $self->{call}); - my $node = Route::Node::get($call); if ($node) { return unless $node->call eq $self->{call}; $node->usercount($_[2]) unless $node->users; $node->reset_obs; + $node->PC92C_dxchan($self->call, $_[-1]); # input filter if required # return unless $self->in_filter_route($node); @@ -1255,9 +1271,6 @@ sub handle_51 DXXml::Ping::handle_ping_reply($self, $from); } } else { - - RouteDB::update($from, $self->{call}); - if (eph_dup($line)) { return; } @@ -1304,12 +1317,13 @@ sub handle_73 my $wcy = WCY::update($d, @_[2..12]); - my $rep; - eval { - $rep = Local::wcy($self, @_[1..12]); - }; - # dbg("Local::wcy error $@") if isdbg('local') if $@; - return if $rep; + if (defined &Local::wcy) { + my $rep; + eval { + $rep = Local::wcy($self, @_[1..12]); + }; + return if $rep; + } # broadcast to the eager world send_wcy_spot($self, $line, $d, @_[2..12]); @@ -1352,7 +1366,10 @@ sub _decode_pc92_call my $is_node = $flag & 4; my $is_extnode = $flag & 2; my $here = $flag & 1; - return ($call, $is_node, $is_extnode, $here, $part[1], $part[2]); + my $ip = $part[3]; + $ip ||= $part[1] if $part[1] && ($part[1] =~ /^(?:\d+\.)+/ || $part[1] =~ /^(?:(?:[abcdef\d]+)?,)+/); + $ip =~ s/,/:/g if $ip; + return ($call, $is_node, $is_extnode, $here, $part[1], $part[2], $ip); } # decode a pc92 call: flag call : version : build @@ -1363,7 +1380,7 @@ sub _encode_pc92_call # plain call or value return $ref unless ref $ref; - my $ext = shift; + my $ext = shift || 0; my $flag = 0; my $call = $ref->call; my $extra = ''; @@ -1372,14 +1389,17 @@ sub _encode_pc92_call $flag |= 4; my $dxchan = DXChannel::get($call); $flag |= 2 if $call ne $main::mycall && $dxchan && !$dxchan->{do_pc9x}; - if ($ext) { - if ($ref->version) { - my $version = $ref->version || 1.0; - $version = $version * 100 + 5300 if $version < 50; - $extra .= ":" . $version; - } + if (($ext & 1) && $ref->version) { + my $version = $ref->version || 1.0; + $version = $version * 100 + 5300 if $version < 50; + $extra .= ":" . $version; } } + if (($ext & 2) && $ref->ip) { + my $ip = $ref->ip; + $ip =~ s/:/,/g; + $extra .= ':' . $ip; + } return "$flag$call$extra"; } @@ -1390,16 +1410,32 @@ sub _add_thingy { my $parent = shift; my $s = shift; - my ($call, $is_node, $is_extnode, $here, $version, $build) = @$s; + my $dxchan = shift; + my $hops = shift; + + my ($call, $is_node, $is_extnode, $here, $version, $build, $ip) = @$s; my @rout; if ($call) { + my $ncall = $parent->call; if ($is_node) { - dbg("ROUTE: added node $call to " . $parent->call) if isdbg('routelow'); - @rout = $parent->add($call, $version, Route::here($here)); + dbg("ROUTE: added node $call to $ncall") if isdbg('routelow'); + @rout = $parent->add($call, $version, Route::here($here), $ip); + my $r = Route::Node::get($call); + $r->PC92C_dxchan($dxchan->call, $hops) if $r; + if ($ip) { + $r->ip($ip); + Log('DXProt', "PC92A $call -> $ip on $ncall"); + } } else { - dbg("ROUTE: added user $call to " . $parent->call) if isdbg('routelow'); - @rout = $parent->add_user($call, Route::here($here)); + dbg("ROUTE: added user $call to $ncall") if isdbg('routelow'); + @rout = $parent->add_user($call, Route::here($here), $ip); + $dxchan->tell_buddies('loginb', $call, $ncall) if $dxchan; + my $r = Route::User::get($call); + if ($ip) { + $r->ip($ip); + Log('DXProt', "PC92A $call -> $ip on $ncall"); + } } if ($pc92_slug_changes && $parent == $main::routeroot) { $things_add{$call} = Route::get($call); @@ -1413,6 +1449,7 @@ sub _del_thingy { my $parent = shift; my $s = shift; + my $dxchan = shift; my ($call, $is_node, $is_extnode, $here, $version, $build) = @$s; my @rout; if ($call) { @@ -1422,9 +1459,12 @@ sub _del_thingy dbg("ROUTE: deleting node $call from " . $parent->call) if isdbg('routelow'); @rout = $ref->del($parent) if $ref; } else { - $ref = Route::User::get($call); dbg("ROUTE: deleting user $call from " . $parent->call) if isdbg('routelow'); - @rout = $parent->del_user($ref) if $ref; + $ref = Route::User::get($call); + if ($ref) { + $dxchan->tell_buddies('logoutb', $call, $parent->call) if $dxchan; + @rout = $parent->del_user($ref); + } } if ($pc92_slug_changes && $parent == $main::routeroot) { $things_del{$call} = $ref unless exists $things_add{$call}; @@ -1478,6 +1518,21 @@ sub check_pc9x_t my $pc = shift; my $create = shift; + # check that the time is between 0 >= $t < 86400 + unless ($t >= 0 && $t < 86400) { + dbg("PCPROT: time invalid t: $t, ignored") if isdbg('chanerr'); + return undef; + } + + # check that the time of this pc9x is within tolerance (default 15 mins either way) + my $now = $main::systime - $main::systime_daystart ; + my $diff = abs($now - $t); + unless ($diff < $pc9x_time_tolerance || 86400 - $diff < $pc9x_time_tolerance) { + my $c = ref $call ? $call->call : $call; + dbg("PC9XERR: $c time out of range t: $t now: $now diff: $diff > $pc9x_time_tolerance, ignored") if isdbg('chan'); + return undef; + } + my $parent = ref $call ? $call : Route::Node::get($call); if ($parent) { # we only do this for external calls whose routing table @@ -1489,26 +1544,46 @@ sub check_pc9x_t my $lastid = $parent->lastid; if (defined $lastid) { if ($t < $lastid) { + # note that this is where we determine whether this pc9x has come in yesterday + # but is still greater (modulo 86400) than the lastid or is simply an old + # duplicate sentence. To determine this we need to do some module 86400 + # arithmetic. High numbers mean that this is an old duplicate sentence, + # low numbers that it is a new sentence. + # + # Typically you will see yesterday being taken on $t = 84, $lastid = 86235 + # and old dupes with $t = 234, $lastid = 256 (which give answers 249 and + # 86378 respectively in the calculation below). + # if ($t+86400-$lastid > $pc9x_past_age) { - dbg("PCPROT: dup id on $t <= lastid $lastid, ignored") if isdbg('chanerr'); - return; + dbg("PCPROT: dup id on $t <= lastid $lastid, ignored") if isdbg('chanerr') || isdbg('pc92dedupe'); + return undef; } } elsif ($t == $lastid) { - dbg("PCPROT: dup id on $t == lastid $lastid, ignored") if isdbg('chanerr'); - return; + dbg("PCPROT: dup id on $t == lastid $lastid, ignored") if isdbg('chanerr') || isdbg('pc92dedupe'); + return undef; } else { - # $t > $lastid, check that the timestamp offered isn't too far away from 'now' - if ($t-$lastid > $pc9x_future_age ) { - dbg("PCPROT: id $t too far in the future of lastid $lastid, ignored") if isdbg('chanerr'); - return; + # check that if we have a low number in lastid that yesterday's numbers + # (likely in the 85000+ area) don't override them, thus causing flip flopping + if ($lastid+86400-$t < $pc9x_past_age) { + dbg("PCPROT: dup id on $t in yesterday, lastid $lastid, ignored") if isdbg('chanerr') || isdbg('pc92dedupe'); + return undef; } } } } } elsif ($create) { $parent = Route::Node->new($call); + } else { + dbg("PCPROT: $call does not exist, ignored") if isdbg('pc92dedupe'); + return undef; + } + if (isdbg('pc92dedupe')) { + my $exists = exists $parent->{lastid}; # naughty, naughty :-) + my $val = $parent->{lastid}; + my $s = $exists ? (defined $val ? $val : 'exists/undef') : 'undef'; + dbg("PCPROT: $call pc92 id lastid $s -> $t"); } - $parent->lastid($t) if $parent; + $parent->lastid($t); return $parent; } @@ -1519,6 +1594,7 @@ sub pc92_handle_first_slot my $slot = shift; my $parent = shift; my $t = shift; + my $hops = shift; my $oparent = $parent; my @radd; @@ -1543,7 +1619,7 @@ sub pc92_handle_first_slot # from the true parent node for this external before we get one for the this node unless ($parent = Route::Node::get($call)) { if ($is_extnode && $oparent) { - @radd = _add_thingy($oparent, $slot); + @radd = _add_thingy($oparent, $slot, $self, $hops); $parent = $radd[0]; } else { dbg("PCPROT: no previous C or A for this external node received, ignored") if isdbg('chanerr'); @@ -1552,7 +1628,7 @@ sub pc92_handle_first_slot } $parent = check_pc9x_t($call, $t, 92) || return; $parent->via_pc92(1); - $parent->PC92C_dxchan($self->{call}); + $parent->PC92C_dxchan($self->{call}, $hops); } } else { dbg("PCPROT: must be \$mycall or external node as first entry, ignored") if isdbg('chanerr'); @@ -1561,7 +1637,7 @@ sub pc92_handle_first_slot $parent->here(Route::here($here)); $parent->version($version || $pc19_version) if $version; $parent->build($build) if $build; - $parent->PC92C_dxchan($self->{call}) unless $self->{call} eq $parent->call; + $parent->PC92C_dxchan($self->{call}, $hops) unless $self->{call} eq $parent->call; return ($parent, @radd); } @@ -1578,6 +1654,12 @@ sub handle_92 my $pcall = $_[1]; my $t = $_[2]; my $sort = $_[3]; + my $hops = $_[-1]; + + # this catches loops of A/Ds +# if (eph_dup($line, $pc9x_dupe_age)) { +# return; +# } if ($pcall eq $main::mycall) { dbg("PCPROT: looped back, ignored") if isdbg('chanerr'); @@ -1602,7 +1684,9 @@ sub handle_92 return; } - my $parent = check_pc9x_t($pcall, $t, 92, 1) || return; + # don't create routing entries for D records that don't already exist + # this is what causes all those PC92 loops! + my $parent = check_pc9x_t($pcall, $t, 92, $sort ne 'D') || return; my $oparent = $parent; $parent->do_pc9x(1); @@ -1652,17 +1736,17 @@ sub handle_92 } } elsif ($sort eq 'K') { - $pc92Kin += length $line if $sort eq 'K'; + $pc92Kin += length $line; # remember the last channel we arrived on - $parent->PC92C_dxchan($self->{call}) unless $self->{call} eq $parent->call; + $parent->PC92C_dxchan($self->{call}, $hops) unless $self->{call} eq $parent->call; my @ent = _decode_pc92_call($_[4]); if (@ent) { my $add; - ($parent, $add) = $self->pc92_handle_first_slot(\@ent, $parent, $t); + ($parent, $add) = $self->pc92_handle_first_slot(\@ent, $parent, $t, $hops); return unless $parent; # dupe push @radd, $add if $add; @@ -1679,7 +1763,7 @@ sub handle_92 $pc92Din += length $line if $sort eq 'D'; # remember the last channel we arrived on - $parent->PC92C_dxchan($self->{call}) unless $self->{call} eq $parent->call; + $parent->PC92C_dxchan($self->{call}, $hops) unless $self->{call} eq $parent->call; # this is the main route section # here is where all the routes are created and destroyed @@ -1698,19 +1782,20 @@ sub handle_92 # that needs to be done. my $add; - ($parent, $add) = $self->pc92_handle_first_slot($ent[0], $parent, $t); + ($parent, $add) = $self->pc92_handle_first_slot($ent[0], $parent, $t, $hops); return unless $parent; # dupe shift @ent; push @radd, $add if $add; } - # do a pass through removing any references to either locally connected nodes or mycall + # do a pass through removing any references to either mycall my @nent; for (@ent) { + my $dxc; next unless $_ && @$_; - if ($_->[0] eq $main::mycall || DXChannel::get($_->[0])) { - dbg("PCPROT: $_->[0] refers to locally connected node, ignored") if isdbg('chanerr'); + if ($_->[0] eq $main::mycall) { + dbg("PCPROT: $_->[0] refers to me, ignored") if isdbg('chanerr'); next; } push @nent, $_; @@ -1718,11 +1803,11 @@ sub handle_92 if ($sort eq 'A') { for (@nent) { - push @radd, _add_thingy($parent, $_); + push @radd, _add_thingy($parent, $_, $self, $hops); } } elsif ($sort eq 'D') { for (@nent) { - push @rdel, _del_thingy($parent, $_); + push @rdel, _del_thingy($parent, $_, $self); } } elsif ($sort eq 'C') { my (@nodes, @users); @@ -1751,15 +1836,15 @@ sub handle_92 foreach my $r (@nent) { my $call = $r->[0]; if ($call) { - push @radd,_add_thingy($parent, $r) if grep $call eq $_, (@$nnodes, @$nusers); + push @radd,_add_thingy($parent, $r, $self, $hops) if grep $call eq $_, (@$nnodes, @$nusers); } } # del users here foreach my $r (@$dnodes) { - push @rdel,_del_thingy($parent, [$r, 1]); + push @rdel,_del_thingy($parent, [$r, 1], $self); } foreach my $r (@$dusers) { - push @rdel,_del_thingy($parent, [$r, 0]); + push @rdel,_del_thingy($parent, [$r, 0], $self); } # remember this last PC92C for rebroadcast on demand @@ -1786,6 +1871,42 @@ sub handle_92 $self->broadcast_route_pc9x($pcall, undef, $line, 0); } +# get all the routes for a thing, bearing in mind that the thing (e.g. a user) +# might be on two or more nodes at the same time or that there may be more than +# one equal distance neighbour to a node. +# +# What this means that if sh/route g1tlh shows that he is on (say) two nodes, then +# a Route::findroutes is done on each of those two nodes, the best route(s) taken from +# each and then combined to give a set of dxchans to send the PC9x record down +# +sub find_pc9x_routes +{ + my $to = shift; + my $ref = Route::get($to); + my @parent; + my %cand; + + if ($ref->isa('Route::User')) { + my $dxchan = DXChannel::get($to); + push @parent, $to if $dxchan; + push @parent, $ref->parents; + } else { + @parent = $to; + } + foreach my $p (@parent) { + my $lasthops; + my @routes = Route::findroutes($p); + foreach my $r (@routes) { + $lasthops = $r->[0] unless defined $lasthops; + if ($r->[0] == $lasthops) { + $cand{$r->[1]->call} = $r->[1]; + } else { + last; + } + } + } + return values %cand; +} sub handle_93 { @@ -1837,39 +1958,37 @@ sub handle_93 return; } + # ignore PC93 coming in from outside this node with a target of local + if ($to eq 'LOCAL' && $self != $main::me) { + dbg("PCPROT: incoming LOCAL chat not from local node, ignored") if isdbg('chanerr'); + return; + } + # if it is routeable then then treat it like a talk my $ref = Route::get($to); if ($ref) { - # local talks my $dxchan; - $dxchan = DXChannel::get($main::myalias) if $to eq $main::mycall; - $dxchan = DXChannel::get($to) unless $dxchan; - # check it... - if ($dxchan) { + + # convert to PC10 or local talks where appropriate + # PC93 capable nodes of the same hop count all get a copy + # if there is a PC10 node then it will get a copy and that + # will be it. Hopefully such a node will not figure highly + # in the route list, unless it is local, 'cos it don't issue PC92s! + # note that both local and PC93s at the same time are possible if the + # user on more than one node. + my @routes = find_pc9x_routes($to); + my $lasthops; + foreach $dxchan (@routes) { if (ref $dxchan && $dxchan->isa('DXChannel')) { - if ($dxchan->is_user) { + if ($dxchan->{do_pc9x}) { + $dxchan->send($line); + } else { $dxchan->talk($from, $to, $via, $text, $onode); - return; } } else { - dbg("ERROR: $to -> $dxchan is not a DXChannel! (local talk)"); + dbg("ERROR: $to -> $dxchan is not a DXChannel! (convert to pc10)"); } } - - # convert to PC10 talks where appropriate - # just go for the "best" one for now (rather than broadcast) - $dxchan = $ref->dxchan; - - # check it... - if (ref $dxchan && $dxchan->isa('DXChannel')) { - if ($dxchan->{do_pc9x}) { - $dxchan->send($line); - } else { - $dxchan->talk($from, $to, $via, $text, $onode); - } - } else { - dbg("ERROR: $to -> $dxchan is not a DXChannel! (convert to pc10)"); - } return; } elsif ($to eq '*' || $to eq 'SYSOP' || $to eq 'WX') { @@ -1881,10 +2000,12 @@ sub handle_93 $self->send_announce(1, pc12($from, $text, $local, $sysop, $wx, $pcall), $from, $local, $text, $sysop, $pcall, $wx, $via eq 'LOCAL' ? $via : undef); return if $via eq 'LOCAL'; } elsif (!is_callsign($to) && $text =~ /^#\d+ /) { - # chat messages to non-pc9x nodes - $self->send_chat(1, pc12($from, $text, undef, $to, undef, $pcall), $from, '*', $text, $to, $pcall, '0'); + # chat messages really only locally connected users + $self->send_chat(1, $line, $from, '*', $text, $to, $pcall, '0'); } - $self->broadcast_route_pc9x($pcall, undef, $line, 0); + + # broadcast this chat sentence everywhere unless it is targetted to 'LOCAL' + $self->broadcast_route_pc9x($pcall, undef, $line, 0) unless $to eq 'LOCAL' || $via eq 'LOCAL'; } # if get here then rebroadcast the thing with its Hop count decremented (if