use strict;
use vars qw($me $pc11_max_age $pc23_max_age
- $last_hour $last10 %emph %pings %rcmds
+ $last_hour $last10 %eph %pings %rcmds
%nodehops $baddx $badspotter $badnode $censorpc
$allowzero $decode_dk0wcy $send_opernam @checklist);
next unless $call && $conf && defined $here && is_callsign($call);
$conf = $conf eq '*';
- push @rout, $parent->add_user($call, Route::here($here)|Route::conf($conf));
+ my $r = Route::User::get($call);
+ my $flags = Route::here($here)|Route::conf($conf);
+
+ if ($r && $r->flags != $flags) {
+ $r->flags($flags);
+ push @rout, $r;
+ } elsif (!$r) {
+ push @rout, $parent->add_user($call, $flags);
+ }
# add this station to the user database, if required
$call =~ s/-\d+$//o; # remove ssid for users
# queue up any messages (look for privates only)
DXMsg::queue_msg(1) if $self->state eq 'normal';
- dbg('route', "B/C PC16 on $ncall for: " . join(',', map{$_->call} @rout)) if @rout;
$self->route_pc16($parent, @rout) if @rout;
return;
}
if ($pcno == 17) { # remove a user
my $dxchan;
my $ncall = $field[2];
+ my $ucall = $field[1];
if ($ncall eq $main::mycall) {
dbg('chan', "PCPROT: trying to alter config on this node from outside!");
return;
dbg('chan', "PCPROT: Route::Node $ncall not in config");
return;
}
- my @rout = $parent->del_user($field[1]);
- dbg('route', "B/C PC17 on $ncall for: $field[1]");
+ my @rout = $parent->del_user($ucall);
$self->route_pc17($parent, @rout) if @rout;
return;
}
# update it if required
my $r;
- if ($parent->call eq $call && !$parent->version) {
+ my $flags = Route::here($here)|Route::conf($conf);
+ if ($parent->call eq $call && ($parent->version ne $ver || $parent->flags != $flags)) {
$parent->version($ver);
- $parent->flags(Route::here($here)|Route::conf($conf));
+ $parent->flags($flags);
push @rout, $parent;
} elsif ($parent->call ne $call) {
next if $call eq $main::mycall || $call eq $self->{call};
push @rout, $r if $r;
} else {
$r = Route::Node::get($call);
- if ($r && (!$r->version || $r->version eq '0000')) {
+ if ($r && ($r->version ne $ver || $r->flags != $flags)) {
$r->version($ver);
$r->flags(Route::here($here)|Route::conf($conf));
push @rout, $r;
$user->put;
}
- dbg('route', "B/C PC19 for: " . join(',', map{$_->call} @rout)) if @rout;
-
$self->route_pc19(@rout) if @rout;
return;
}
my $call = uc $field[1];
my @rout;
my $parent = Route::Node::get($self->{call});
+ unless ($parent) {
+ dbg('chan', "PCPROT: Route::Node $call not in config");
+ return;
+ }
+ my $node = Route::Node::get($call);
if ($call ne $main::mycall) { # don't allow malicious buggers to disconnect me!
if ($call eq $self->{call}) {
}
# routing objects
- if ($parent) {
- push @rout, $parent->del_node($call);
- } else {
- dbg('chan', "PCPROT: Route::Node $call not in config");
- }
+ push @rout, $node->del($parent) if $node;
} else {
dbg('chan', "PCPROT: I WILL _NOT_ be disconnected!");
return;
}
- dbg('route', "B/C PC21 for: " . join(',', (map{$_->call} @rout))) if @rout;
-
$self->route_pc21(@rout) if @rout;
return;
}
$ref->here($field[2]) if $ref;
$ref = Route::User::get($call);
$ref->here($field[2]) if $ref;
- last SWITCH;
+
+ $self->route_pc24($ref, $field[3]) if $ref && !eph_dup($line);
+ return;
}
if ($pcno == 25) { # merge request
if ($pcno == 41) { # user info
# add this station to the user database, if required
- my $user = DXUser->get_current($field[1]);
- $user = DXUser->new($field[1]) if !$user;
+ my $call = $field[1];
+ my $user = DXUser->get_current($call);
+ $user = DXUser->new($call) if !$user;
if ($field[2] == 1) {
$user->name($field[3]);
}
$user->lastoper($main::systime); # to cut down on excessive for/opers being generated
$user->put;
- last SWITCH;
+ my $ref = Route::get($call);
+ $self->route_pc41($ref, $field[2], $field[3], $field[4]) if $ref && !eph_dup($line);
}
if ($pcno == 43) {
last SWITCH;
}
if ($pcno == 50) { # keep alive/user list
- my $node = Route::Node::get($field[1]);
+ my $call = $field[1];
+ my $node = Route::Node::get($call);
if ($node) {
return unless $node->call eq $self->{call};
$node->usercount($field[2]);
+ $self->route_pc50($node, $field[2], $field[3]) unless eph_dup($line);
}
- last SWITCH;
+ return;
}
if ($pcno == 51) { # incoming ping requests/answers
+ my $to = $field[1];
+ my $from = $field[2];
+ my $flag = $field[3];
# is it for us?
- if ($field[1] eq $main::mycall) {
- my $flag = $field[3];
+ if ($to eq $main::mycall) {
if ($flag == 1) {
- $self->send(pc51($field[2], $field[1], '0'));
+ $self->send(pc51($from, $to, '0'));
} else {
# it's a reply, look in the ping list for this one
- my $ref = $pings{$field[2]};
+ my $ref = $pings{$from};
if ($ref) {
- my $tochan = DXChannel->get($field[2]);
+ my $tochan = DXChannel->get($from);
while (@$ref) {
my $r = shift @$ref;
my $dxchan = DXChannel->get($r->{call});
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))
+ $dxchan->send($dxchan->msg('pingi', $from, $s, $ave))
} elsif ($dxchan->is_node) {
if ($tochan) {
$tochan->{nopings} = $tochan->user->nopings || 2; # pump up the timer
}
} else {
# route down an appropriate thingy
- $self->route($field[1], $line);
+ $self->route($to, $line);
}
return;
}
if ($pcno == 75) { # dunno but route it
- if ($field[1] ne $main::mycall) {
- $self->route($field[1], $line);
+ my $call = $field[1];
+ if ($call ne $main::mycall) {
+ $self->route($call, $line);
}
return;
}
if ($pcno == 73) { # WCY broadcasts
+ my $call = $field[1];
# do some de-duping
- my $d = cltounix($field[1], sprintf("%02d18Z", $field[2]));
+ my $d = cltounix($call, 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', "PCPROT: WCY Date ($field[1] $field[2]) out of range");
+ dbg('chan', "PCPROT: WCY Date ($call $field[2]) out of range");
return;
}
@field = map { unpad($_) } @field;
}
if ($pcno == 84) { # remote commands (incoming)
- if ($field[1] eq $main::mycall) {
+ my $call = $field[1];
+ if ($call eq $main::mycall) {
my $ref = DXUser->get_current($field[2]);
my $cref = Route::Node::get($field[2]);
Log('rcmd', 'in', $ref->{priv}, $field[2], $field[4]);
$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]);
+ my $ref = DXUser->get_current($call);
if ($ref && $ref->is_clx) {
- $self->route($field[1], $line);
+ $self->route($call, $line);
} else {
- $self->route($field[1], pc34($field[2], $field[1], $field[4]));
+ $self->route($call, pc34($field[2], $call, $field[4]));
}
}
return;
}
if ($pcno == 85) { # remote command replies
- if ($field[1] eq $main::mycall) {
+ my $call = $field[1];
+ if ($call eq $main::mycall) {
my $dxchan = DXChannel->get($field[3]);
if ($dxchan) {
$dxchan->send($field[4]);
}
}
} else {
- my $ref = DXUser->get_current($field[1]);
+ my $ref = DXUser->get_current($call);
if ($ref && $ref->is_clx) {
- $self->route($field[1], $line);
+ $self->route($call, $line);
} else {
- $self->route($field[1], pc35($field[2], $field[1], $field[4]));
+ $self->route($call, pc35($field[2], $call, $field[4]));
}
}
return;
# REBROADCAST!!!!
#
- if (emph_dup($line)) {
+ if (eph_dup($line)) {
dbg('chan', "PCPROT: Ephemeral dup, dropped");
} else {
unless ($self->{isolate}) {
# send a pc50 out on this channel
$dxchan->{pc50_t} = $main::systime unless exists $dxchan->{pc50_t};
if ($t >= $dxchan->{pc50_t} + $DXProt::pc50_interval) {
- $dxchan->send(pc50(scalar DXChannel::get_all_users));
+ my $s = pc50($me, scalar DXChannel::get_all_users);
+ eph_dup($s);
+ $dxchan->send($s);
$dxchan->{pc50_t} = $t;
}
# every ten seconds
if ($t - $last10 >= 10) {
- # clean out emphemera
+ # clean out ephemera
- emph_clean();
+ eph_clean();
$last10 = $t;
}
($filter) = $dxchan->{spotsfilter}->it(@{$fref}) if ref $fref;
next unless $filter;
}
- next if $sort eq 'ann' && !$dxchan->{ann};
+ next if $sort eq 'ann' && !$dxchan->{ann} && $s !~ /^To\s+LOCAL\s+de\s+(?:$main::myalias|$main::mycall)/i;
next if $sort eq 'wwv' && !$dxchan->{wwv};
next if $sort eq 'wcy' && !$dxchan->{wcy};
next if $sort eq 'wx' && !$dxchan->{wx};
}
# do routing stuff
-# my $node = Route::Node::get($self->{call});
-# my @rout = $node->del_nodes if $node;
- my @rout = $main::routeroot->del_node($call);
- dbg('route', "B/C PC21 (from PC39) for: " . join(',', (map{ $_->call } @rout))) if @rout;
+ my $node = Route::Node::get($call);
+ my @rout;
+ if ($node) {
+ @rout = $node->del_nodes; # at the next level
+ @rout = $node->del($main::routeroot);
+ }
# unbusy and stop and outgoing mail
my $mref = DXMsg::get_busy($call);
if ($self->{routefilter}) {
for (; @_ && $no; $no--) {
my $r = shift;
- ($filter, $hops) = $self->{routefilter}->it($self->{call}, $self->{dxcc}, $self->{itu}, $self->{cq}, $r->call, $r->dxcc, $r->itu, $r->cq);
- push @rin, $r if $filter;
+ if ($r) {
+ ($filter, $hops) = $self->{routefilter}->it($self->{call}, $self->{dxcc}, $self->{itu}, $self->{cq}, $r->call, $r->dxcc, $r->itu, $r->cq);
+ push @rin, $r if $filter;
+ } else {
+ dbg('chan', "was sent a null value");
+ }
}
}
if (@rin) {
broadcast_route($self, \&pc21, scalar @_, @_);
}
-sub emph_dup
+sub route_pc24
+{
+ my $self = shift;
+ broadcast_route($self, \&pc24, 1, @_);
+}
+
+sub route_pc41
+{
+ my $self = shift;
+ broadcast_route($self, \&pc41, 1, @_);
+}
+
+sub route_pc50
+{
+ my $self = shift;
+ broadcast_route($self, \&pc50, 1, @_);
+}
+
+
+
+sub eph_dup
{
my $s = shift;
# chop the end off
- $s =~ s/\^H\d\d?\^?~?@//;
- return 1 if exists $emph{$s};
- $emph{$s} = $main::systime;
+ $s =~ s/\^H\d\d?\^?~?$//;
+ return 1 if exists $eph{$s};
+ $eph{$s} = $main::systime;
return undef;
}
-sub emph_clean
+sub eph_clean
{
my ($key, $val);
- while (($key, $val) = each %emph) {
+ while (($key, $val) = each %eph) {
if ($main::systime - $val > 90) {
- delete $emph{$key};
+ delete $eph{$key};
}
}
}