From c20a2c1e01d707d6c3fa25067df93d491aba8fff Mon Sep 17 00:00:00 2001
From: minima <minima>
Date: Sun, 29 Oct 2000 11:00:06 +0000
Subject: [PATCH] added echo cancelling started new filter code, objectifyed
 old filter code

---
 Changes            |   7 +++
 cmd/show/log.pl    |   2 +-
 perl/DXLogPrint.pm |   4 +-
 perl/DXProt.pm     |  12 ++--
 perl/Filter.pm     | 144 ++++++++++++++++++++++++++-------------------
 perl/client.pl     |   6 ++
 src/client.c       |  35 +++++++++--
 src/cmsg.c         |   7 ++-
 8 files changed, 142 insertions(+), 75 deletions(-)

diff --git a/Changes b/Changes
index e446baa8..af1d970e 100644
--- a/Changes
+++ b/Changes
@@ -1,9 +1,16 @@
+29Oct00=======================================================================
+1. put in echo cancelling measures into the clients. This doesn't mean you
+shouldn't take steps to prevent echoing on node links, but it may help where
+(whatever you do) it still bloody echos! This is experimental. 
 28Oct00=======================================================================
 1. updated show/sun and show/moon from stuff sent by Steve Franke K9AN
 2. added show/call which queries jeifer.pineknot.com for any call in the 
 world (as opposed to UALR which only does US calls). Inspired by a bit of 
 perl sent to me by Steve Franke (again!) and also Angel EA7WA who gave me the
 pineknot ip address.
+3. fixed clients so that they accept -0 as a valid SSID and then strip it off
+as though they had come in without (why has this taken so long to appear? How
+long have we been running this code ??????). 
 27Oct00=======================================================================
 1. alter the code in clean_old of DXMsg system to see if we get some different
 behaviour with random crashing
diff --git a/cmd/show/log.pl b/cmd/show/log.pl
index bced5855..8a00e385 100644
--- a/cmd/show/log.pl
+++ b/cmd/show/log.pl
@@ -35,5 +35,5 @@ if ($self->priv < 6) {
 	return (1, $self->msg('e5')) if $who ne $self->call;
 }
 
-@out = DXLog::print($from, $to, $main::systime, undef,  $who);
+@out = DXLog::print($from, $to, $main::systime, $who);
 return (1, @out);
diff --git a/perl/DXLogPrint.pm b/perl/DXLogPrint.pm
index 60f8b685..185912cd 100644
--- a/perl/DXLogPrint.pm
+++ b/perl/DXLogPrint.pm
@@ -37,9 +37,9 @@ sub print
 	my $count;
 	    
 	$search = '1' unless $pattern || $who;
-	$search = "\$ref->[1] =~ /$pattern/" if $pattern;
+	$search = "\$ref->[1] =~ /$pattern/i" if $pattern;
 	$search .= ' && ' if $pattern && $who;
-	$search .= "(\$ref->[2] =~ /$who/ || \$ref->[3] =~ /$who/)" if $who;
+	$search .= "(\$ref->[2] =~ /$who/i || \$ref->[3] =~ /$who/i)" if $who;
 	$eval = qq(
 			   my \$c;
 			   my \$ref;
diff --git a/perl/DXProt.pm b/perl/DXProt.pm
index 5d2b10b8..db342dfb 100644
--- a/perl/DXProt.pm
+++ b/perl/DXProt.pm
@@ -466,7 +466,7 @@ sub normal
 						$org_itu = $dxcc[1]->itu;
 						$org_cq = $dxcc[1]->cq();						
 					}
-					my ($filter, $hops) = Filter::it($self->{inannfilter}, @field[1..6], $self->{call}, 
+					my ($filter, $hops) = $self->{inannfilter}->it(@field[1..6], $self->{call}, 
 													$ann_dxcc, $ann_itu, $ann_cq, $org_dxcc, $org_itu, $org_cq);
 					unless ($filter) {
 						dbg('chan', "Rejected by filter");
@@ -1139,7 +1139,7 @@ sub send_dx_spot
 		my ($filter, $hops);
 
 		if ($dxchan->{spotfilter}) {
-		    ($filter, $hops) = Filter::it($dxchan->{spotfilter}, @_, $self->{call} );
+		    ($filter, $hops) = $dxchan->{spotfilter}->it(@_, $self->{call} );
 			next unless $filter;
 		}
 		
@@ -1184,7 +1184,7 @@ sub send_wwv_spot
 		my ($filter, $hops);
 
 		if ($dxchan->{wwvfilter}) {
-			 ($filter, $hops) = Filter::it($dxchan->{wwvfilter}, @_, $self->{call} );
+			 ($filter, $hops) = $dxchan->{wwvfilter}->it(@_, $self->{call} );
 			 next unless $filter;
 		}
 		if ($dxchan->is_node) {
@@ -1228,7 +1228,7 @@ sub send_wcy_spot
 		my ($filter, $hops);
 
 		if ($dxchan->{wcyfilter}) {
-			 ($filter, $hops) = Filter::it($dxchan->{wcyfilter}, @_, $self->{call} );
+			 ($filter, $hops) = $dxchan->{wcyfilter}->it(@_, $self->{call} );
 			 next unless $filter;
 		}
 		if ($dxchan->is_clx || $dxchan->is_spider) {
@@ -1303,7 +1303,7 @@ sub send_announce
 				$org_itu = $dxcc[1]->itu;
 				$org_cq = $dxcc[1]->cq;						
 			}
-			($filter, $hops) = Filter::it($dxchan->{annfilter}, @_, $self->{call}, $ann_dxcc, $ann_itu, $ann_cq, $org_dxcc, $org_itu, $org_cq);
+			($filter, $hops) = $dxchan->{annfilter}->it(@_, $self->{call}, $ann_dxcc, $ann_itu, $ann_cq, $org_dxcc, $org_itu, $org_cq);
 			next unless $filter;
 		} 
 		if ($dxchan->is_node && $_[1] ne $main::mycall) {  # i.e not specifically routed to me
@@ -1473,7 +1473,7 @@ sub broadcast_list
 		
 		if ($sort eq 'dx') {
 		    next unless $dxchan->{dx};
-			($filter) = Filter::it($dxchan->{spotfilter}, @{$fref}) if ref $fref;
+			($filter) = $dxchan->{spotfilter}->it(@{$fref}) if ref $fref;
 			next unless $filter;
 		}
 		next if $sort eq 'ann' && !$dxchan->{ann};
diff --git a/perl/Filter.pm b/perl/Filter.pm
index a53ae034..2b30c8cd 100644
--- a/perl/Filter.pm
+++ b/perl/Filter.pm
@@ -12,42 +12,24 @@
 #
 # $Id$
 #
-# The INSTRUCTIONS
+# The NEW INSTRUCTIONS
+#
+# use the commands accept/spot|ann|wwv|wcy and reject/spot|ann|wwv|wcy
+# also show/filter spot|ann|wwv|wcy
 #
 # The filters live in a directory tree of their own in $main::root/filter
 #
 # Each type of filter (e.g. spot, wwv) live in a tree of their own so you
 # can have different filters for different things for the same callsign.
 #
-# Each filter file has the same structure:-
-#
-# <some comment>
-# @in = (
-#      [ action, fieldno, fieldsort, comparison, action data ],
-#      ...
-# );
-#
-# The action is usually 1 or 0 but could be any numeric value
-#
-# The fieldno is the field no in the list of fields that is presented
-# to 'Filter::it' 
-#
-# The fieldsort is the type of field that we are dealing with which 
-# currently can be 'a', 'n', 'r' or 'd'. 'a' is alphanumeric, 'n' is 
-# numeric, 'r' is ranges of pairs of numeric values and 'd' is default.
-#
-# Filter::it basically goes thru the list of comparisons from top to
-# bottom and when one matches it will return the action and the action data as a list. 
-# The fields
-# are the element nos of the list that is presented to Filter::it. Element
-# 0 is the first field of the list.
-#
+
 
 package Filter;
 
 use DXVars;
 use DXUtil;
 use DXDebug;
+use Data::Dumper;
 
 use strict;
 
@@ -62,40 +44,6 @@ sub init
 
 }
 
-#
-# takes the reference to the filter (the first argument) and applies
-# it to the subsequent arguments and returns the action specified.
-#
-sub it
-{
-	my $filter = shift;
-	my ($action, $field, $fieldsort, $comp, $actiondata);
-	my $ref;
-
-	# default action is 1
-	$action = 1;
-	$actiondata = "";
-	return ($action, $actiondata) if !$filter;
-
-	for $ref (@{$filter}) {
-		($action, $field, $fieldsort, $comp, $actiondata) = @{$ref};
-		if ($fieldsort eq 'n') {
-			my $val = $_[$field];
-			return ($action, $actiondata)  if grep $_ == $val, @{$comp};
-		} elsif ($fieldsort eq 'r') {
-			my $val = $_[$field];
-			my $i;
-			my @range = @{$comp};
-			for ($i = 0; $i < @range; $i += 2) {
-				return ($action, $actiondata)  if $val >= $range[$i] && $val <= $range[$i+1];
-			}
-		} elsif ($fieldsort eq 'a') {
-			return ($action, $actiondata)  if $_[$field] =~ m{$comp};
-		} else {
-			return ($action, $actiondata);      # the default action
-		}
-	}
-}
 
 # this reads in a filter statement and returns it as a list
 # 
@@ -120,17 +68,22 @@ sub read_in
 	
 	# load it
 	if (-e $fn) {
-		do "$fn";
+		$in = undef; 
+		my $s = readfilestr($fn);
+		my $newin = eval $s;
 		dbg('conn', "$@") if $@;
-		return $in;
+		return bless [ @$in ], 'Filter::Old' if $in;
+		return $newin;
 	}
 	return undef;
 }
 
 # this writes out the filter in a form suitable to be read in by 'read_in'
 # It expects a list of references to filter lines
-sub write_out
+sub write
 {
+	my $self = shift;
+	
 	my $sort = shift;
 	my $call = shift;
 	my $fn = "$filterbasefn/$sort";
@@ -170,5 +123,74 @@ sub write_out
 	close FILTER;
 }
 
+package Filter::Old;
+
+use strict;
+use vars qw(@ISA);
+@ISA = qw(Filter);
+
+# the OLD instructions!
+#
+# Each filter file has the same structure:-
+#
+# <some comment>
+# @in = (
+#      [ action, fieldno, fieldsort, comparison, action data ],
+#      ...
+# );
+#
+# The action is usually 1 or 0 but could be any numeric value
+#
+# The fieldno is the field no in the list of fields that is presented
+# to 'Filter::it' 
+#
+# The fieldsort is the type of field that we are dealing with which 
+# currently can be 'a', 'n', 'r' or 'd'. 'a' is alphanumeric, 'n' is 
+# numeric, 'r' is ranges of pairs of numeric values and 'd' is default.
+#
+# Filter::it basically goes thru the list of comparisons from top to
+# bottom and when one matches it will return the action and the action data as a list. 
+# The fields
+# are the element nos of the list that is presented to Filter::it. Element
+# 0 is the first field of the list.
+#
+
+#
+# takes the reference to the filter (the first argument) and applies
+# it to the subsequent arguments and returns the action specified.
+#
+sub it
+{
+	my $filter = shift;            # this is now a bless ref of course but so what
+	
+	my ($action, $field, $fieldsort, $comp, $actiondata);
+	my $ref;
+
+	# default action is 1
+	$action = 1;
+	$actiondata = "";
+	return ($action, $actiondata) if !$filter;
+
+	for $ref (@{$filter}) {
+		($action, $field, $fieldsort, $comp, $actiondata) = @{$ref};
+		if ($fieldsort eq 'n') {
+			my $val = $_[$field];
+			return ($action, $actiondata)  if grep $_ == $val, @{$comp};
+		} elsif ($fieldsort eq 'r') {
+			my $val = $_[$field];
+			my $i;
+			my @range = @{$comp};
+			for ($i = 0; $i < @range; $i += 2) {
+				return ($action, $actiondata)  if $val >= $range[$i] && $val <= $range[$i+1];
+			}
+		} elsif ($fieldsort eq 'a') {
+			return ($action, $actiondata)  if $_[$field] =~ m{$comp};
+		} else {
+			return ($action, $actiondata);      # the default action
+		}
+	}
+}
+
+
 1;
 __END__
diff --git a/perl/client.pl b/perl/client.pl
index b8494578..ff2ca473 100755
--- a/perl/client.pl
+++ b/perl/client.pl
@@ -119,6 +119,8 @@ sub rec_socket
 			if ($buffered) {
 				if (length $outqueue >= $client_buffer_lth) {
 					print $stdout $outqueue;
+					pop @echo if @echo > $maxecho;
+					push @echo, $outqueue;
 					$outqueue = "";
 				}
 				$outqueue .= "$savenl$line$snl";
@@ -144,6 +146,8 @@ sub rec_socket
 		} elsif ($sort eq 'B') {
 			if ($buffered && $outqueue) {
 				print $stdout $outqueue;
+				pop @echo if @echo > $maxecho;
+				push @echo, $outqueue;
 				$outqueue = "";
 			}
 			$buffered = $line;	# set buffered or unbuffered
@@ -199,6 +203,7 @@ sub rec_stdin
 			unshift @lines, ($lastbit . $first) if ($first);
 			foreach $first (@lines) {
 				#		  print "send_now $call $first\n";
+				next if grep {$_ eq $first } @echo;
 				$conn->send_later("I$call|$first");
 			}
 			$lastbit = $buf;
@@ -340,6 +345,7 @@ $savenl = "";                   # an NL that has been saved from last time
 $timeout = 60;                  # default timeout for connects
 $abort = "";                    # the current abort string
 $cpath = "$root/connect";		# the basic connect directory
+$maxecho = 5;                  # length of max echo queue
 
 $pid = 0;                       # the pid of the child program
 $csort = "";                    # the connection type
diff --git a/src/client.c b/src/client.c
index 167ef647..8df62449 100644
--- a/src/client.c
+++ b/src/client.c
@@ -34,6 +34,7 @@
 
 #include "sel.h"
 #include "cmsg.h"
+#include "chain.h"
 #include "debug.h"
 
 #define TEXT 1
@@ -95,8 +96,9 @@ int tabsize = 8;				/* default tabsize for text messages */
 char *connsort = "local";		/* the connection variety */
 int state = 0;					/* the current state of the connection */
 int laststate = 0;				/* the last state we were in */
-
-
+reft echobase;					/* the anti echo queue */
+int maxecho = 5;				/* the depth of the anti echo queue */
+int echon;						/* no of entries in the anti echo queue */
 
 #define CONNECTED 100
 #define WAITLOGIN 1
@@ -221,7 +223,22 @@ fcb_t *fcb_new(int cnum, int sort)
 void flush_text(fcb_t *f)
 {
 	if (f->obuf) {
-		cmsg_send(f->outq, f->obuf, 0);
+		/* save this onto the front of the echo chain */
+		cmsg_t *imp = f->obuf;
+		int size = imp->inp - imp->data;
+		cmsg_t *emp = cmsg_new(size, imp->sort, imp->portp);
+
+		emp->size = size;
+		memcpy(emp->data, imp->data, size);
+		emp->inp = emp->data + size; /* just in case */
+		chain_add(&echobase, emp);
+		if (++echon > maxecho) {
+			emp = cmsg_prev(&echobase);
+			cmsg_free(emp);
+		}
+		
+		/* queue it for sending */
+		cmsg_send(f->outq, imp, 0);
 		f->sp->flags |= SEL_OUTPUT;
 		f->obuf = 0;
 	}
@@ -572,12 +589,20 @@ void setmode(char *m)
 
 void process_stdin()
 {
-	cmsg_t *mp = cmsg_next(in->inq);
+	cmsg_t *wmp, *mp = cmsg_next(in->inq);
 	char *p, hasa, hasn, i;
 	char callsign[MAXCALLSIGN+1];
 	
 	if (mp) {
 		dbg(DMSG, "MSG size: %d", mp->size);
+		
+		/* check for echos */
+		for (wmp = 0; wmp = chain_get_next(&echobase, wmp); ) {
+			if (!memcmp(wmp->data, mp->data, wmp->size)) {
+				cmsg_callback(mp, 0);
+				return;
+			}
+		}
 
 		switch (state) {
 		case CONNECTED:
@@ -854,6 +879,8 @@ main(int argc, char *argv[])
 #ifdef SIGPWR
 	signal(SIGPWR, terminate);
 #endif
+	/* init a few things */
+	chain_init(&echobase);
 
 	/* connect up stdin */
 	in = fcb_new(0, TEXT);
diff --git a/src/cmsg.c b/src/cmsg.c
index 8732f19b..c3c79ef8 100755
--- a/src/cmsg.c
+++ b/src/cmsg.c
@@ -91,6 +91,7 @@ cmsg_t *cmsg_new(int size, int sort, void *pp)
 	return mp;
 }
 
+
 void cmsg_send(reft *base, cmsg_t *mp, void (*callback)())
 {
 	time(&mp->t);
@@ -177,7 +178,11 @@ void cmsg_flush(reft *base, int reply)
 /*
  * 
  * $Log$
- * Revision 1.2  2000-07-20 14:16:00  minima
+ * Revision 1.3  2000-10-29 11:00:07  minima
+ * added echo cancelling
+ * started new filter code, objectifyed old filter code
+ *
+ * Revision 1.2  2000/07/20 14:16:00  minima
  * can use Sourceforge now!
  * added user->qra cleaning
  * added 4 digit qra to user broadcast dxspots if available
-- 
2.43.0