$investigation_int $pc19_version $myprot_version
%nodehops $baddx $badspotter $badnode $censorpc $rspfcheck
$allowzero $decode_dk0wcy $send_opernam @checklist
- $eph_pc15_restime
+ $eph_pc15_restime $pc9x_past_age $pc9x_future_age
);
+$pc9x_past_age = 15*60; # maximum age in the past of a px9x
+$pc9x_future_age = 5*60; # maximum age in the future ditto
+
# incoming talk commands
sub handle_10
{
RouteDB::update($_[6], $self->{call});
# RouteDB::update($to, $_[6]);
+ # convert this to a PC93 and process it as such
+ $self->normal(pc93($to, $from, $via, $_[3], $_[6]));
+ return;
+
+ # this is all redundant but kept for now for reference
+
# it is here and logged on
$dxchan = DXChannel::get($main::myalias) if $to eq $main::mycall;
$dxchan = DXChannel::get($to) unless $dxchan;
my $dxchan;
if ((($dxchan = DXChannel::get($_[2])) && $dxchan->is_user) || $_[4] =~ /^[\#\w.]+$/){
- $self->send_chat($line, @_[1..6]);
+ $self->send_chat(0, $line, @_[1..6]);
} elsif ($_[2] eq '*' || $_[2] eq $main::mycall) {
# remember a route
}
# send it
- $self->send_announce($line, @_[1..6]);
+ $self->send_announce(0, $line, @_[1..6]);
} else {
$self->route($_[2], $line);
}
dbg("PCPROT: don't send users to $self->{call}") if isdbg('chanerr');
return;
}
+
# is it me?
if ($ncall eq $main::mycall) {
dbg("PCPROT: trying to alter config on this node from outside!") if isdbg('chanerr');
my $h;
$h = 1 if DXChannel::get($ncall);
RouteDB::update($ncall, $self->{call}, $h);
-
- if (eph_dup($line)) {
- dbg("PCPROT: dup PC16 detected") if isdbg('chanerr');
+ if ($h && $self->{call} ne $ncall) {
+ dbg("PCPROT: trying to update a local node, ignored") if isdbg('chanerr');
return;
}
- unless ($h) {
- dbg("PCPROT: non-local PC16, ignored") if isdbg('chanerr');
+ if (eph_dup($line)) {
+ dbg("PCPROT: dup PC16 detected") if isdbg('chanerr');
return;
}
# input filter if required
return unless $self->in_filter_route($parent);
+ } else {
+ $parent = Route::Node->new($ncall);
+ }
+
+ unless ($h) {
+ if ($parent->via_pc92) {
+ dbg("PCPROT: non-local node controlled by PC92, ignored") if isdbg('chanerr');
+ return;
+ }
}
my $i;
$r->flags($flags);
$au = $r;
}
- push @rout, $r if $au;
+ push @rout, $r if $h && $au;
} else {
- push @rout, $parent->add_user($call, $flags);
+ my @ans = $parent->add_user($call, $flags);
+ push @rout, @ans if $h && @ans;
}
# send info to all logged in thingies
$user->put;
}
if (@rout) {
- $self->route_pc16($origin, $line, $parent, @rout);
- $self->route_pc92a($main::mycall, undef, $parent, @rout) if $self->{state} eq 'normal';
+ $self->route_pc16($origin, $line, $parent, @rout) if @rout;
+# $self->route_pc92a($main::mycall, undef, $parent, @rout) if $h && $self->{state} eq 'normal';
}
}
dbg("PCPROT: don't send users to $self->{call}") if isdbg('chanerr');
return;
}
+
if ($ncall eq $main::mycall) {
dbg("PCPROT: trying to alter config on this node from outside!") if isdbg('chanerr');
return;
RouteDB::delete($ncall, $self->{call});
- unless ($ncall eq $self->{call}) {
- dbg("PCPROT: PC17 from non-local $ncall, ignored") if isdbg('chanerr');
- return;
- }
-
my $uref = Route::User::get($ucall);
unless ($uref) {
dbg("PCPROT: Route::User $ucall not in config") if isdbg('chanerr');
+ return;
}
my $parent = Route::Node::get($ncall);
unless ($parent) {
dbg("PCPROT: Route::Node $ncall not in config") if isdbg('chanerr');
+ return;
}
- $dxchan = $parent->dxchan if $parent;
+ $dxchan = DXChannel::get($ncall);
if ($dxchan && $dxchan ne $self) {
dbg("PCPROT: PC17 from $self->{call} trying to alter locally connected $ncall, ignored!") if isdbg('chanerr');
return;
}
+ unless ($dxchan) {
+ if ($parent->via_pc92) {
+ dbg("PCPROT: non-local node controlled by PC92, ignored") if isdbg('chanerr');
+ return;
+ }
+ }
+
+ if (DXChannel::get($ucall)) {
+ dbg("PCPROT: trying do disconnect local user, ignored") if isdbg('chanerr');
+ return;
+ }
+
# input filter if required and then remove user if present
- if ($parent) {
# return unless $self->in_filter_route($parent);
- $parent->del_user($uref) if $uref;
- } else {
- $parent = Route->new($ncall); # throw away
- }
+ $parent->del_user($uref);
# send info to all logged in thingies
$self->tell_login('logoutu', "$ncall: $ucall") if DXUser->get_current($ncall)->is_local_node;
return;
}
- $uref = Route->new($ucall) unless $uref; # throw away
$self->route_pc17($origin, $line, $parent, $uref);
- $self->route_pc92d($main::mycall, undef, $parent, $uref);
+# $self->route_pc92d($main::mycall, undef, $parent, $uref) if $dxchan;
}
# link request
$self->state('init');
# record the type and version offered
- if ($_[1] =~ /DXSpider Version: (\d+\.\d+) Build: (\d+\.\d+)/) {
+ if ($_[1] =~ /DXSpider Version: (\d+\.\d+) Build: (\d+(?:\.\d+)?)/) {
$self->version(53 + $1);
$self->user->version(53 + $1);
$self->build(0 + $2);
$self->user->put;
$self->sort('S');
}
- $self->{handle_xml}++ if DXXml::available() && $_[1] =~ /\bxml\b/;
- $self->{do_pc92}++ if $_[1] =~ /\bpc92\b/;
+ $self->{handle_xml}++ if DXXml::available() && $_[1] =~ /\bxml/;
+ if ($_[1] =~ /\bpc9x/) {
+ $self->{do_pc9x} = 1;
+ dbg("Do px9x set on $self->{call}");
+ }
} else {
$self->version(50.0);
$self->version($_[2] / 100) if $_[2] && $_[2] =~ /^\d+$/;
my $newline = "PC19^";
# new routing list
- my @rout;
+ my (@rout, @pc92out);
# first get the INTERFACE node
my $parent = Route::Node::get($self->{call});
return;
}
+ my $h;
+
# parse the PC19
#
# We are making a major change from now on. We are only going to accept
next if $call eq $main::mycall;
# check that this PC19 isn't trying to alter the wrong dxchan
+ $h = 0;
my $dxchan = DXChannel::get($call);
- if ($dxchan && $dxchan != $self) {
- dbg("PCPROT: PC19 from $self->{call} trying to alter wrong locally connected $call, ignored!") if isdbg('chanerr');
- next;
+ if ($dxchan) {
+ if ($dxchan == $self) {
+ $h = 1;
+ } else {
+ dbg("PCPROT: PC19 from $self->{call} trying to alter wrong locally connected $call, ignored!") if isdbg('chanerr');
+ next;
+ }
}
my $user = check_add_node($call);
RouteDB::update($call, $self->{call}, $dxchan ? 1 : undef);
- unless ($dxchan) {
- dbg("PCPROT: PC19 not directly connected, ignored") if isdbg('chanerr');
- next;
+ unless ($h) {
+ if ($parent->via_pc92) {
+ dbg("PCPROT: non-local node controlled by PC92, ignored") if isdbg('chanerr');
+ next;
+ }
}
my $r = Route::Node::get($call);
my $ar = $parent->add($call, $ver, $flags);
$user->wantroutepc19(1) unless defined $user->wantroutepc19;
push @rout, $ar if $ar;
+ push @pc92out, $r if $h;
} else {
next;
}
# but remember there will only be one (pair) these because any extras will be
# thrown away.
if (@rout) {
- $self->route_pc21($self->{call}, $line, @rout);
+# $self->route_pc21($self->{call}, $line, @rout);
$self->route_pc19($self->{call}, $line, @rout);
- $self->route_pc92a($main::mycall, $line, $main::routeroot, @rout) if $self->{state} eq 'normal';
+ }
+ if (@pc92out) {
+ $self->route_pc92a($main::mycall, $line, $main::routeroot, @pc92out) if $self->{state} eq 'normal';
}
}
{
my $self = shift;
- # send out delayed PC92 config for this node if it is external
- unless ($self->{do_pc92}) {
- my $node = Route::Node::get($self->{call});
- if ($node) {
- my @rout = map {my $r = Route::User::get($_); $r ? ($r) : ()} $node->users;
- $self->route_pc92c($main::mycall, undef, $node, @rout);
- }
+ # send out new PC92 config to everyone else
+ my $line = gen_my_pc92_config($main::me);
+ $self->broadcast_route_pc9x($main::mycall, undef, $line, 0);
+
+ # if this is an external node then send out the external config
+ unless ($self->{do_pc9x}) {
+ $line = gen_my_pc92_config(Route::Node::get($self->{call}));
+ $self->broadcast_route_pc9x($main::mycall, undef, $line, 0);
}
}
my $pcno = shift;
my $line = shift;
my $origin = shift;
+
+ if ($self->{do_pc9x} && $self->{state} ne 'init92') {
+ dbg("PCPROT: disconnecting because login call not sent in any pc92") if isdbg('chanerr');
+ $self->send("**** You logged in with $self->{call} but that is NOT your \$mycall");
+ $self->disconnect;
+ return;
+ }
$self->send_local_config();
$self->send(pc22());
$self->state('normal');
my $node = Route::Node::get($call);
if ($node) {
+ if ($node->via_pc92) {
+ dbg("PCPROT: controlled by PC92, ignored") if isdbg('chanerr');
+ return;
+ }
+
my $dxchan = DXChannel::get($call);
if ($dxchan && $dxchan != $self) {
dbg("PCPROT: PC21 from $self->{call} trying to alter locally connected $call, ignored!") if isdbg('chanerr');
return;
}
+ if (eph_dup($line)) {
+ dbg("PCPROT: dup PC21 detected") if isdbg('chanerr');
+ return;
+ }
+
if (@rout) {
$self->route_pc21($origin, $line, @rout);
- $self->route_pc92d($main::mycall, $line, $main::routeroot, @rout);
+# $self->route_pc92d($main::mycall, $line, $main::routeroot, @rout);
}
}
my $pcno = shift;
my $line = shift;
my $origin = shift;
- $self->state('normal');
- $self->{lastping} = 0;
- $self->send_delayed_pc92
+ if ($self->{do_pc9x}) {
+ if ($self->{state} ne 'init92') {
+ dbg("PCPROT: disconnecting because login call not sent in any pc92") if isdbg('chanerr');
+ $self->send("**** You logged in with $self->{call} but that is NOT your \$mycall");
+ $self->disconnect;
+ return;
+ }
+ }
+ $self->{lastping} = 0;
+ $self->state('normal');
+ $self->send_delayed_pc92;
}
# WWV info
my $line = shift;
my $origin = shift;
my $call = $_[1];
-
- my $l = $line;
- $l =~ s/[\x00-\x20\x7f-\xff]+//g; # remove all funny characters and spaces for dup checking
+ my $sort = $_[2];
+ my $val = $_[3];
+
+ my $l = "PC41^$call^$sort";
if (eph_dup($l, $eph_info_restime)) {
dbg("PCPROT: dup PC41, ignored") if isdbg('chanerr');
return;
# my $ref = Route::get($call) || Route->new($call);
# return unless $self->in_filter_route($ref);
- if ($_[3] eq $_[2] || $_[3] =~ /^\s*$/) {
+ if ($val eq $sort || $val =~ /^\s*$/) {
dbg('PCPROT: invalid value') if isdbg('chanerr');
return;
}
my $user = DXUser->get_current($call);
$user = DXUser->new($call) unless $user;
- if ($_[2] == 1) {
- $user->name($_[3]);
- } elsif ($_[2] == 2) {
- $user->qth($_[3]);
- } elsif ($_[2] == 3) {
- if (is_latlong($_[3])) {
- my ($lat, $long) = DXBearing::stoll($_[3]);
- $user->lat($lat);
- $user->long($long);
- $user->qra(DXBearing::lltoqra($lat, $long));
+ 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);
+ } elsif ($sort == 2) {
+ $user->qth($val);
+ } elsif ($sort == 3) {
+ if (is_latlong($val)) {
+ my ($lat, $long) = DXBearing::stoll($val);
+ $user->lat($lat) if $lat;
+ $user->long($long) if $long;
+ $user->qra(DXBearing::lltoqra($lat, $long)) unless $user->qra;
} else {
dbg('PCPROT: not a valid lat/long') if isdbg('chanerr');
return;
}
- } elsif ($_[2] == 4) {
- $user->homenode($_[3]);
- } elsif ($_[2] == 5) {
- if (is_qra(uc $_[3])) {
- my ($lat, $long) = DXBearing::qratoll(uc $_[3]);
- $user->lat($lat);
- $user->long($long);
- $user->qra(uc $_[3]);
+ } elsif ($sort == 4) {
+ $user->homenode($val);
+ } elsif ($sort == 5) {
+ if (is_qra(uc $val)) {
+ my ($lat, $long) = DXBearing::qratoll(uc $val);
+ $user->lat($lat) if $lat && !$user->lat;
+ $user->long($long) if $long && !$user->long;
+ $user->qra(uc $val);
} else {
dbg('PCPROT: not a valid QRA locator') if isdbg('chanerr');
return;
}
# perhaps this IS what we want after all
- # $self->route_pc41($ref, $call, $_[2], $_[3], $_[4]);
+ # $self->route_pc41($ref, $call, $sort, $val, $_[4]);
}
sub handle_42 {goto &handle_28}
my $icall = shift;
my @part = split /:/, $icall;
my ($flag, $call) = unpack "A A*", $part[0];
- return () unless $flag && $flag ge '0' && $flag le '7';
+ return () unless defined $flag && $flag ge '0' && $flag le '7';
return () unless $call && is_callsign($call);
my $is_node = $flag & 4;
my $is_extnode = $flag & 2;
sub _encode_pc92_call
{
my $ref = shift;
+
+ # plain call or value
+ return $ref unless ref $ref;
+
my $ext = shift;
my $flag = 0;
my $call = $ref->call;
if ($ref->isa('Route::Node') || $ref->isa('DXProt')) {
$flag |= 4;
my $dxchan = DXChannel::get($call);
- $flag |= 2 if $call ne $main::mycall && $dxchan && !$dxchan->{do_pc92};
+ $flag |= 2 if $call ne $main::mycall && $dxchan && !$dxchan->{do_pc9x};
if ($ext) {
if ($ref->version) {
my $version = $ref->version || 1.0;
{
my $parent = shift;
my $s = shift;
- my ($call, $is_node, $is_extnode, $here, $version, $build) = _decode_pc92_call($s);
+ my ($call, $is_node, $is_extnode, $here, $version, $build) = @$s;
my @rout;
if ($call) {
if ($is_node) {
+ dbg("ROUTE: added node $call to " . $parent->call) if isdbg('routelow');
@rout = $parent->add($call, $version, Route::here($here));
} else {
+ dbg("ROUTE: added user $call to " . $parent->call) if isdbg('routelow');
@rout = $parent->add_user($call, Route::here($here));
}
}
{
my $parent = shift;
my $s = shift;
- my ($call, $is_node, $is_extnode, $here, $version, $build) = _decode_pc92_call($s);
+ my ($call, $is_node, $is_extnode, $here, $version, $build) = @$s;
my @rout;
if ($call) {
if ($is_node) {
my $nref = Route::Node::get($call);
+ dbg("ROUTE: deleting node $call from " . $parent->call) if isdbg('routelow');
@rout = $nref->del($parent) if $nref;
} else {
my $uref = Route::User::get($call);
+ dbg("ROUTE: deleting user $call from " . $parent->call) if isdbg('routelow');
@rout = $parent->del_user($uref) if $uref;
}
}
my $t = shift;
my $pc = shift;
my $create = shift;
-
+
my $parent = ref $call ? $call : Route::Node::get($call);
if ($parent) {
- my $lastid = $parent->lastid->{$pc} || 0;
- $t += 86400 if $t < $lastid - 43200;
- if ($lastid >= $t) {
- dbg("PCPROT: dup / old id on $call <= $lastid, ignored") if isdbg('chanerr');
- return;
+ # we only do this for external calls whose routing table
+ # record come and go. The reference for mycall is permanent
+ # and not that frequently used, it also never times out, so
+ # the id on it is completely unreliable. Besides, only commands
+ # originating on this box will go through this code...
+ if ($parent->call ne $main::mycall) {
+ my $lastid = $parent->lastid->{$pc} || 0;
+ if ($t < $lastid) {
+ if (my $d = $lastid-86400+$t > $pc9x_past_age) {
+ dbg("PCPROT: $call id $t <= $lastid, ignored") if isdbg('chanerr');
+ return;
+ }
+ }
+ if ($lastid == $t) {
+ dbg("PCPROT: dup id on $call = $lastid, ignored") if isdbg('chanerr');
+ return;
+ }
}
- $t -= 86400 if $t >= 86400;
} elsif ($create) {
$parent = Route::Node->new($call);
}
$parent->lastid->{$pc} = $t;
-
+
return $parent;
}
my $line = shift;
my $origin = shift;
- $self->{do_pc92} ||= 1;
-
+ my (@radd, @rdel);
+
my $pcall = $_[1];
unless ($pcall) {
dbg("PCPROT: invalid callsign string '$_[1]', ignored") if isdbg('chanerr');
my $t = $_[2];
my $sort = $_[3];
- my @ent = grep {$_ && /^[0-7]/} @_[4 .. $#_];
-
if ($pcall eq $main::mycall) {
dbg("PCPROT: looped back, ignored") if isdbg('chanerr');
return;
}
+ if ($pcall eq $self->{call} && $self->{state} eq 'init') {
+ $self->state('init92');
+ $self->{do_pc9x} = 1;
+ dbg("Do pc9x set on $pcall");
+ }
+ unless ($self->{do_pc9x}) {
+ dbg("PCPROT: PC9x come in from non-PC9x node, ignored") if isdbg('chanerr');
+ return;
+ }
+
my $parent = check_pc9x_t($pcall, $t, 92, 1) || return;
+ my $oparent = $parent;
- $parent->lastid->{92} = $t;
- $parent->do_pc92(1);
+ $parent->do_pc9x(1);
+ $parent->via_pc92(1);
+
+ if ($sort eq 'F' || $sort eq 'R') {
- if (@ent) {
+ # this is the route finding section
+ # here is where the consequences of the 'find' command
+ # are dealt with
- # look at the first one which will always be a node of some sort
- # and update any information that needs to be done.
- my ($call, $is_node, $is_extnode, $here, $version, $build) = _decode_pc92_call($ent[0]);
- if ($call && $is_node) {
- if ($call eq $main::mycall) {
- dbg("PCPROT: looped back on node entry, ignored") if isdbg('chanerr');
+ my $from = $_[4];
+ my $target = $_[5];
+
+ if ($sort eq 'F') {
+ my $flag;
+ my $ref;
+ my $dxchan;
+ if ($ref = DXChannel::get($target)) {
+ $flag = 1; # we are directly connected
+ } else {
+ $ref = Route::get($target);
+ $dxchan = $ref->dxchan;
+ $flag = 2;
+ }
+ if ($ref && $flag && $dxchan) {
+ $self->send(pc92r($from, $target, $flag, int($dxchan->{pingave}*1000)));
return;
}
- if ($is_extnode) {
- # reparent to external node (note that we must have received a 'C' or 'A' record
- # from the true parent node for this external before we get one for the this node
- unless ($parent = Route::Node::get($call)) {
- dbg("PCPROT: no previous C or A for this external node received, ignored") if isdbg('chanerr');
- return;
+ } elsif ($sort eq 'R') {
+ if (my $dxchan = DXChannel::get($from)) {
+ handle_pc92_find_reply($dxchan, $pcall, $from, $target, @_[6,7]);
+ } else {
+ my $ref = Route::get($from);
+ if ($ref) {
+ my @dxchan = grep {$_->do_pc9x} $ref->alldxchan;
+ if (@dxchan) {
+ $_->send($line) for @dxchan;
+ } else {
+ dbg("PCPROT: no return route, ignored") if isdbg('chanerr')
+ }
+ } else {
+ dbg("PCPROT: no return route, ignored") if isdbg('chanerr')
}
- my $parent = check_pc9x_t($call, $t, 92) || return;
}
- } else {
- dbg("PCPROT: must be mycall or external node as first entry, ignored") if isdbg('chanerr');
return;
}
- $parent->here(Route::here($here));
- $parent->version($version) if $version && $version > $parent->version;
- $parent->build($build) if $build && $build > $parent->build;
- shift @ent;
- }
+ } elsif ($sort eq 'A' || $sort eq 'D' || $sort eq 'C') {
- my (@radd, @rdel);
-
- if ($sort eq 'A') {
- for (@ent) {
- push @radd, _add_thingy($parent, $_);
+ # this is the main route section
+ # here is where all the routes are created and destroyed
+
+ my @ent = map {[ _decode_pc92_call($_) ]} grep {$_ && /^[0-7]/} @_[4 .. $#_];
+ if (@ent) {
+
+ # look at the first one which will always be a node of some sort
+ # and update any information that needs to be done.
+ my ($call, $is_node, $is_extnode, $here, $version, $build) = @{$ent[0]};
+ if ($call && $is_node) {
+ if ($call eq $main::mycall) {
+ dbg("PCPROT: looped back on node entry, ignored") if isdbg('chanerr');
+ return;
+ }
+ if ($is_extnode) {
+ # this is only accepted from my "self"
+ if (DXChannel::get($call) && $call ne $self->{call}) {
+ dbg("PCPROT: locally connected node config for $call from other another node $self->{call}, ignored") if isdbg('chanerr');
+ return;
+ }
+ # reparent to external node (note that we must have received a 'C' or 'A' record
+ # from the true parent node for this external before we get one for the this node
+ unless ($parent = Route::Node::get($call)) {
+ dbg("PCPROT: no previous C or A for this external node received, ignored") if isdbg('chanerr');
+ return;
+ }
+ $parent = check_pc9x_t($call, $t, 92) || return;
+ $parent->via_pc92(1);
+ }
+ } else {
+ dbg("PCPROT: must be mycall or external node as first entry, ignored") if isdbg('chanerr');
+ return;
+ }
+ $parent->here(Route::here($here));
+ $parent->version($version) if $version && $version > $parent->version;
+ $parent->build($build) if $build && $build > $parent->build;
+ shift @ent;
}
- } elsif ($sort eq 'D') {
+
+ # do a pass through removing any references to either locally connected nodes or mycall
+ my @nent;
for (@ent) {
- push @rdel, _del_thingy($parent, $_);
+ next unless $_;
+ if ($_->[0] eq $main::mycall || DXChannel::get($_->[0])) {
+ dbg("PCPROT: $_->[0] refers to locally connected node, ignored") if isdbg('chanerr');
+ next;
+ }
+ push @nent, $_;
}
- } elsif ($sort eq 'C') {
- my (@nodes, @users);
- for (@ent) {
- my ($call, $is_node, $is_extnode, $here, $version, $build) = _decode_pc92_call($_);
- if ($call) {
- if ($is_node) {
- push @nodes, $call;
+
+ if ($sort eq 'A') {
+ for (@nent) {
+ push @radd, _add_thingy($parent, $_);
+ }
+ } elsif ($sort eq 'D') {
+ for (@nent) {
+ push @rdel, _del_thingy($parent, $_);
+ }
+ } elsif ($sort eq 'C') {
+ my (@nodes, @users);
+
+ # we only reset obscounts on config records
+ $oparent->reset_obs;
+ dbg("ROUTE: reset obscount on $pcall now " . $oparent->obscount) if isdbg('route');
+ if ($oparent != $parent) {
+ $parent->reset_obs;
+ dbg("ROUTE: reset obscount on $parent->{call} now " . $parent->obscount) if isdbg('route');
+ }
+
+ #
+ foreach my $r (@nent) {
+ # my ($call, $is_node, $is_extnode, $here, $version, $build) = _decode_pc92_call($_);
+ if ($r->[0]) {
+ if ($r->[1]) {
+ push @nodes, $r->[0];
+ } else {
+ push @users, $r->[0];
+ }
} else {
- push @users, $call;
+ dbg("DXPROT: pc92 call entry '$_' not decoded, ignored") if isdbg('chanerr');
}
- } else {
- dbg("DXPROT: pc92 call entry '$_' not decoded, ignored") if isdbg('chanerr');
}
- }
- my ($dnodes, $dusers, $nnodes, $nusers) = $parent->calc_config_changes(\@nodes, \@users);
+ my ($dnodes, $dusers, $nnodes, $nusers) = $parent->calc_config_changes(\@nodes, \@users);
- for (@ent) {
- my ($call, $is_node, $is_extnode, $here, $version, $build) = _decode_pc92_call($_);
- if ($call) {
- push @radd,_add_thingy($parent, $_) if grep $call eq $_, (@$nnodes, @$nusers);
- push @rdel,_del_thingy($parent, $_) if grep $call eq $_, (@$dnodes, @$dusers);
+ # add users here
+ foreach my $r (@nent) {
+ my $call = $r->[0];
+ if ($call) {
+ push @radd,_add_thingy($parent, $r) if grep $call eq $_, (@$nnodes, @$nusers);
+ }
}
+ # del users here
+ foreach my $r (@$dnodes) {
+ push @rdel,_del_thingy($parent, [$r, 1]);
+ }
+ foreach my $r (@$dusers) {
+ push @rdel,_del_thingy($parent, [$r, 0]);
+ }
+ } else {
+ dbg("PCPROT: unknown action '$sort', ignored") if isdbg('chanerr');
+ return;
}
- } else {
- dbg("PCPROT: unknown action '$sort', ignored") if isdbg('chanerr');
- return;
+
+ foreach my $r (@rdel) {
+ next unless $r;
+
+ $self->route_pc21($pcall, undef, $r) if $r->isa('Route::Node');
+ $self->route_pc17($pcall, undef, $parent, $r) if $r->isa('Route::User');
+ }
+ my @pc19 = grep { $_ && $_->isa('Route::Node') } @radd;
+ my @pc16 = grep { $_ && $_->isa('Route::User') } @radd;
+ unshift @pc19, $parent if $self->{state} eq 'init92' && $oparent == $parent;
+ $self->route_pc19($pcall, undef, @pc19) if @pc19;
+ $self->route_pc16($pcall, undef, $parent, @pc16) if @pc16;
}
+ # broadcast it if we get here
$self->broadcast_route_pc9x($pcall, undef, $line, 0);
- foreach my $r (@rdel) {
- next unless $r;
+}
+
+
+sub handle_93
+{
+ my $self = shift;
+ my $pcno = shift;
+ my $line = shift;
+ my $origin = shift;
+
+# $self->{do_pc9x} ||= 1;
+
+ my $pcall = $_[1];
+ unless (is_callsign($pcall)) {
+ dbg("PCPROT: invalid callsign string '$_[1]', ignored") if isdbg('chanerr');
+ return;
+ }
+ my $t = $_[2];
+ my $parent = check_pc9x_t($pcall, $t, 93, 1) || return;
+
+ my $to = $_[3];
+ my $from = $_[4];
+ my $via = $_[5];
+ my $text = $_[6];
+ my $onode = $_[7];
+ $onode = $pcall if @_ <= 8;
+
+ # will we allow it at all?
+ if ($censorpc) {
+ my @bad;
+ if (@bad = BadWords::check($text)) {
+ dbg("PCPROT: Bad words: @bad, dropped") if isdbg('chanerr');
+ return;
+ }
+ }
+
+ # if this is a 'bad spotter' user then ignore it
+ my $nossid = $from;
+ $nossid =~ s/-\d+$//;
+ if ($badspotter->in($nossid)) {
+ dbg("PCPROT: Bad Spotter, dropped") if isdbg('chanerr');
+ return;
+ }
+
+ if (is_callsign($to)) {
+ # local talks
+ my $dxchan;
+ $dxchan = DXChannel::get($main::myalias) if $to eq $main::mycall;
+ $dxchan = DXChannel::get($to) unless $dxchan;
+ if ($dxchan && $dxchan->is_user) {
+ $dxchan->talk($from, $to, $via, $text, $onode);
+ return;
+ }
+
+ # convert to PC10 talks where appropriate
+ my $ref = Route::get($to);
+ if ($ref) {
+ my @dxchan = $ref->alldxchan;
+ for $dxchan (@dxchan) {
+ if ($dxchan->{do_pc9x}) {
+ $dxchan->send($line);
+ } else {
+ $dxchan->talk($from, $to, $via, $text, $onode);
+ }
+ }
+ return;
+ }
+
+ # otherwise, drop through and allow it to be broadcast
+ } elsif ($to eq '*' || uc $to eq 'SYSOP' || uc $to eq 'WX') {
+ # announces
+ my $sysop = uc $to eq 'SYSOP' ? '*' : ' ';
+ my $wx = uc $to eq 'WX' ? '1' : '0';
+ my $local = $via eq 'LOCAL' ? '*' : $via;
- $self->route_pc21($pcall, undef, $r) if $r->isa('Route::Node');
- $self->route_pc17($pcall, undef, $parent, $r) if $r->isa('Route::User');
+ $self->send_announce(1, pc12($from, $text, $local, $via, $sysop, $wx, $pcall), $from, $local, $text, $sysop, $pcall, $wx, $via eq 'LOCAL' ? $via : undef);
+ return if $via eq 'LOCAL';
+ } else {
+ # chat messages to non-pc9x nodes
+ $self->send_chat(1, pc12($from, $text, undef, $to, undef, $pcall), $from, '*', $text, $to, $pcall, '0');
}
- my @pc19 = grep { $_ && $_->isa('Route::Node') } @radd;
- my @pc16 = grep { $_ && $_->isa('Route::User') } @radd;
- $self->route_pc19($pcall, undef, @pc19) if @pc19;
- $self->route_pc16($pcall, undef, $parent, @pc16) if @pc16;
+ $self->broadcast_route_pc9x($pcall, undef, $line, 0);
}
# if get here then rebroadcast the thing with its Hop count decremented (if
if (eph_dup($line)) {
dbg("PCPROT: Ephemeral dup, dropped") if isdbg('chanerr');
} else {
- unless ($self->{isolate}) {
- DXChannel::broadcast_nodes($line, $self) if $line =~ /\^H\d+\^?~?$/; # send it to everyone but me
+ if ($pcno >= 90) {
+ my $pcall = $_[1];
+ unless (is_callsign($pcall)) {
+ dbg("PCPROT: invalid callsign string '$_[1]', ignored") if isdbg('chanerr');
+ return;
+ }
+ my $t = $_[2];
+ my $parent = check_pc9x_t($pcall, $t, $pcno, 1) || return;
+ $self->broadcast_route_pc9x($pcall, undef, $line, 0);
+ } else {
+ unless ($self->{isolate}) {
+ DXChannel::broadcast_nodes($line, $self) if $line =~ /\^H\d+\^?~?$/; # send it to everyone but me
+ }
}
}
}