From dab9e3607e7a6592fc3e316cc83ab17fcd09cb61 Mon Sep 17 00:00:00 2001
From: minima <minima>
Date: Fri, 15 Dec 2006 13:19:20 +0000
Subject: [PATCH] chop out all the external linking and add prototype pc92
 sentence.

---
 perl/DXChannel.pm |   2 +
 perl/DXProt.pm    | 301 +++++++++++++++++++---------------------------
 perl/DXProtout.pm |  61 +++++++++-
 3 files changed, 183 insertions(+), 181 deletions(-)

diff --git a/perl/DXChannel.pm b/perl/DXChannel.pm
index b8824cf4..bf419cec 100644
--- a/perl/DXChannel.pm
+++ b/perl/DXChannel.pm
@@ -119,6 +119,8 @@ $count = 0;
 		  lastmsgpoll => '0,Last Msg Poll,atime',
 		  inscript => '9,In a script,yesno',
 		  handle_xml => '9,Handles XML,yesno',
+		  do_pc92 => '9,Handles PC92,yesno',
+		  send_pc92 => '9,Send PC92,atime',
 		  inqueue => '9,Input Queue,parray',
 		 );
 
diff --git a/perl/DXProt.pm b/perl/DXProt.pm
index b1631628..30f03b7e 100644
--- a/perl/DXProt.pm
+++ b/perl/DXProt.pm
@@ -724,83 +724,23 @@ sub handle_16
 		return;
 	}
 
-	RouteDB::update($ncall, $self->{call});
+	my $h;
+	$h = 1 if DXChannel::get($ncall);
+	RouteDB::update($ncall, $self->{call}, $h);
 
-	# do we believe this call? 
-	unless ($ncall eq $self->{call} || $self->is_believed($ncall)) {
-		if (my $ivp = Investigate::get($ncall, $self->{call})) {
-			$ivp->store_pcxx($pcno,$line,$origin,@_);
-		} else {
-			dbg("PCPROT: We don't believe $ncall on $self->{call}") if isdbg('chanerr');
-		}
+	if (eph_dup($line)) {
+		dbg("PCPROT: dup PC16 detected") if isdbg('chanerr');
 		return;
 	}
 
-	if (eph_dup($line)) {
-		dbg("PCPROT: dup PC16 detected") if isdbg('chanerr');
+	unless ($h) {
+		dbg("PCPROT: non-local PC16, ignored") 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;
-		}
-	} else {
-				
+	if ($parent) {
 		$dxchan = $parent->dxchan;
 		if ($dxchan && $dxchan ne $self) {
 			dbg("PCPROT: PC16 from $self->{call} trying to alter locally connected $ncall, ignored!") if isdbg('chanerr');
@@ -858,6 +798,7 @@ sub handle_16
 		$user->put;
 	}
 	$self->route_pc16($origin, $line, $parent, @rout) if @rout;
+	
 }
 		
 # remove a user
@@ -885,13 +826,8 @@ sub handle_17
 
 	RouteDB::delete($ncall, $self->{call});
 
-	# do we believe this call? 
-	unless ($ncall eq $self->{call} || $self->is_believed($ncall)) {
-		if (my $ivp = Investigate::get($ncall, $self->{call})) {
-			$ivp->store_pcxx($pcno,$line,$origin,@_);
-		} else {
-			dbg("PCPROT: We don't believe $ncall on $self->{call}") if isdbg('chanerr');
-		}
+	unless ($ncall eq $self->{call}) {
+		dbg("PCPROT: PC17 from non-local $ncall, ignored") if isdbg('chanerr');
 		return;
 	}
 
@@ -952,6 +888,7 @@ sub handle_18
 			$self->sort('S');
 		}
 		$self->{handle_xml}++ if DXXml::available() && $_[1] =~ /\bxml\b/;
+		$self->{do_pc92}++ if $_[1] =~ /\bpc92\b/;
 	} else {
 		$self->version(50.0);
 		$self->version($_[2] / 100) if $_[2] && $_[2] =~ /^\d+$/;
@@ -988,27 +925,17 @@ sub handle_19
 		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->priv(1);		# I have relented and defaulted nodes
-				$user->lockout(1);
-				$user->homenode($origin);
-				$user->node($origin);
-				$user->wantroutepc19(1);
-			}
-			$user->sort('A') unless $user->is_node;
-			$user->put;
-		}
-		$parent = $op;
-	}
-
 	# parse the PC19
+	# 
+	# We are making a major change from now on. We are only going to accept
+	# PC19s from directly connected nodes.  This means that we are probably
+	# going to throw away most of the data that we are being sent. 
+	#
+	# The justification for this is that most of it is wrong or out of date
+	# anyway. 
+	# 
+	# From now on we are only going to believe PC92 data.
+	#
 	for ($i = 1; $i < $#_-1; $i += 4) {
 		my $here = $_[$i];
 		my $call = uc $_[$i+1];
@@ -1043,26 +970,15 @@ sub handle_19
 		}
 		$user->sort('A') unless $user->is_node;
 
-		RouteDB::update($call, $self->{call});
-
-		# do we believe this call?
-		my $genline = "PC19^$here^$call^$conf^$ver^$_[-1]^"; 
-		unless ($call eq $self->{call} || $self->is_believed($call)) {
-			my $pt = $user->lastping($self->{call}) || 0;
-			if ($pt+$investigation_int < $main::systime && !Investigate::get($call, $self->{call})) {
-				my $ivp  = Investigate->new($call, $self->{call});
-				$ivp->version($ver);
-				$ivp->here($here);
-				$ivp->store_pcxx($pcno,$genline,$origin,'PC19',$here,$call,$conf,$ver,$_[-1]);
-			} else {
-				dbg("PCPROT: We don't believe $call on $self->{call}") if isdbg('chanerr');
-			}
-			$user->put;
-			next;
-		}
+#		if (eph_dup($genline)) {
+#			dbg("PCPROT: dup PC19 for $call detected") if isdbg('chanerr');
+#			next;
+#		}
+
+		RouteDB::update($call, $self->{call}, $dxchan ? 1 : undef);
 
-		if (eph_dup($genline)) {
-			dbg("PCPROT: dup PC19 for $call detected") if isdbg('chanerr');
+		unless ($dxchan) {
+			dbg("PCPROT: PC19 not directly connected, ignored") if isdbg('chanerr');
 			next;
 		}
 
@@ -1075,7 +991,7 @@ sub handle_19
 			if ($call ne $parent->call) {
 				if ($self->in_filter_route($r)) {
 					$ar = $parent->add($call, $ver, $flags);
-					push @rout, $ar if $ar;
+#					push @rout, $ar if $ar;
 				} else {
 					next;
 				}
@@ -1083,11 +999,9 @@ sub handle_19
 			if ($r->version ne $ver || $r->flags != $flags) {
 				$r->version($ver);
 				$r->flags($flags);
-				push @rout, $r unless $ar;
 			}
+			push @rout, $r;
 		} 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)) {
@@ -1097,10 +1011,6 @@ sub handle_19
 				} 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;
 			}
 		}
 
@@ -1112,8 +1022,13 @@ sub handle_19
 		$user->put;
 	}
 
-
-	$self->route_pc19($origin, $line, @rout) if @rout;
+	# we are not automatically sending out PC19s, we send out a composite PC21,PC19 instead
+	# 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_pc19($self->{call}, $line, @rout);
+	}
 }
 		
 # send local configuration
@@ -1130,6 +1045,9 @@ sub handle_20
 }
 		
 # delete a cluster from the list
+#
+# This should never occur for directly connected nodes.
+#
 sub handle_21
 {
 	my $self = shift;
@@ -1140,59 +1058,42 @@ sub handle_21
 
 	eph_del_regex("^PC1[679].*$call");
 			
-	# if I get a PC21 from the same callsign as self then treat it
-	# as a PC39: I have gone away
+	# if I get a PC21 from the same callsign as self then ignore it
 	if ($call eq $self->call) {
-		$self->disconnect(1);
+		dbg("PCPROT: self referencing PC21 from $self->{call}");
 		return;
 	}
 
 	RouteDB::delete($call, $self->{call});
 
-	# check if we believe this
-	unless ($call eq $self->{call} || $self->is_believed($call)) {
-		if (my $ivp = Investigate::get($call, $self->{call})) {
-			$ivp->store_pcxx($pcno,$line,$origin,@_);
-		} else {
-			dbg("PCPROT: We don't believe $call on $self->{call}") if isdbg('chanerr');
-		}
+	my $parent = Route::Node::get($self->{call});
+	unless ($parent) {
+		dbg("PCPROT: my parent $self->{call} has disappeared");
+		$self->disconnect;
 		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);
+	
+	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;
 			}
-		} else {
-			dbg("PCPROT: I WILL _NOT_ be disconnected!") 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;
@@ -1649,6 +1550,17 @@ sub handle_85
 	$self->process_rcmd_reply($_[1], $_[2], $_[3], $_[4]);
 }
 
+# DXSpider routing entries
+sub handle_92
+{
+	my $self = shift;
+	my $pcno = shift;
+	my $line = shift;
+	my $origin = shift;
+
+	$self->{do_pc92} ||= 1;
+}
+
 # if get here then rebroadcast the thing with its Hop count decremented (if
 # there is one). If it has a hop count and it decrements to zero then don't
 # rebroadcast it.
@@ -2287,19 +2199,6 @@ sub disconnect
 
 	RouteDB::delete_interface($call);
 	
-	# remove them from the pc19list as well
-	while (my ($k,$v) = each %pc19list) {
-		my @l = grep {$_->[0] ne $call} @{$pc19list{$k}};
-		if (@l) {
-			$pc19list{$k} = \@l;
-		} else {
-			delete $pc19list{$k};
-		}
-		
-		# and the ephemera
-		eph_del_regex("^PC1[679].*$k");
-	}
-
 	# unbusy and stop and outgoing mail
 	my $mref = DXMsg::get_busy($call);
 	$mref->stop_msg($call) if $mref;
@@ -2397,6 +2296,7 @@ sub broadcast_route
 			next if $dxchan == $self;
 			next if $dxchan == $main::me;
 			next unless $dxchan->isa('DXProt');
+			next if $self->{do_pc92};
 			next if ($generate == \&pc16 || $generate==\&pc17) && !$dxchan->user->wantsendpc16;
  
 			$dxchan->send_route($origin, $generate, @_);
@@ -2404,6 +2304,27 @@ sub broadcast_route
 	}
 }
 
+sub broadcast_route_pc9x
+{
+	my $self = shift;
+	my $origin = shift;
+	my $generate = shift;
+	my $line = shift;
+	my @dxchan = DXChannel::get_all_nodes();
+	my $dxchan;
+	
+	unless ($self->{isolate}) {
+		foreach $dxchan (@dxchan) {
+			next if $dxchan == $self;
+			next if $dxchan == $main::me;
+			next unless $dxchan->isa('DXProt');
+			next unless $self->{do_pc92};
+ 
+			$dxchan->send_route($origin, $generate, @_);
+		}
+	}
+}
+
 sub route_pc16
 {
 	my $self = shift;
@@ -2462,6 +2383,30 @@ sub route_pc50
 	broadcast_route($self, $origin, \&pc50, $line, 1, @_);
 }
 
+sub route_pc92c
+{
+	my $self = shift;
+	my $origin = shift;
+	my $line = shift;
+	broadcast_route_pc9x($self, $origin, \&pc92c, $line, 1, @_);
+}
+
+sub route_pc92a
+{
+	my $self = shift;
+	my $origin = shift;
+	my $line = shift;
+	broadcast_route_pc9x($self, $origin, \&pc92a, $line, 1, @_);
+}
+
+sub route_pc92d
+{
+	my $self = shift;
+	my $origin = shift;
+	my $line = shift;
+	broadcast_route_pc9x($self, $origin, \&pc92d, $line, 1, @_);
+}
+
 sub in_filter_route
 {
 	my $self = shift;
diff --git a/perl/DXProtout.pm b/perl/DXProtout.pm
index 522352e4..856a60bb 100644
--- a/perl/DXProtout.pm
+++ b/perl/DXProtout.pm
@@ -123,7 +123,7 @@ sub pc17
 # Request init string
 sub pc18
 {
-	my $flags = "";
+	my $flags = " pc";
 	$flags .= " xml" if DXXml::available(); 
 	return "PC18^DXSpider Version: $main::version Build: $main::build$flags^$DXProt::myprot_version^";
 }
@@ -374,9 +374,64 @@ sub pc85
 	return "PC85^$tonode^$fromnode^$call^$msg^~";
 }
 
-# spider route broadcast
-sub pc90
+# spider route broadcasts
+#
+
+my $_last_time;
+my $_last_occurs;
+
+sub _gen_time
+{
+	if (!$_last_time || $_last_time != $main::systime) {
+		$_last_time = $main::systime;
+		$_last_occurs = 0;
+		return $_last_time;
+	} else {
+		$_last_occurs++;
+		return "$_last_time:$_last_occurs";
+	}
+}
+
+sub _gen_pc92
+{
+	my $sort = shift;
+	my $s = "PC92^$sort^" . _gen_time;
+	for (@_) {
+		my $flag = 0;
+		my $call = $_->call; 
+		my $extra = '';
+		if ($_->isa('Route::Node')) {
+			$flag = 4;
+			if ($call ne $main::mycall && DXChannel::get($call)) {
+				$flag += 2;
+			}
+			if ($sort eq 'C') {
+				$extra .= ':' . ($_->version || '') if $_->build;
+				$extra .= ':' . $_->build if $_->build;
+			}
+		}
+		$flag += $_->here ? 1 : 0;
+		$s .= "^$flag$call$extra";
+	}
+	return $s . '^H99';
+}
+
+# add a local one
+sub pc92a
+{
+	return _gen_pc92('A', @_);
+}
+
+# delete a local one
+sub pc92d
+{
+	return _gen_pc92('D', @_);
+}
+
+# send a config
+sub pc92c
 {
+	return _gen_pc92('C', @_);
 }
 
 1;
-- 
2.43.0