use DXDebug;
use Filter;
use Local;
+use DXDb;
use Carp;
$self->{consort} = $line; # save the connection type
$self->{here} = 1;
- # get the filters
- $self->{spotfilter} = Filter::read_in('spots', $call);
- $self->{wwvfilter} = Filter::read_in('wwv', $call);
- $self->{annfilter} = Filter::read_in('ann', $call);
+ # 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->{inannfilter} = Filter::read_in('ann', $call, 1);
# set unbuffered and no echo
$self->send_now('B',"0");
my $ref = DXChannel->get($call);
$ref->send("$call de $field[1]: $text") if $ref && $ref->{talk};
} else {
- route($field[2], $line); # relay it on its way
+ $self->route($field[2], $line); # relay it on its way
}
return;
}
# route 'foreign' pc26s
if ($pcno == 26) {
if ($field[7] ne $main::mycall) {
- route($field[7], $line);
+ $self->route($field[7], $line);
return;
}
}
# if this is a 'nodx' node then ignore it
- last SWITCH if grep $field[7] =~ /^$_/, @DXProt::nodx_node;
+ if (grep $field[7] =~ /^$_/, @DXProt::nodx_node) {
+ dbg('chan', "Bad DXNode, dropped");
+ return;
+ }
# convert the date to a unix date
my $d = cltounix($field[3], $field[4]);
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];
+ my $dupkey = $field[1].$field[2].$text;
if ($anndup{$dupkey}) {
dbg('chan', "Duplicate Announce ignored\n");
return;
}
$anndup{$dupkey} = $main::systime;
- # global ann filtering on INPUT
- my ($filter, $hops) = Filter::it($self->{annfilter}, @field[1..6], $self->{call} ) if $self->{annfilter};
- if ($self->{annfilter} && !$filter) {
- dbg('chan', "Rejected by filter");
- return;
- }
-
if ($field[2] eq '*' || $field[2] eq $main::mycall) {
- # strip leading and trailing stuff
- my $text = unpad($field[3]);
- my $target;
- my $to = 'To ';
- my @list;
-
- if ($field[4] eq '*') { # sysops
- $target = "SYSOP";
- @list = map { $_->priv >= 5 ? $_ : () } get_all_users();
- } elsif ($field[4] gt ' ') { # speciality list handling
- my ($name) = split /\./, $field[4];
- $target = "$name"; # put the rest in later (if bothered)
- }
-
- if ($field[6] eq '1') {
- $target = "WX";
- $to = '';
- }
- $target = "All" if !$target;
-
- if (@list > 0) {
- broadcast_list("$to$target de $field[1]: $text", 'ann', undef, @list);
- } else {
- broadcast_users("$target de $field[1]: $text", 'ann', undef);
+ # global ann filtering on INPUT
+ if ($self->{inannfilter}) {
+ my ($filter, $hops) = Filter::it($self->{inannfilter}, @field[1..6], $self->{call} );
+ unless ($filter) {
+ dbg('chan', "Rejected by filter");
+ return;
+ }
}
- Log('ann', $target, $field[1], $text);
+
+ # 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);
+ my $wwv = Geomag::update($main::systime, $hour, $sfi, $a, $k, "R=$r, Next K=$next$alarm", $decode_dk0wcy, $field[5], $r) if $sfi && $r;
}
- return if $field[2] eq $main::mycall; # it's routed to me
} else {
- route($field[2], $line);
- return; # only on a routed one
+ $self->route($field[2], $line);
}
- last SWITCH;
+ return;
}
if ($pcno == 13) {
if ($pcno == 16) { # add a user
my $node = DXCluster->get_exact($field[1]);
+ my $dxchan;
+ if (!$node && ($dxchan = DXChannel->get($field[1]))) {
+ # add it to the node table if it isn't present and it's
+ # connected locally
+ $node = DXNode->new($dxchan, $field[1], 0, 1, 5400);
+ broadcast_ak1a(pc19($dxchan, $node), $dxchan, $self) unless $dxchan->{isolate};
+
+ }
return unless $node; # ignore if havn't seen a PC19 for this one yet
return unless $node->isa('DXNode');
if ($node->dxchan != $self) {
dbg('chan', "LOOP: $field[1] came in on wrong channel");
return;
}
- my $dxchan;
if (($dxchan = DXChannel->get($field[1])) && $dxchan != $self) {
dbg('chan', "LOOP: $field[1] connected locally");
return;
}
my $i;
-
-
+
for ($i = 2; $i < $#field; $i++) {
my ($call, $confmode, $here) = $field[$i] =~ /^(\S+) (\S) (\d)/o;
next if !$call || length $call < 3 || length $call > 8;
if ($pcno == 17) { # remove a user
my $node = DXCluster->get_exact($field[2]);
+ my $dxchan;
+ if (!$node && ($dxchan = DXChannel->get($field[2]))) {
+ # add it to the node table if it isn't present and it's
+ # connected locally
+ $node = DXNode->new($dxchan, $field[2], 0, 1, 5400);
+ broadcast_ak1a(pc19($dxchan, $node), $dxchan, $self) unless $dxchan->{isolate};
+ return;
+ }
return unless $node;
return unless $node->isa('DXNode');
if ($node->dxchan != $self) {
dbg('chan', "LOOP: $field[2] came in on wrong channel");
return;
}
- my $dxchan;
if (($dxchan = DXChannel->get($field[2])) && $dxchan != $self) {
dbg('chan', "LOOP: $field[2] connected locally");
return;
# route 'foreign' pc27s
if ($pcno == 27) {
if ($field[8] ne $main::mycall) {
- route($field[8], $line);
+ $self->route($field[8], $line);
return;
}
}
dbg('chan', "Dup WWV Spot ignored\n");
return;
}
- if (($pcno == 23 && $d < $main::systime - $pc23_max_age) || $d > $main::systime + 900 || $field[2] < 0 || $field[2] > 23) {
+ 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 == 25) { # merge request
if ($field[1] ne $main::mycall) {
- route($field[1], $line);
+ $self->route($field[1], $line);
return;
}
if ($field[2] eq $main::mycall) {
if ($pcno == 49 || $field[1] eq $main::mycall) {
DXMsg::process($self, $line);
} else {
- route($field[1], $line);
+ $self->route($field[1], $line);
}
return;
}
$self->send(pc35($main::mycall, $field[2], "$main::mycall:your attempt is logged, Tut tut tut...!"));
}
} else {
- route($field[1], $line);
+ $self->route($field[1], $line);
}
return;
}
delete $rcmds{$field[2]} if !$dxchan;
}
} else {
- route($field[1], $line);
+ $self->route($field[1], $line);
}
return;
}
last SWITCH;
}
if ($pcno == 37 || $pcno == 44 || $pcno == 45 || $pcno == 46 || $pcno == 47) {
- if ($field[1] eq $main::mycall) {
- ;
- } else {
- route($field[1], $line);
- }
+ DXDb::process($self, $line);
return;
}
# 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;
+ while (@$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;
+ }
}
}
} else {
# route down an appropriate thingy
- route($field[1], $line);
+ $self->route($field[1], $line);
}
return;
}
# REBROADCAST!!!!
#
- if (!$self->{isolate}) {
+ unless ($self->{isolate}) {
broadcast_ak1a($line, $self); # send it to everyone but me
}
}
if ($t >= $dxchan->pc50_t + $DXProt::pc50_interval) {
$dxchan->send(pc50());
$dxchan->pc50_t($t);
- }
+ }
}
my $key;
$dxchan->send($routeit) if $routeit;
} else {
$dxchan->send($routeit) unless $dxchan->{isolate} || $self->{isolate};
-
}
} elsif ($dxchan->is_user && $dxchan->{dx}) {
my $buf = Spot::formatb($_[0], $_[1], $_[2], $_[3], $_[4]);
$buf .= "\a\a" if $dxchan->{beep};
if ($dxchan->{state} eq 'prompt' || $dxchan->{state} eq 'convers') {
- $dxchan->send($buf) if !$hops || ($hops && $filter);
+ $dxchan->send($buf);
} else {
- $dxchan->delay($buf) if !$hops || ($hops && $filter);
+ $dxchan->delay($buf);
}
}
}
# taking into account filtering and so on
foreach $dxchan (@dxchan) {
my $routeit;
- my ($filter, $hops) = Filter::it($dxchan->{wwvfilter}, @_, $self->{call} ) if $dxchan->{wwvfilter};
+ my ($filter, $hops);
+
+ if ($dxchan->{spotfilter}) {
+ ($filter, $hops) = Filter::it($dxchan->{wwvfilter}, @_, $self->{call} );
+ next unless $filter;
+ }
if ($dxchan->is_ak1a) {
next if $dxchan == $self;
if ($hops) {
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') {
- $dxchan->send($buf) if !$hops || ($hops && $filter);
+ $dxchan->send($buf);
+ } else {
+ $dxchan->delay($buf);
+ }
+ }
+ }
+}
+
+# send an announce
+sub send_announce
+{
+ my $self = shift;
+ my $line = shift;
+ my @dxchan = DXChannel->get_all();
+ my $dxchan;
+ my $text = unpad($_[2]);
+ my $target;
+ my $to = 'To ';
+
+ if ($_[3] eq '*') { # sysops
+ $target = "SYSOP";
+ } elsif ($_[3] gt ' ') { # speciality list handling
+ my ($name) = split /\./, $_[3];
+ $target = "$name"; # put the rest in later (if bothered)
+ }
+
+ if ($_[5] eq '1') {
+ $target = "WX";
+ $to = '';
+ }
+ $target = "All" if !$target;
+
+ Log('ann', $target, $_[0], $text);
+
+ # 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->{annfilter}) {
+ ($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
+ 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->{ann}) {
+ 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') {
+ $dxchan->send($buf);
} else {
- $dxchan->delay($buf) if !$hops || ($hops && $filter);
+ $dxchan->delay($buf);
}
}
}
#
sub route
{
- my ($call, $line) = @_;
+ my ($self, $call, $line) = @_;
my $cl = DXCluster->get_exact($call);
- if ($cl) {
+ if ($cl) { # don't route it back down itself
+ 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) {
my $r = {};
$r->{call} = $from;
$r->{t} = $main::systime;
- route($to, pc51($to, $main::mycall, 1));
+ route(undef, $to, pc51($to, $main::mycall, 1));
push @$ref, $r;
}
$r->{call} = $from;
$r->{t} = $main::systime;
$r->{cmd} = $cmd;
- route($to, pc34($main::mycall, $to, $cmd));
+ route(undef, $to, pc34($main::mycall, $to, $cmd));
$rcmds{$to} = $r;
}
1;