X-Git-Url: http://dxcluster.net/gitweb/gitweb.cgi?a=blobdiff_plain;f=perl%2FDXProt.pm;h=d9b03a907d1768420574dcb9ffb51e19266cc983;hb=0e84728de35d2dadbb9d624614a471b68ae9eef6;hp=19859af08d4789b95022e4962500506f8148ecb6;hpb=82cf94c00faefabee08b8a930dab31de8b75ee49;p=spider.git diff --git a/perl/DXProt.pm b/perl/DXProt.pm index 19859af0..d9b03a90 100644 --- a/perl/DXProt.pm +++ b/perl/DXProt.pm @@ -24,20 +24,24 @@ use DXProtout; use DXDebug; use Filter; use Local; +use DXDb; use Carp; use strict; -use vars qw($me $pc11_max_age $pc11_dup_age $pc23_dup_age - %spotdup %wwvdup $last_hour %pings %rcmds +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); + %anndup $allowzero $pc12_dup_lth $decode_dk0wcy); $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 = 24*3600; # the maximum time to keep the ann 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 @@ -111,10 +115,10 @@ sub start $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"); @@ -149,7 +153,13 @@ sub normal my ($pcno) = $field[0] =~ /^PC(\d\d)/; # just get the number return unless $pcno; return if $pcno < 10 || $pcno > 51; - + + # dump bad protocol messages unless it is a PC29 + if ($line =~ /\%[0-9A-F][0-9A-F]/o && $pcno != 29) { + dbg('chan', "CORRUPT protocol message - dumped"); + return; + } + # local processing 1 my $pcr; eval { @@ -172,15 +182,26 @@ sub normal 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; } if ($pcno == 11 || $pcno == 26) { # dx spot + + # route 'foreign' pc26s + if ($pcno == 26) { + if ($field[7] ne $main::mycall) { + $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]); @@ -195,7 +216,7 @@ sub normal # store it away my $spotter = $field[6]; - $spotter =~ s/-\d+$//o; # strip off the ssid from the spotter + $spotter =~ s/-[\@\d]+$//o; # strip off the ssid from the spotter # do some de-duping my $freq = $field[1] - 0; @@ -212,6 +233,12 @@ sub normal dbg('chan', "Bad DX spot, ignored"); return; } + + # 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"); + return; + } my @spot = Spot::add($freq, $field[2], $d, $text, $spotter, $field[7]); @@ -239,58 +266,40 @@ sub normal } if ($pcno == 12) { # announces - # announce duplicate checking - my $text = uc unpad($field[3]); - my $dupkey = $field[1].$field[2].$text.$field[4].$field[6]; + # announce duplicate checking + my $text = substr(uc unpad($field[3]), 0, $pc12_dup_lth); + my $dupkey = $field[1].$field[2].$text; if ($anndup{$dupkey}) { dbg('chan', "Duplicate Announce ignored\n"); return; } $anndup{$dupkey} = $main::systime; - # global ann filtering - 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 = ''; + # 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; + } } - $target = "All" if !$target; + + # send it + $self->send_announce($line, @field[1..6]); - if (@list > 0) { - broadcast_list("$to$target de $field[1]: $text", 'ann', undef, @list); - } else { - broadcast_users("$target de $field[1]: $text", 'ann', undef); + 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) if $sfi && $r; } - Log('ann', $target, $field[1], $text); - 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) { @@ -305,15 +314,26 @@ sub normal 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: come in on wrong channel"); + dbg('chan', "LOOP: $field[1] came in on wrong channel"); + return; + } + 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; @@ -341,10 +361,22 @@ sub normal 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: come in on wrong channel"); + dbg('chan', "LOOP: $field[2] came in on wrong channel"); + return; + } + if (($dxchan = DXChannel->get($field[2])) && $dxchan != $self) { + dbg('chan', "LOOP: $field[2] connected locally"); return; } my $ref = DXCluster->get_exact($field[1]); @@ -353,36 +385,57 @@ sub normal } if ($pcno == 18) { # link request + $self->state('init'); + + # first clear out any nodes on this dxchannel + my @gonenodes = map { $_->dxchan == $self ? $_ : () } DXNode::get_all(); + foreach my $node (@gonenodes) { + next if $node->dxchan == $DXProt::me; + broadcast_ak1a(pc21($node->call, 'Gone, re-init') , $self) unless $self->{isolate}; + $node->del(); + } $self->send_local_config(); $self->send(pc20()); - $self->state('init'); return; # we don't pass these on } if ($pcno == 19) { # incoming cluster list my $i; + my $newline = "PC19^"; for ($i = 1; $i < $#field-1; $i += 4) { my $here = $field[$i]; my $call = uc $field[$i+1]; - my $confmode = $field[$i+2] eq '*'; + my $confmode = $field[$i+2]; my $ver = $field[$i+3]; + + $ver = 5400 if !$ver && $allowzero; # now check the call over my $node = DXCluster->get_exact($call); - if ($node && $node->dxchan != $self) { - dbg('chan', "LOOP: come in on wrong channel"); - return; + if ($node) { + my $dxchan; + if (($dxchan = DXChannel->get($call)) && $dxchan != $self) { + dbg('chan', "LOOP: $call connected locally"); + } + if ($node->dxchan != $self) { + dbg('chan', "LOOP: $call come in on wrong channel"); + next; + } + dbg('chan', "already have $call"); + next; } - next if $node; # we already have this # check for sane parameters next if $ver < 5000; # only works with version 5 software next if length $call < 3; # min 3 letter callsigns + + # add it to the nodes table and outgoing line + $newline .= "$here^$call^$confmode^$ver^"; DXNode->new($self, $call, $confmode, $here, $ver); # unbusy and stop and outgoing mail (ie if somehow we receive another PC19 without a disconnect) my $mref = DXMsg::get_busy($call); - $mref->stop_msg($self) if $mref; + $mref->stop_msg($call) if $mref; # add this station to the user database, if required (don't remove SSID from nodes) my $user = DXUser->get_current($call); @@ -398,8 +451,11 @@ sub normal $user->put; } - # queue up any messages - DXMsg::queue_msg(0) if $self->state eq 'normal'; + return if $newline eq "PC19^"; + + # add hop count + $newline .= get_hops(19) . "^"; + $line = $newline; last SWITCH; } @@ -407,10 +463,6 @@ sub normal $self->send_local_config(); $self->send(pc22()); $self->state('normal'); - - # queue mail - DXMsg::queue_msg(0); - return; } @@ -420,7 +472,12 @@ sub normal my $node = DXCluster->get_exact($call); if ($node) { if ($node->dxchan != $self) { - dbg('chan', "LOOP: come in on wrong channel"); + dbg('chan', "LOOP: $call come in on wrong channel"); + return; + } + my $dxchan; + if (($dxchan = DXChannel->get($call)) && $dxchan != $self) { + dbg('chan', "LOOP: $call connected locally"); return; } $node->del(); @@ -434,45 +491,53 @@ sub normal if ($pcno == 22) { $self->state('normal'); - - # queue mail - DXMsg::queue_msg(0); return; } - + if ($pcno == 23 || $pcno == 27) { # WWV info + + # route 'foreign' pc27s + if ($pcno == 27) { + if ($field[8] ne $main::mycall) { + $self->route($field[8], $line); + return; + } + } + # do some de-duping my $d = cltounix($field[1], sprintf("%02d18Z", $field[2])); my $sfi = unpad($field[3]); my $k = unpad($field[4]); 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"); return; } - if ($d > $main::systime + 900 || $field[2] < 0 || $field[2] > 23) { + 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"); return; } $wwvdup{$dupkey} = $d; $field[6] =~ s/-\d+$//o; # remove spotter's ssid - my $wwv = Geomag::update($d, $field[2], $sfi, $k, $i, @field[6..$#field]); + my $wwv = Geomag::update($d, $field[2], $sfi, $k, $i, @field[6..8], $r); - my $r; + my $rep; eval { - $r = Local::wwv($self, $field[1], $field[2], $sfi, $k, $i, @field[6..$#field]); + $rep = Local::wwv($self, $field[1], $field[2], $sfi, $k, $i, @field[6..8], $r); }; # dbg('local', "Local::wwv2 error $@") if $@; - return if $r; + return if $rep; # DON'T be silly and send on PC27s! return if $pcno == 27; - # broadcast to the eager users - broadcast_users("WWV de $field[7] <$field[2]>: SFI=$sfi, A=$k, K=$i, $field[6]", 'wwv', $wwv ); - last SWITCH; + # broadcast to the eager world + send_wwv_spot($self, $line, $d, $field[2], $sfi, $k, $i, @field[6..8]); + return; } if ($pcno == 24) { # set here status @@ -484,7 +549,11 @@ sub normal 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) { + dbg('chan', "Trying to merge to myself, ignored"); return; } @@ -492,10 +561,10 @@ sub normal # spots if ($field[3] > 0) { - my @in = reverse Spot::search(1, undef, undef, 0, $field[3]-1); + my @in = reverse Spot::search(1, undef, undef, 0, $field[3]); my $in; foreach $in (@in) { - $self->send(pc26(@{$in}[0..4], $in->[7])); + $self->send(pc26(@{$in}[0..4], $field[2])); } } @@ -504,14 +573,18 @@ sub normal my @in = reverse Geomag::search(0, $field[4], time, 1); my $in; foreach $in (@in) { - $self->send(pc27(@{$in})); + $self->send(pc27(@{$in}[0..5], $field[2])); } } return; } - + if (($pcno >= 28 && $pcno <= 33) || $pcno == 40 || $pcno == 42 || $pcno == 49) { # mail/file handling - DXMsg::process($self, $line); + if ($pcno == 49 || $field[1] eq $main::mycall) { + DXMsg::process($self, $line); + } else { + $self->route($field[1], $line); + } return; } @@ -540,7 +613,7 @@ sub normal $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; } @@ -554,15 +627,13 @@ sub normal delete $rcmds{$field[2]} if !$dxchan; } } else { - route($field[1], $line); + $self->route($field[1], $line); } return; } - if ($pcno == 37) { - last SWITCH; - } - + # for pc 37 see 44 onwards + if ($pcno == 38) { # node connected list from neighbour return; } @@ -599,25 +670,18 @@ sub normal if ($pcno == 43) { last SWITCH; } - if ($pcno == 44) { - last SWITCH; - } - if ($pcno == 45) { - last SWITCH; - } - if ($pcno == 46) { - last SWITCH; - } - if ($pcno == 47) { - last SWITCH; - } - if ($pcno == 48) { - last SWITCH; + if ($pcno == 37 || $pcno == 44 || $pcno == 45 || $pcno == 46 || $pcno == 47) { + DXDb::process($self, $line); + return; } if ($pcno == 50) { # keep alive/user list - my $ref = DXCluster->get_exact($field[1]); - $ref->update_users($field[2]) if $ref; + my $node = DXCluster->get_exact($field[1]); + if ($node) { + return unless $node->isa('DXNode'); + return unless $node->dxchan == $self; + $node->update_users($field[2]); + } last SWITCH; } @@ -632,15 +696,17 @@ 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; + 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; } @@ -654,7 +720,7 @@ sub normal # REBROADCAST!!!! # - if (!$self->{isolate}) { + unless ($self->{isolate}) { broadcast_ak1a($line, $self); # send it to everyone but me } } @@ -677,7 +743,7 @@ sub process if ($t >= $dxchan->pc50_t + $DXProt::pc50_interval) { $dxchan->send(pc50()); $dxchan->pc50_t($t); - } + } } my $key; @@ -711,7 +777,7 @@ sub finish # unbusy and stop and outgoing mail my $mref = DXMsg::get_busy($call); - $mref->stop_msg($self) if $mref; + $mref->stop_msg($call) if $mref; # broadcast to all other nodes that all the nodes connected to via me are gone my @gonenodes = map { $_->dxchan == $self ? $_ : () } DXNode::get_all(); @@ -727,7 +793,7 @@ sub finish delete $pings{$call}; # now broadcast to all other ak1a nodes that I have gone - broadcast_ak1a(pc21($call, 'Gone.'), $self); + broadcast_ak1a(pc21($call, 'Gone.'), $self) unless $self->{isolate}; Log('DXProt', $call . " Disconnected"); $ref->del() if $ref; @@ -747,7 +813,13 @@ sub send_dx_spot # taking into account filtering and so on foreach $dxchan (@dxchan) { my $routeit; - my ($filter, $hops) = Filter::it($dxchan->{spotfilter}, @_, $self->{call} ) if $dxchan->{spotfilter}; + my ($filter, $hops); + + if ($dxchan->{spotfilter}) { + ($filter, $hops) = Filter::it($dxchan->{spotfilter}, @_, $self->{call} ); + next unless $filter; + } + if ($dxchan->is_ak1a) { next if $dxchan == $self; if ($hops) { @@ -761,15 +833,122 @@ sub send_dx_spot $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); + } + } + } +} + +sub send_wwv_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->{spotfilter}) { + ($filter, $hops) = Filter::it($dxchan->{wwvfilter}, @_, $self->{call} ); + next unless $filter; + } + if ($dxchan->is_ak1a) { + 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->{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') { + $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); } } } @@ -823,9 +1002,13 @@ sub send_local_config # 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) { @@ -964,7 +1147,7 @@ sub get_all_user_calls sub get_hops { - my ($pcno) = @_; + my $pcno = shift; my $hops = $DXProt::hopcount{$pcno}; $hops = $DXProt::def_hopcount if !$hops; return "H$hops"; @@ -1032,7 +1215,7 @@ sub addping 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; } @@ -1044,7 +1227,7 @@ sub addrcmd $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;