From: minima Date: Sat, 3 Jan 2004 00:18:27 +0000 (+0000) Subject: add more code gradually X-Git-Url: http://dxcluster.net/gitweb/gitweb.cgi?a=commitdiff_plain;h=refs%2Fheads%2Fspider2;p=spider.git add more code gradually --- diff --git a/perl/DXCommandmode.pm b/perl/DXCommandmode.pm index 64bff8e6..51612254 100644 --- a/perl/DXCommandmode.pm +++ b/perl/DXCommandmode.pm @@ -34,6 +34,7 @@ use Script; use Net::Telnet; use QSL; use DB_File; +use Thingy; use strict; use vars qw(%Cache %cmd_cache $errstr %aliases $scriptbase $maxerrors %nothereslug $maxbadcount); diff --git a/perl/DXProt.pm b/perl/DXProt.pm index db5bfabe..03405a08 100644 --- a/perl/DXProt.pm +++ b/perl/DXProt.pm @@ -33,6 +33,7 @@ use DXHash; use Route; use Route::Node; use Script; +use Thingy; use strict; @@ -301,27 +302,12 @@ sub sendinit $self->send(pc18()); } -sub removepc90 -{ - $_[0] =~ s/^PC90\^[-A-Z0-9]+\^\d+\^//; -} - -sub removepc91 -{ - $_[0] =~ s/^PC91\^[-A-Z0-9]+\^\d+\^[-A-Z0-9]+\^//; -} sub send { my $self = shift; while (@_) { my $line = shift; - if ($self->user->wantpc90) { - $line = mungepc90($line); - } else { - removepc91($line); - removepc90($line); - } $self->SUPER::send($line); } } @@ -684,9 +670,7 @@ sub handle_16 } # general checks - my $dxchan; my $ncall = $_[1]; - my $newline = "PC16^"; # do I want users from this channel? unless ($self->user->wantpc16) { @@ -698,120 +682,27 @@ sub handle_16 dbg("PCPROT: trying to alter config on this node from outside!") if isdbg('chanerr'); return; } - my $parent = Route::Node::get($ncall); - - # if there is a parent, proceed, otherwise if there is a latent PC19 in the PC19list, - # fix it up in the routing tables and issue it forth before the PC16 - unless ($parent) { - my $nl = $pc19list{$ncall}; - - if ($nl && @_ > 3) { # 3 because of the hop count! - - # this is a new (remembered) node, now attach it to me if it isn't in filtered - # and we haven't disallowed it - my $user = DXUser->get_current($ncall); - if (!$user) { - $user = DXUser->new($ncall); - $user->sort('A'); - $user->priv(1); # I have relented and defaulted nodes - $user->lockout(1); - $user->homenode($ncall); - $user->node($ncall); - } - my $wantpc19 = $user->wantroutepc19; - if ($wantpc19 || !defined $wantpc19) { - my $new = Route->new($ncall); # throw away - if ($self->in_filter_route($new)) { - my @nrout; - for (@$nl) { - $parent = Route::Node::get($_->[0]); - $dxchan = $parent->dxchan if $parent; - if ($dxchan && $dxchan ne $self) { - dbg("PCPROT: PC19 from $self->{call} trying to alter locally connected $ncall, ignored!") if isdbg('chanerr'); - $parent = undef; - } - if ($parent) { - my $r = $parent->add($ncall, $_->[1], $_->[2]); - push @nrout, $r unless @nrout; - } - } - $user->wantroutepc19(1) unless defined $wantpc19; # for now we work on the basis that pc16 = real route - $user->lastin($main::systime) unless DXChannel->get($ncall); - $user->put; - - # route the pc19 - this will cause 'stuttering PC19s' for a while - $self->route_pc19($origin, $line, @nrout) if @nrout ; - $parent = Route::Node::get($ncall); - unless ($parent) { - dbg("PCPROT: lost $ncall after sending PC19 for it?"); - return; - } - } else { - return; - } - delete $pc19list{$ncall}; - } - } else { - dbg("PCPROT: Node $ncall not in config") if isdbg('chanerr'); - return; + # is it connected directly to me? + if ($ncall eq $self->{call}) { + my @users; + for (my $i = 2; $i < $#_; $i++) { + my ($call, $conf, $here) = $_[$i] =~ /^(\S+) (\S) (\d)/o; + next unless $call && $conf && defined $here && is_callsign($call); + next if $call eq $main::mycall; + push @users, "$here$call"; } - } else { - - $dxchan = $parent->dxchan; - if ($dxchan && $dxchan ne $self) { - dbg("PCPROT: PC16 from $self->{call} trying to alter locally connected $ncall, ignored!") if isdbg('chanerr'); - return; - } - - # input filter if required - return unless $self->in_filter_route($parent); - } - my $i; - my @rout; - for ($i = 2; $i < $#_; $i++) { - my ($call, $conf, $here) = $_[$i] =~ /^(\S+) (\S) (\d)/o; - next unless $call && $conf && defined $here && is_callsign($call); - next if $call eq $main::mycall; - - eph_del_regex("^PC17\\^$call\\^$ncall"); - - $conf = $conf eq '*'; - - # reject this if we think it is a node already - my $r = Route::Node::get($call); - my $u = DXUser->get_current($call) unless $r; - if ($r || ($u && $u->is_node)) { - dbg("PCPROT: $call is a node") if isdbg('chanerr'); - next; - } - - $r = Route::User::get($call); - my $flags = Route::here($here)|Route::conf($conf); - - if ($r) { - my $au = $r->addparent($parent); - if ($r->flags != $flags) { - $r->flags($flags); - $au = $r; - } - push @rout, $r if $au; + if (@users) { + my $t = Thingy::Route->new_user_connection($ncall, $ncall, @users); + $t->{_pcline} = [$line]; + $t->queue; } else { - push @rout, $parent->add_user($call, $flags); + dbg("PCPROT: no valid users, dropped") if isdbg('chanerr'); } - - - # add this station to the user database, if required - $call =~ s/-\d+$//o; # remove ssid for users - my $user = DXUser->get_current($call); - $user = DXUser->new($call) if !$user; - $user->homenode($parent->call) if !$user->homenode; - $user->node($parent->call); - $user->lastin($main::systime) unless DXChannel->get($call); - $user->put; + } else { + dbg("PCPROT: non-local PC16, dropped") if isdbg('chanerr'); } - $self->route_pc16($origin, $line, $parent, @rout) if @rout; } # remove a user @@ -832,39 +723,21 @@ sub handle_17 dbg("PCPROT: don't send users to $self->{call}") if isdbg('chanerr'); return; } + + # ignore PC17 addressed from me if ($ncall eq $main::mycall) { dbg("PCPROT: trying to alter config on this node from outside!") 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 ($dxchan && $dxchan ne $self) { - dbg("PCPROT: PC17 from $self->{call} trying to alter locally connected $ncall, ignored!") if isdbg('chanerr'); - return; - } - - # input filter if required - return unless $self->in_filter_route($parent); - - $parent->del_user($uref); - - if (eph_dup($line)) { - dbg("PCPROT: dup PC17 detected") if isdbg('chanerr'); - return; + # is it connected directly to me? + if ($ncall eq $self->{call}) { + my $t = Thingy::Route->new_user_disconnection($ncall, $ncall, $ucall); + $t->{_pcline} = [$line]; + $t->queue; + } else { + dbg("PCPROT: non-local PC17, dropped") if isdbg('chanerr'); } - - $self->route_pc17($origin, $line, $parent, $uref); } # link request @@ -878,27 +751,32 @@ sub handle_18 # record the type and version offered if ($_[1] =~ /DXSpider Version: (\d+\.\d+) Build: (\d+\.\d+)/) { - $self->version(53 + $1); - $self->user->version(53 + $1); - $self->build(0 + $2); - $self->user->build(0 + $2); + $self->version($1); + $self->user->version($1); + $self->build($2); + $self->user->build($2); unless ($self->is_spider) { $self->user->sort('S'); $self->user->put; $self->sort('S'); } } else { - $self->version(50.0); - $self->version($_[2] / 100) if $_[2] && $_[2] =~ /^\d+$/; + $self->version(0.5000); + $self->version("0.$_[2]") if $_[2] && $_[2] =~ /^\d+$/; $self->user->version($self->version); } - # first clear out any nodes on this dxchannel - my $parent = Route::Node::get($self->{call}); - my @rout = $parent->del_nodes; - $self->route_pc21($origin, $line, @rout, $parent) if @rout; - $self->send_local_config(); - $self->send(pc20()); + if ($self->version >= 2.0 && $self->version < 5) { + $self = bless $self, 'QXProt' unless $self->isa('QXProt'); + $self->sendinit; + } else { + # first clear out any nodes on this dxchannel + my $parent = Route::Node::get($self->{call}); + my @rout = $parent->del_nodes; + $self->route_pc21($origin, $line, @rout, $parent) if @rout; + $self->send_local_config(); + $self->send(pc20()); + } } # incoming cluster list @@ -909,48 +787,13 @@ sub handle_19 my $line = shift; my $origin = shift; - my $i; - my $newline = "PC19^"; - if (eph_dup($line)) { dbg("PCPROT: dup PC19 detected") if isdbg('chanerr'); return; } - # new routing list - my @rout; - - # first get the INTERFACE node - my $parent = Route::Node::get($self->{call}); - unless ($parent) { - dbg("DXPROT: my parent $self->{call} has disappeared"); - $self->disconnect; - return; - } - - # if the origin isn't the same as the INTERFACE, then reparent, creating nodes as necessary - if ($origin ne $self->call) { - my $op = Route::Node::get($origin); - unless ($op) { - $op = $parent->add($origin, 5000, Route::here(1)); - my $user = DXUser->get_current($origin); - if (!$user) { - $user = DXUser->new($origin); - $user->sort('S'); - $user->priv(1); # I have relented and defaulted nodes - $user->lockout(1); - $user->homenode($origin); - $user->node($origin); - $user->wantroutepc19(1); - $user->wantpc90(1); - } - $user->put; - } - $parent = $op; - } - # parse the PC19 - for ($i = 1; $i < $#_-1; $i += 4) { + for (my $i = 1; $i < $#_-1; $i += 4) { my $here = $_[$i]; my $call = uc $_[$i+1]; my $conf = $_[$i+2]; @@ -960,77 +803,16 @@ sub handle_19 eph_del_regex("^PC(?:21\\^$call|17\\^[^\\^]+\\^$call)"); # check for sane parameters - # $ver = 5000 if $ver eq '0000'; next if $ver < 5000; # only works with version 5 software - next if length $call < 3; # min 3 letter callsigns next if $call eq $main::mycall; - # check that this PC19 isn't trying to alter the wrong dxchan - 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 ($call eq $self->{call}) { + my $t = Thingy::Route->new_node_connection($main::mycall, $call, "$here$call"); + $t->{v} = $ver; + $t->queue; + last; } - - # add this station to the user database, if required (don't remove SSID from nodes) - my $user = DXUser->get_current($call); - if (!$user) { - $user = DXUser->new($call); - $user->sort('A'); - $user->priv(1); # I have relented and defaulted nodes - $user->lockout(1); - $user->homenode($call); - $user->node($call); - } - - my $r = Route::Node::get($call); - my $flags = Route::here($here)|Route::conf($conf); - - # modify the routing table if it is in it, otherwise store it in the pc19list for now - if ($r) { - my $ar; - if ($call ne $parent->call) { - if ($self->in_filter_route($r)) { - $ar = $parent->add($call, $ver, $flags); - push @rout, $ar if $ar; - } else { - next; - } - } - if ($r->version ne $ver || $r->flags != $flags) { - $r->version($ver); - $r->flags($flags); - push @rout, $r unless $ar; - } - } else { - - # if he is directly connected or allowed then add him, otherwise store him up for later - if ($call eq $self->{call} || $user->wantroutepc19) { - my $new = Route->new($call); # throw away - if ($self->in_filter_route($new)) { - my $ar = $parent->add($call, $ver, $flags); - $user->wantroutepc19(1) unless defined $user->wantroutepc19; - push @rout, $ar if $ar; - } else { - next; - } - } else { - $pc19list{$call} = [] unless exists $pc19list{$call}; - my $nl = $pc19list{$call}; - push @{$pc19list{$call}}, [$self->{call}, $ver, $flags] unless grep $_->[0] eq $self->{call}, @$nl; - } - } - - # 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($call) if $mref; - - $user->lastin($main::systime) unless DXChannel->get($call); - $user->put; } - - - $self->route_pc19($origin, $line, @rout) if @rout; } # send local configuration @@ -1063,44 +845,6 @@ sub handle_21 $self->disconnect(1); return; } - - # check to see if we are in the pc19list, if we are then don't bother with any of - # this routing table manipulation, just remove it from the list and dump it - my @rout; - if (my $nl = $pc19list{$call}) { - $pc19list{$call} = [ grep {$_->[0] ne $self->{call}} @$nl ]; - delete $pc19list{$call} unless @{$pc19list{$call}}; - } else { - - my $parent = Route::Node::get($self->{call}); - unless ($parent) { - dbg("DXPROT: my parent $self->{call} has disappeared"); - $self->disconnect; - return; - } - if ($call ne $main::mycall) { # don't allow malicious buggers to disconnect me! - my $node = Route::Node::get($call); - if ($node) { - - 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; - } - - # input filter it - return unless $self->in_filter_route($node); - - # routing objects - push @rout, $node->del($parent); - } - } else { - dbg("PCPROT: I WILL _NOT_ be disconnected!") if isdbg('chanerr'); - return; - } - } - - $self->route_pc21($origin, $line, @rout) if @rout; } @@ -1492,7 +1236,7 @@ sub handle_51 } } } else { - if ($line !~ /^PC90/ && eph_dup($line)) { + if (eph_dup($line)) { dbg("PCPROT: dup PC51 detected") if isdbg('chanerr'); return; } @@ -1992,31 +1736,19 @@ sub send_local_config $self->send_route($main::mycall, \&pc19, scalar(@localnodes)+1, $main::routeroot, @localnodes); my $node; - if ($self->user->wantpc90) { - for $node (@localnodes) { - my @nodes = map {my $r = Route::Node::get($_); $r ? $r : ()} $node->nodes; - $self->send_route($node->call, \&pc19, scalar(@nodes)+1, @nodes); - for my $r (@nodes) { - push @remotenodes, $r unless grep $r eq $_, @remotenodes; - } - } - } else { - my @rawintcalls = map { $_->nodes } @localnodes if @localnodes; - my @intcalls; - for $node (@rawintcalls) { - push @intcalls, $node unless grep $node eq $_, @intcalls; - } - my $ref = Route::Node::get($self->{call}); - my @rnodes = $ref->nodes; - for $node (@intcalls) { - push @remotenodes, Route::Node::get($node) unless grep $node eq $_, @rnodes, @remotenodes; - } - $self->send_route($main::mycall, \&pc19, scalar(@remotenodes), @remotenodes); + my @rawintcalls = map { $_->nodes } @localnodes if @localnodes; + my @intcalls; + for $node (@rawintcalls) { + push @intcalls, $node unless grep $node eq $_, @intcalls; } + my $ref = Route::Node::get($self->{call}); + my @rnodes = $ref->nodes; + for $node (@intcalls) { + push @remotenodes, Route::Node::get($node) unless grep $node eq $_, @rnodes, @remotenodes; + } + $self->send_route($main::mycall, \&pc19, scalar(@remotenodes), @remotenodes); } - - # get all the users connected on the above nodes and send them out foreach $node ($main::routeroot, @localnodes, @remotenodes) { if ($node) { @@ -2349,7 +2081,6 @@ sub send_route next unless $routeit; } - $routeit = mungepc91($origin, $routeit) if $self->user->wantpc90; $self->send($routeit); } } @@ -2371,11 +2102,7 @@ sub broadcast_route next unless $dxchan->isa('DXProt'); next if ($generate == \&pc16 || $generate==\&pc17) && !$dxchan->user->wantsendpc16; - if ($self->user->wantpc90 && $line) { - $dxchan->send(mungepc91($origin, $line)); - } else { - $dxchan->send_route($origin, $generate, @_); - } + $dxchan->send_route($origin, $generate, @_); } } } @@ -2459,7 +2186,6 @@ sub eph_dup # chop the end off $s =~ s/\^H\d\d?\^?\~?$//; - removepc90($s); $r = 1 if exists $eph{$s}; # pump up the dup if it keeps circulating $eph{$s} = $main::systime + $t; return $r; diff --git a/perl/QXProt.pm b/perl/QXProt.pm index ccf7c83d..689432d0 100644 --- a/perl/QXProt.pm +++ b/perl/QXProt.pm @@ -68,8 +68,7 @@ sub sendinit { my $self = shift; - my $t = Thingy::Route->new_node_connect($main::mycall, $main::mycall, nextmsgid(), $self->{call}); - $t->add; + $self->node_update; } sub normal @@ -84,7 +83,7 @@ sub normal # return unless my ($tonode, $fromnode, $class, $msgid, $hoptime, $rest) = - $_[1] =~ /^([^,]+,){5,5}:(.*)$/; + $_[1] =~ /^([^;]+;){5,5}\|(.*)$/; my $self = shift; @@ -96,14 +95,22 @@ sub normal # and create a new thingy based on the class passed (if known) # ignore pairs with a leading '_'. - my @par = map {/^_/ ? split(/=/,$_,2) : ()} split /,/, $rest; + my @par; + + for (split /;/, $rest) { + next if /^_/; + next unless /^\w+=/; + s/\%([0-9A-F][0-9A-F])/chr(hex($1))/eg; + push @par, split(/=/,$_,2); + } + no strict 'refs'; my $pkg = 'Thingy::' . lcfirst $class; my $t = $pkg->new(_tonode=>$tonode, _fromnode=>$fromnode, _msgid=>$msgid, _hoptime=>$newhoptime, _newdata=>$rest, _inon=>$self->{call}, @par) if defined *$pkg && $pkg->can('new'); - $t->add if $t; + $t->queue if $t; return; } @@ -120,8 +127,8 @@ sub process sub disconnect { my $self = shift; - my $t = Thingy::Route->new_node_disconnect($main::mycall, $main::mycall, nextmsgid(), $self->{call}); - $t->add; + my $t = Thingy::Route->new_node_disconnect($main::mycall, $main::mycall, $self->{call}); + $t->queue; $self->DXProt::disconnect(@_); } @@ -136,9 +143,48 @@ sub nextmsgid sub node_update { - my $t = Thingy::Route->new_node_update(nextmsgid()); - $t->add if $t; + my $t = Thingy::Route->new_node_update(); + $t->queue if $t; } +sub t_send +{ + my $self = shift; + my $t = shift; + confess('$t is not a Thingy') unless $t->isa('Thingy'); + + # manufacture the protocol line if required + unless (exists $t->{_newprot}) { + my ($class) = ref $self =~ /::(\w+)$/; + unless (exists $t->{_rest}) { + $t->{_rest} = ""; + while (my ($k,$v) = each %$t) { + next if $k =~ /^_/; + if (ref $v && @$v) { + my $val = ""; + for(@$v) { + my $vv = $_; + $vv =~ s/([\%;=,\x00-\x1f\x7f-\xff])/sprintf("%%%02X", ord($1))/eg; + $val .= $vv . ','; + } + if (length $val) { + chop $val; + $t->{_rest} .= "$k=$val;"; + } + } elsif (length $v) { + $v =~ s/([\%;=\x00-\x1f\x7f-\xff])/sprintf("%%%02X", ord($1))/eg; + $t->{_rest} .= "$k=$v;"; + } + } + chop $t->{_rest} if length $t->{_rest}; + } + + $t->{_hoptime} ||= 1; + $t->{_msgid} = nextmsgid() unless $t->{_msgid}; + $t->{_newprot} = join(';', $t->{_tonode}, $t->{_fromnode}, uc $class, + $t->{_msgid}, $t->{_hoptime}) . '|' . $t->{_rest}; + } + $self->SUPER::send($t->{_newprot}); +} 1; diff --git a/perl/Route.pm b/perl/Route.pm index 68b71eb6..ed0d7e76 100644 --- a/perl/Route.pm +++ b/perl/Route.pm @@ -37,6 +37,7 @@ use vars qw(%list %valid $filterdef); cq => '0,CQ Zone', state => '0,State', city => '0,City', + lastupdate => '0,Last Update,cldatetime', ); $filterdef = bless ([ diff --git a/perl/Route/Node.pm b/perl/Route/Node.pm index d9395ec8..96abc941 100644 --- a/perl/Route/Node.pm +++ b/perl/Route/Node.pm @@ -29,6 +29,8 @@ use vars qw(%list %valid @ISA $max $filterdef); users => '0,Users,parray', usercount => '0,User Count', version => '0,Version', + build => '0,Build', + software => '0,Software', np => '0,Using New Prot,yesno', lid => '0,Last Msgid', ); diff --git a/perl/Thingy.pm b/perl/Thingy.pm index 7ae3d8f4..785428cf 100644 --- a/perl/Thingy.pm +++ b/perl/Thingy.pm @@ -22,6 +22,7 @@ $main::branch += $BRANCH; use DXChannel; use DXDebug; +use Thingy::Hi; use Thingy::Route; use vars qw(@queue); @@ -38,7 +39,6 @@ sub new bless $self, $class; $self->{_tonode} ||= '*'; $self->{_fromnode} ||= $main::mycall; - $self->{_hoptime} ||= 0; while (my ($k,$v) = each %$self) { delete $self->{$k} unless defined $v; } @@ -46,7 +46,7 @@ sub new } # add the Thingy to the queue -sub add +sub queue { push @queue, shift; } @@ -59,7 +59,7 @@ sub process if ($t) { # go directly to this class's t= handler if there is one - my $type = $t->{t}; + my $type = lc $t->{t}; if ($type) { # remove extraneous characters put there by the ungodly $type =~ s/[^\w]//g; diff --git a/perl/Thingy/Hi.pm b/perl/Thingy/Hi.pm new file mode 100644 index 00000000..f274d6c8 --- /dev/null +++ b/perl/Thingy/Hi.pm @@ -0,0 +1,53 @@ +# +# Generate Hi (Hello) Thingies +# +# $Id$ +# +# Copyright (c) 2004 Dirk Koopman G1TLH +# + +package Thingy::Hi; + +use strict; + +use vars qw($VERSION $BRANCH); +$VERSION = sprintf( "%d.%03d", q$Revision$ =~ /(\d+)\.(\d+)/ ); +$BRANCH = sprintf( "%d.%03d", q$Revision$ =~ /\d+\.\d+\.(\d+)\.(\d+)/,(0,0)); +$main::build += $VERSION; +$main::branch += $BRANCH; + +use vars qw(@ISA); + +@ISA = qw(Thingy); + +# this is my version of a PC18 +sub new +{ + my $pkg = shift; + my $tonode = shift; + my $t = $pkg->SUPER::new( _tonode=>$tonode, + id=>'DXSpider', v=>$main::version, b=>$main::build); + return $t; +} + +sub normal +{ + my $t = shift; + my $dxchan = DXChannel->get($t->{_fromnode}); + my $r = Route::Node::get($t->{_fromnode}) || Route::Node->new($t->{_fromnode}); + $r->version($t->{v}); + $r->build($t->{b}); + $r->software($t->{id}); + $r->np(1); + $r->lid($t->{_msgid}); + $r->lastupdate($main::systime); + + if ($dxchan->state eq 'init') { + my $ot = Thingy::Hi->new($t->{_fromnode}); + $dxchan->t_send($ot); + $dxchan->state('normal'); + } +} + +1; + diff --git a/perl/Thingy/Route.pm b/perl/Thingy/Route.pm index 514d50e8..01587181 100644 --- a/perl/Thingy/Route.pm +++ b/perl/Thingy/Route.pm @@ -26,10 +26,10 @@ sub new_node_connect my $pkg = shift; my $fromnode = shift; my $inon = shift; - my $msgid = shift; - my $t = $pkg->SUPER::new(_fromnode=>$fromnode, _msgid=>$msgid, + my @n = map {uc} @_; + my $t = $pkg->SUPER::new(_fromnode=>$fromnode, _inon=>$inon, - t=>'nc', n=>join('|', @_)); + id=>'DXSpider', v=>$main::version, b=>$main::build, t=>'nc', n=>\@n); return $t; } @@ -39,10 +39,10 @@ sub new_node_disconnect my $pkg = shift; my $fromnode = shift; my $inon = shift; - my $msgid = shift; - my $t = $pkg->SUPER::new(_fromnode=>$fromnode, _msgid=>$msgid, + my @n = map {uc} @_; + my $t = $pkg->SUPER::new(_fromnode=>$fromnode, _inon=>$inon, - t=>'nd', n=>join('|', @_)); + t=>'nd', n=>\@n); return $t; } @@ -50,14 +50,37 @@ sub new_node_disconnect sub new_node_update { my $pkg = shift; - my $msgid = shift; my @nodes = grep {$_ ne $main::mycall} DXChannel::get_all_node_calls(); my @users = DXChannel::get_all_user_calls(); - my $t = $pkg->SUPER::new(_msgid=>$msgid, t=>'nu', - id=>"DXSpider $main::version $main::build", - n=>join('|', @nodes), u=>join('|', @users)); + my $t = $pkg->SUPER::new(t=>'nu', + id=>'DXSpider', v=>$main::version, b=>$main::build, + n=>\@nodes, u=>\@users); + return $t; +} + +sub new_user_connect +{ + my $pkg = shift; + my $fromnode = shift; + my $inon = shift; + my @u = map {uc} @_; + my $t = $pkg->SUPER::new(_fromnode=>$fromnode, + _inon=>$inon, + t=>'uc', u=>\@u); + return $t; +} + +sub new_user_discconnect +{ + my $pkg = shift; + my $fromnode = shift; + my $inon = shift; + my @u = map {uc} @_; + my $t = $pkg->SUPER::new(_fromnode=>$fromnode, + _inon=>$inon, + t=>'ud', u=>\@u); return $t; } @@ -65,3 +88,260 @@ sub normal { } + +# node update (this will completely rewrite the node's info) +sub handle_nu +{ + my $t = shift; + +} + +# node connection +sub handle_nc +{ + my $t = shift; + + my @rout; + + # first get the fromnode + my $dxchan = DXChannel->get($t->{_inon}) || return; + my $parent = Route::Node::get($t->{_fromnode}); + + unless ($parent) { + push @rout, $parent = Route::Node->new($t->{_fromnode}); + } + + for (@{$t->{n}) { + my ($here, $call) = unpack "AA*", $_; + + # if it is a new node add it to the user database + my $user = DXUser->get_current($call); + unless ($user) { + $user = DXUser->new($call); + $user->sort('A'); + $user->priv(1); # I have relented and defaulted nodes + $user->lockout(1); + $user->homenode($call); + $user->node($call); + } + + # add each of the nodes to this parent + + } + # add this station to the user database, if required (don't remove SSID from nodes) + + my $r = Route::Node::get($call); + my $flags = Route::here($here)|Route::conf($conf); + + # modify the routing table if it is in it, otherwise store it in the pc19list for now + if ($r) { + my $ar; + if ($call ne $parent->call) { + if ($self->in_filter_route($r)) { + $ar = $parent->add($call, $ver, $flags); + push @rout, $ar if $ar; + } else { + next; + } + } + if ($r->version ne $ver || $r->flags != $flags) { + $r->version($ver); + $r->flags($flags); + push @rout, $r unless $ar; + } + } else { + + # if he is directly connected or allowed then add him, otherwise store him up for later + if ($call eq $self->{call} || $user->wantroutepc19) { + my $new = Route->new($call); # throw away + if ($self->in_filter_route($new)) { + my $ar = $parent->add($call, $ver, $flags); + $user->wantroutepc19(1) unless defined $user->wantroutepc19; + push @rout, $ar if $ar; + } else { + next; + } + } else { + $pc19list{$call} = [] unless exists $pc19list{$call}; + my $nl = $pc19list{$call}; + push @{$pc19list{$call}}, [$self->{call}, $ver, $flags] unless grep $_->[0] eq $self->{call}, @$nl; + } + } + + # 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($call) if $mref; + + $user->lastin($main::systime) unless DXChannel->get($call); + $user->put; + } + + + $self->route_pc19($origin, $line, @rout) if @rout; + +} + +# node disconnection +sub handle_nd +{ + my $t = shift; + +} + +# user connection +sub handle_uc +{ + my $t = shift; + + my $newline = "PC16^"; + my $parent = Route::Node::get($t->{_fromnode}); + + # if there is a parent, proceed, otherwise if there is a latent PC19 in the PC19list, + # fix it up in the routing tables and issue it forth before the PC16 + unless ($parent) { + my $nl = $pc19list{$ncall}; + + if ($nl && @_ > 3) { # 3 because of the hop count! + + # this is a new (remembered) node, now attach it to me if it isn't in filtered + # and we haven't disallowed it + my $user = DXUser->get_current($ncall); + if (!$user) { + $user = DXUser->new($ncall); + $user->sort('A'); + $user->priv(1); # I have relented and defaulted nodes + $user->lockout(1); + $user->homenode($ncall); + $user->node($ncall); + } + + my $wantpc19 = $user->wantroutepc19; + if ($wantpc19 || !defined $wantpc19) { + my $new = Route->new($ncall); # throw away + if ($self->in_filter_route($new)) { + my @nrout; + for (@$nl) { + $parent = Route::Node::get($_->[0]); + $dxchan = $parent->dxchan if $parent; + if ($dxchan && $dxchan ne $self) { + dbg("PCPROT: PC19 from $self->{call} trying to alter locally connected $ncall, ignored!") if isdbg('chanerr'); + $parent = undef; + } + if ($parent) { + my $r = $parent->add($ncall, $_->[1], $_->[2]); + push @nrout, $r unless @nrout; + } + } + $user->wantroutepc19(1) unless defined $wantpc19; # for now we work on the basis that pc16 = real route + $user->lastin($main::systime) unless DXChannel->get($ncall); + $user->put; + + # route the pc19 - this will cause 'stuttering PC19s' for a while + $self->route_pc19($origin, $line, @nrout) if @nrout ; + $parent = Route::Node::get($ncall); + unless ($parent) { + dbg("PCPROT: lost $ncall after sending PC19 for it?"); + return; + } + } else { + return; + } + delete $pc19list{$ncall}; + } + } else { + dbg("PCPROT: Node $ncall not in config") if isdbg('chanerr'); + return; + } + } else { + + $dxchan = $parent->dxchan; + if ($dxchan && $dxchan ne $self) { + dbg("PCPROT: PC16 from $self->{call} trying to alter locally connected $ncall, ignored!") if isdbg('chanerr'); + return; + } + + # input filter if required + return unless $self->in_filter_route($parent); + } + + my $i; + my @rout; + for ($i = 2; $i < $#_; $i++) { + my ($call, $conf, $here) = $_[$i] =~ /^(\S+) (\S) (\d)/o; + next unless $call && $conf && defined $here && is_callsign($call); + next if $call eq $main::mycall; + + eph_del_regex("^PC17\\^$call\\^$ncall"); + + $conf = $conf eq '*'; + + # reject this if we think it is a node already + my $r = Route::Node::get($call); + my $u = DXUser->get_current($call) unless $r; + if ($r || ($u && $u->is_node)) { + dbg("PCPROT: $call is a node") if isdbg('chanerr'); + next; + } + + $r = Route::User::get($call); + my $flags = Route::here($here)|Route::conf($conf); + + if ($r) { + my $au = $r->addparent($parent); + if ($r->flags != $flags) { + $r->flags($flags); + $au = $r; + } + push @rout, $r if $au; + } else { + push @rout, $parent->add_user($call, $flags); + } + + + # add this station to the user database, if required + $call =~ s/-\d+$//o; # remove ssid for users + my $user = DXUser->get_current($call); + $user = DXUser->new($call) if !$user; + $user->homenode($parent->call) if !$user->homenode; + $user->node($parent->call); + $user->lastin($main::systime) unless DXChannel->get($call); + $user->put; + } + $self->route_pc16($origin, $line, $parent, @rout) if @rout; +} + +# user disconnection +sub handle_ud +{ + my $t = shift; + + 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 ($dxchan && $dxchan ne $self) { + dbg("PCPROT: PC17 from $self->{call} trying to alter locally connected $ncall, ignored!") if isdbg('chanerr'); + return; + } + + # input filter if required + return unless $self->in_filter_route($parent); + + $parent->del_user($uref); + + if (eph_dup($line)) { + dbg("PCPROT: dup PC17 detected") if isdbg('chanerr'); + return; + } + + $self->route_pc17($origin, $line, $parent, $uref); + +} diff --git a/perl/cluster.pl b/perl/cluster.pl index 01d2809e..59a03030 100755 --- a/perl/cluster.pl +++ b/perl/cluster.pl @@ -502,7 +502,7 @@ DXProt->init(); QXProt->init(); # put in a DXCluster node for us here so we can add users and take them away -$routeroot = Route::Node->new($mycall, $version*100+5300, Route::here($main::me->here)|Route::conf($main::me->conf)); +$routeroot = Route::Node->new($mycall, $version*100+5251, Route::here($main::me->here)|Route::conf($main::me->conf)); # make sure that there is a routing OUTPUT node default file #unless (Filter::read_in('route', 'node_default', 0)) {