a nominially working aranea with DX commands converted
authorminima <minima>
Sun, 13 Feb 2005 23:36:01 +0000 (23:36 +0000)
committerminima <minima>
Sun, 13 Feb 2005 23:36:01 +0000 (23:36 +0000)
20 files changed:
cmd/connect.pl
cmd/dx.pl
cmd/show/connect.pl
cmd/who.pl
perl/AMsg.pm
perl/Aranea.pm
perl/DXChannel.pm
perl/DXCommandmode.pm
perl/DXDebug.pm
perl/DXProt.pm
perl/DXProtVars.pm
perl/DXProtout.pm
perl/ExtMsg.pm
perl/Filter.pm
perl/Spot.pm
perl/Thingy.pm
perl/Thingy/Dx.pm [new file with mode: 0644]
perl/Thingy/Hello.pm
perl/Verify.pm
perl/cluster.pl

index d1c583cbd3d6a7f3a65a7062bd373523d34c48af..1f1ad03f640b76f53f1a59f8b1e8aecd678afb5e 100644 (file)
@@ -16,7 +16,16 @@ return (1, $self->msg('lockout', $call)) if $user && $user->lockout;
 
 my @out;
 push @out, $self->msg('constart', $call);
-ExtMsg::start_connect($call, "$main::root/connect/$lccall");
+my $fn = "$main::root/connect/$lccall";
+
+my $f = new IO::File $fn;
+if ($f) {
+       my @f = <$f>;
+       $f->close;
+       ExtMsg::start_connect($call, @f);
+} else {
+       push @out, $self->msg('e3', 'connect', $fn);
+}
 return (1, @out);
 
 
index 02fc3ca448604706d3ecd06996027faf155bfe24..9a9aff7108a2c58b0b9f079702d4650effd5b982 100644 (file)
--- a/cmd/dx.pl
+++ b/cmd/dx.pl
@@ -104,8 +104,9 @@ return (1, @out) unless $valid;
 
 # Store it here (but only if it isn't baddx)
 my $t = (int ($main::systime/60)) * 60;
-return (1, $self->msg('dup')) if Spot::dup($freq, $spotted, $t, $line, $spotter);
 my @spot = Spot::prepare($freq, $spotted, $t, $line, $spotter, $main::mycall);
+my $thing = Thingy::Dx->new(origin=>$main::mycall, group=>'DX', user=>$spotter);
+$thing->from_DXProt(spotdata=>\@spot);
 
 if ($DXProt::baddx->in($spotted) || $freq =~ /^69/ || $localonly) {
 
@@ -113,19 +114,10 @@ if ($DXProt::baddx->in($spotted) || $freq =~ /^69/ || $localonly) {
        if ($freq =~ /^69/) {
                $self->badcount(($self->badcount||0) + 1);
        }
-
-       $self->dx_spot(undef, undef, @spot);
-       return (1);
 } else {
-       if (@spot) {
-               # store it 
-               Spot::add(@spot);
-
-               # send orf to the users
-               DXProt::send_dx_spot($self, DXProt::pc11($spotter, $freq, $spotted, $line), @spot);
-       }
+       $thing->queue($self);
 }
-
+push @out, $thing->gen_DXCommandmode($self);
 return (1, @out);
 
 
index 98211ddfd31b3dc9d6560fb8d0fa1d8119d703f1..23b2620bac196f7beebad99057cd4b1c18d942f7 100644 (file)
@@ -18,8 +18,9 @@ foreach my $call (sort keys %Msg::conns) {
        my $c = $call;
        my $addr;
        
-       if ($c =~ /^Server\s+(\S+)$/) {
+       if ($c =~ /^Server\s+(.*)$/) {
                $addr = $1;
+               $addr =~ s/\s+using.*$//;
                $c = "Server";
        } else {
                $addr = "$r->{peerhost}/$r->{peerport}";
index 12010d818ff7498c37fce3d444da5ab3fb4b58e3..3b12fd0e7c4de0658502cf00ff3a6da4d2b519a2 100644 (file)
@@ -19,13 +19,13 @@ foreach $dxchan ( sort {$a->call cmp $b->call} DXChannel::get_all ) {
        my $type = $dxchan->is_node ? "NODE" : "USER";\r
        my $sort = "    ";\r
        if ($dxchan->is_node) {\r
-               $sort = 'ANEA' if $dxchan->is_aranea;\r
                $sort = "DXSP" if $dxchan->is_spider;\r
                $sort = "CLX " if $dxchan->is_clx;\r
                $sort = "DXNT" if $dxchan->is_dxnet;\r
                $sort = "AR-C" if $dxchan->is_arcluster;\r
                $sort = "AK1A" if $dxchan->is_ak1a;\r
        }\r
+       $type = 'ANEA' if $dxchan->is_aranea;\r
        my $name = $dxchan->user->name || " ";\r
        my $ping = $dxchan->is_node && $dxchan != $main::me ? sprintf("%5.2f", $dxchan->pingave) : "     ";\r
        my $conn = $dxchan->conn;\r
index 19fe9208818f28a075e6264fcb9353059c11566a..6a17832253962408ade247fbae34524bf649633d 100644 (file)
@@ -54,7 +54,7 @@ sub dequeue
                        } 
                }
                if ($conn->{state} eq 'WC' && exists $conn->{cmd} && @{$conn->{cmd}} == 0) {
-                       $conn->to_connected($conn->{call}, 'O', $conn->{csort});
+                       $conn->{state} = 'WH';
                }
        } elsif ($conn->{msg} =~ /\cJ/) {
                my @lines =  $conn->{msg} =~ /([^\cM\cJ]*)\cM?\cJ/g;
@@ -67,23 +67,19 @@ sub dequeue
                        dbg("connect $conn->{cnum}: $msg") if $conn->{state} ne 'C' && isdbg('connect');
                        if ($conn->{state} eq 'C') {
                                &{$conn->{rproc}}($conn, $msg);
-                       } elsif ($conn->{state} eq 'WA' ) {
-                               my $uref = DXUser->get_current($conn->{call});
+                       } elsif ($conn->{state} eq 'WH' ) {
+                               # this is the first stage that we have a callsign
+                               # do we have a hello?
                                $msg =~ s/[\r\n]+$//;
-                               if ($uref && $msg eq $uref->passwd) {
-                                       my $sort = $conn->{csort};
-                                       $sort = 'local' if $conn->{peerhost} eq "127.0.0.1";
-                                       $conn->{usedpasswd} = 1;
-                                       $conn->to_connected($conn->{call}, 'A', $sort);
-                               } else {
-                                       $conn->send_now("Sorry");
-                                       $conn->disconnect;
+                               if ($msg =~ m{ROUTE,[0-9A-F,]+|HELLO}) {
+                                       # a possibly valid HELLO line, process it
+                                       $conn->new_channel($msg);
                                }
                        } elsif ($conn->{state} eq 'WC') {
                                if (exists $conn->{cmd} && @{$conn->{cmd}}) {
                                        $conn->_docmd($msg);
                                        if ($conn->{state} eq 'WC' && exists $conn->{cmd} &&  @{$conn->{cmd}} == 0) {
-                                               $conn->to_connected($conn->{call}, 'O', $conn->{csort});
+                                               $conn->{state} = 'WH';
                                        }
                                }
                        }
@@ -91,18 +87,6 @@ sub dequeue
        } 
 }
 
-sub to_connected
-{
-       my ($conn, $call, $dir, $sort) = @_;
-       $conn->{state} = 'C';
-       $conn->conns($call);
-       delete $conn->{cmd};
-       $conn->{timeout}->del if $conn->{timeout};
-       delete $conn->{timeout};
-       $conn->nolinger;
-       &{$conn->{rproc}}($conn, "$dir$call|$sort");
-}
-
 sub login
 {
        return \&new_channel;
@@ -141,30 +125,23 @@ sub new_client {
                                $conn->disconnect();
                        }
                        Log('Aranea', "Incoming connection from $conn->{peerhost}");
-                       $conn->{outgoing} = 0;
+                       $conn->{outbound} = 0;
                        $conn->{state} = 'WH';          # wait for return authorize
                        my $thing = $conn->{lastthing} = Thingy::Hello->new(origin=>$main::mycall, group=>'ROUTE');
+
                        $thing->send($conn, 'Aranea');
+                       dbg("-> D $conn->{peerhost} $thing->{Aranea}") if isdbg('chan');
                }
        } else {
                dbg("ExtMsg: error on accept ($!)") if isdbg('err');
        }
 }
 
-sub start_connect
+sub set_newchannel_rproc
 {
-       my $call = shift;
-       my $fn = shift;
-       my $conn = AMsg->new(\&new_channel); 
-       $conn->{outgoing} = 1;
-       $conn->conns($call);
-       
-       my $f = new IO::File $fn;
-       push @{$conn->{cmd}}, <$f>;
-       $f->close;
-       $conn->{state} = 'WC';
-       $conn->_dotimeout($deftimeout);
-       $conn->_docmd;
+       my $conn = shift;
+       $conn->{rproc} = \&new_channel;
+       $conn->{state} = 'WH';
 }
 
 # 
@@ -174,10 +151,19 @@ sub start_connect
 sub new_channel
 {
        my ($conn, $msg) = @_;
+       my $call = $conn->{call} || $conn->{peerhost};
+
+       dbg("<- I $call $msg") if isdbg('chan');
+
        my $thing = Aranea::input($msg);
-       return unless defined $thing;
+       unless ($thing) {
+               dbg("Invalid thingy: $msg from $conn->{peerhost}");
+               $conn->send_now("Sorry");
+               $conn->disconnect;
+               return;
+       }
 
-       my $call = $thing->{origin};
+       $call = $thing->{origin};
        unless (is_callsign($call)) {
                main::already_conn($conn, $call, DXM::msg($main::lang, "illcall", $call));
                return;
@@ -188,7 +174,7 @@ sub new_channel
        my $user = DXUser->get_current($call);
        my $dxchan = DXChannel->get($call);
        if ($dxchan) {
-               if ($main::bumpexisting) {
+               if ($main::bumpexisting && $call ne $main::mycall) {
                        my $ip = $conn->{peerhost} || 'unknown';
                        $dxchan->send_now('D', DXM::msg($main::lang, 'conbump', $call, $ip));
                        Log('DXCommand', "$call bumped off by $ip, disconnected");
@@ -224,12 +210,17 @@ sub new_channel
        $dxchan = Aranea->new($call, $conn, $user);
 
        # check that the conn has a callsign
-       $conn->conns($call) if $conn->isa('IntMsg');
+       $conn->conns($call);
 
        # set callbacks
        $conn->set_error(sub {main::error_handler($dxchan)});
        $conn->set_rproc(sub {my ($conn,$msg) = @_; $dxchan->rec($msg)});
-       $dxchan->rec($msg);
+       $conn->{state} = 'C';
+       delete $conn->{cmd};
+       $conn->{timeout}->del if $conn->{timeout};
+       delete $conn->{timeout};
+       $conn->nolinger;
+       $thing->handle($dxchan);
 }
 
 sub send
index 1d0a912fe6dcea060b2f17d9d06b3e7ba594a106..3af3aee9432cd934f21f992cbd3006b3f36867a4 100644 (file)
@@ -24,6 +24,7 @@ use Route::Node;
 use Script;
 use Verify;
 use DXDupe;
+use Thingy;
 
 use vars qw($VERSION $BRANCH);
 $VERSION = sprintf( "%d.%03d", q$Revision$ =~ /(\d+)\.(\d+)/ );
@@ -40,6 +41,7 @@ $dupeage = 12*60*60;                  # duplicates stored half a day
 
 my $seqno = 0;
 my $dayno = 0;
+my $daystart = 0;
 
 sub init
 {
@@ -109,7 +111,7 @@ sub start
        $self->{metric} ||= 100;
        $self->{lastping} = $main::systime;
        
-       $self->state('init');
+       $self->state('normal');
        $self->{pc50_t} = $main::systime;
 
        # send info to all logged in thingies
@@ -118,7 +120,6 @@ sub start
        # run a script send the output to the debug file
        my $script = new Script(lc $call) || new Script('node_default');
        $script->run($self) if $script;
-       $self->send("Hello?");
 }
 
 #
@@ -127,8 +128,8 @@ sub start
 sub normal
 {
        my ($self, $line) = @_;
-
-       
+       my $thing = input($line);
+       $thing->queue($self) if $thing;
 }
 
 #
@@ -139,7 +140,57 @@ sub process
 {
 
        # calc day number
-       $dayno = (gmtime($main::systime))[3];
+       my $d = (gmtime($main::systime))[3];
+       if ($d != $dayno) {
+               $dayno = $d;
+               $daystart = $main::systime - ($main::systime % 86400);
+       }
+}
+
+sub disconnect
+{
+       my $self = shift;
+       my $call = $self->call;
+
+       return if $self->{disconnecting}++;
+       
+       # get rid of any PC16/17/19
+#      eph_del_regex("^PC1[679]*$call");
+
+       # do routing stuff, remove me from routing table
+       my $node = Route::Node::get($call);
+       my @rout;
+       if ($node) {
+               @rout = $node->del($main::routeroot);
+               
+               # and all my ephemera as well
+               for (@rout) {
+                       my $c = $_->call;
+#                      eph_del_regex("^PC1[679].*$c");
+               }
+       }
+
+       RouteDB::delete_interface($call);
+       
+       # unbusy and stop and outgoing mail
+       my $mref = DXMsg::get_busy($call);
+       $mref->stop_msg($call) if $mref;
+       
+       # broadcast to all other nodes that all the nodes connected to via me are gone
+#      $self->route_pc21($main::mycall, undef, @rout) if @rout;
+
+       # remove outstanding pings
+#      delete $pings{$call};
+       
+       # I was the last node visited
+    $self->user->node($main::mycall);
+
+       # send info to all logged in thingies
+       $self->tell_login('logoutn');
+
+       Log('Aranea', $call . " Disconnected");
+
+       $self->SUPER::disconnect;
 }
 
 # 
@@ -154,24 +205,49 @@ sub genheader
        my $from = shift;
        
        my $date = ((($dayno << 1) | $ntpflag) << 18) |  ($main::systime % 86400);
-       my $r = "$mycall,$to," . sprintf('%06X%04X,0', $date, $seqno);
+       my $r = "$mycall,$to," . sprintf('%6X%04X,0', $date, $seqno);
        $r .= ",$from" if $from;
        $seqno++;
        $seqno = 0 if $seqno > 0x0ffff;
        return $r;
 }
 
+#
+# decode the date time sequence group
+#
+
+sub decode_dts
+{
+       my $dts = shift;
+       my ($dt, $seqno) = map {hex} unpack "H6H4", $dts;
+       my $secs = $dt & 0x3FFFF;
+       $dt >>= 18;
+       my $day = $dt >> 1;
+       my $ntp = $dt & 1;
+       my $t;
+       if ($dayno == $day) {
+               $t = $daystart + $secs;
+       } elsif ($dayno < $day) {
+               $t = $daystart + (($day-$dayno) * 86400) + $secs;
+       } else {
+               $t = $daystart + (($dayno-$day) * 86400) + $secs;
+       }
+       return ($t, $seqno, $ntp);
+}
+
 # subroutines to encode and decode values in lists 
 sub tencode
 {
        my $s = shift;
-       $s =~ s/([\%=|,\x00-\x1f\x7f-\xff])/sprintf("%%%02X", ord($1))/eg; 
+       $s =~ s/([\%=|,\'\x00-\x1f\x7f-\xff])/sprintf("%%%02X", ord($1))/eg; 
+       $s = "'$s'" if $s =~ / /;
        return $s;
 }
 
 sub tdecode
 {
        my $s = shift;
+       $s =~ s/^'(.*)'$/$1/;
        $s =~ s/\%([0-9A-F][0-9A-F])/chr(hex($1))/eg;
        return $s;
 }
@@ -194,39 +270,167 @@ sub genmsg
        return "$head|$data";
 }
 
+
+sub decode_input
+{
+       my $self = shift;
+       my $line = shift;
+       return ('I', $self->{call}, $line);
+}
+
 sub input
 {
        my $line = shift;
        my ($head, $data) = split /\|/, $line, 2;
        return unless $head && $data;
+
        my ($origin, $group, $dts, $hop, $user) = split /,/, $head;
-       return if DXDupe::add("Ara,$origin,$dts", $dupeage);
-       $hop++;
+       return if DXDupe::check("Ara,$origin,$dts", $dupeage);
+       my $err;
+       $err .= "incomplete header," unless $origin && defined $group && $dts && defined $hop;
        my ($cmd, $rdata) = split /,/, $data, 2;
-       my $class = 'Thingy::' . ucfirst $cmd;
+
+       # validate it further
+       $err .= "missing cmd or data," unless $cmd && $data;
+       $err .= "invalid command ($cmd)," unless $cmd =~ /^[A-Z][A-Z0-9]*$/;
+       $err .= "invalid group ($group)," unless $group =~ /^[-A-Z0-9\/:]{2,}$/;
+
+       my $class = 'Thingy::' . ucfirst(lc $cmd);
        my $thing;
+       my ($t, $seqno, $ntp) = decode_dts($dts) unless $err;
+       $err .= "invalid date/seq," unless $t;
        
-       # create the appropriate Thingy
-       if (defined *$class) {
+       if ($err) {
+               chop $err;
+               dbg("Aranea input: $err");
+       } elsif ($class->can('new')) {
+               # create the appropriate Thingy
                $thing = $class->new();
 
                # reconstitute the header but wth hop increased by one
-               $head = join(',', $origin, $group, $dts, $hop);
+               $head = join(',', $origin, $group, $dts, ++$hop);
                $head .= ",$user" if $user;
                $thing->{Aranea} = "$head|$data";
 
                # store useful data
                $thing->{origin} = $origin;
-               $thing->{group} = $group;
-               $thing->{time} = decode_dts($dts);
+               ($thing->{group}, $thing->{touser}) = split /:/, $group, 2;
+               $thing->{time} = $t;
                $thing->{user} = $user if $user;
                $thing->{hopsaway} = $hop; 
                
-               while (my ($k,$v) = split /,/, $rdata) {
-                       $thing->{$k} = tdecode($v);
+               for (split(/,/, $rdata)) {
+                       if (/=/) {
+                               my ($k,$v) = split /=/, $_, 2;
+                               $thing->{$k} = tdecode($v);
+                       } else {
+                               $thing->{$_} = 1;
+                       }
+               }
+
+               # post process the thing, this generally adds on semantic meaning
+               # does parameter checking etc. It also adds / prepares the thingy so
+               # this is compatible with older protocol and arranges data so
+               # that the filtering can still work.
+               if ($thing->can('from_Aranea')) {
+
+                       # if a thing is ok then return that thing, otherwise return
+                       # nothing
+                       $thing = $thing->from_Aranea;
                }
        }
        return $thing;
 }
 
+# this is the DXChannel send
+# note that this does NOT send out stuff in same way as other DXChannels
+# it is just as it comes, no extra bits added (here)
+sub send                                               # this is always later and always data
+{
+       my $self = shift;
+       my $conn = $self->{conn};
+       return unless $conn;
+       my $call = $self->{call};
+
+       for (@_) {
+#              chomp;
+        my @lines = split /\n/;
+               for (@lines) {
+                       $conn->send_later($_);
+                       dbg("-> D $call $_") if isdbg('chan');
+               }
+       }
+       $self->{t} = $main::systime;
+}
+
+#
+# load of dummies for DXChannel broadcasts
+# these will go away in time?
+# These are all from PC protocol
+#
+
+sub dx_spot
+{
+       my $self = shift;
+       my $line = shift;
+       my $isolate = shift;
+       my ($filter, $hops);
+
+       if ($self->{spotsfilter}) {
+               ($filter, $hops) = $self->{spotsfilter}->it(@_);
+               return unless $filter;
+       }
+#      send_prot_line($self, $filter, $hops, $isolate, $line);
+}
+
+sub wwv
+{
+       my $self = shift;
+       my $line = shift;
+       my $isolate = shift;
+       my ($filter, $hops);
+       
+       if ($self->{wwvfilter}) {
+               ($filter, $hops) = $self->{wwvfilter}->it(@_);
+               return unless $filter;
+       }
+#      send_prot_line($self, $filter, $hops, $isolate, $line)
+}
+
+sub wcy
+{
+       my $self = shift;
+       my $line = shift;
+       my $isolate = shift;
+       my ($filter, $hops);
+
+       if ($self->{wcyfilter}) {
+               ($filter, $hops) = $self->{wcyfilter}->it(@_);
+               return unless $filter;
+       }
+#      send_prot_line($self, $filter, $hops, $isolate, $line) if $self->is_clx || $self->is_spider || $self->is_dxnet;
+}
+
+sub announce
+{
+       my $self = shift;
+       my $line = shift;
+       my $isolate = shift;
+       my $to = shift;
+       my $target = shift;
+       my $text = shift;
+       my ($filter, $hops);
+
+       if ($self->{annfilter}) {
+               ($filter, $hops) = $self->{annfilter}->it(@_);
+               return unless $filter;
+       }
+#      send_prot_line($self, $filter, $hops, $isolate, $line) unless $_[1] eq $main::mycall;
+}
+
+sub chat
+{
+       goto &announce;
+}
+
 1;
index acd4245c6cddebd8edcfd2aa6ccffd6a5c2beaab..696544293791e147552aff791992eb50a5df9d0c 100644 (file)
@@ -266,7 +266,7 @@ sub is_bbs
 sub is_node
 {
        my $self = shift;
-       return $self->{'sort'} =~ /[ACRSXW]/;
+       return $self->{'sort'} =~ /[ACRSX]/;
 }
 # is it an ak1a node ?
 sub is_ak1a
index debc23d2af1dddc01fc1b5f4ed1aafd4c05896fe..276b346b64447a4d6efe2abf293b56439d1f5f21 100644 (file)
@@ -35,6 +35,8 @@ use Net::Telnet;
 use QSL;
 use DB_File;
 use VE7CC;
+use Thingy;
+use Thingy::Dx;
 
 use strict;
 use vars qw(%Cache %cmd_cache $errstr %aliases $scriptbase $maxerrors %nothereslug $maxbadcount $msgpolltime);
@@ -847,14 +849,15 @@ sub chat
 sub format_dx_spot
 {
        my $self = shift;
-
-       my $t = ztime($_[2]);
+       my $spot = ref $_[0] ? shift : \@_;
+       
+       my $t = ztime($spot->[2]);
        my $loc = '';
        my $clth = $self->{consort} eq 'local' ? 29 : 30;
-       my $comment = substr $_[3], 0, $clth; 
+       my $comment = substr $spot->[3], 0, $clth; 
        $comment .= ' ' x ($clth - length($comment));
        if ($self->{user}->wantgrid) { 
-               my $ref = DXUser->get_current($_[4]);
+               my $ref = DXUser->get_current($spot->[4]);
                if ($ref) {
                        $loc = $ref->qra || '';
                        $loc = ' ' . substr($loc, 0, 4) if $loc;
@@ -862,17 +865,17 @@ sub format_dx_spot
        }
 
        if ($self->{user}->wantdxitu) {
-               $loc = ' ' . sprintf("%2d", $_[10]) if defined $_[10];
-               $comment = substr($comment, 0,  $self->{consort} eq 'local' ? 26 : 27) . ' ' . sprintf("%2d", $_[8]) if defined $_[8]; 
+               $loc = ' ' . sprintf("%2d", $spot->[10]) if defined $spot->[10];
+               $comment = substr($comment, 0,  $self->{consort} eq 'local' ? 26 : 27) . ' ' . sprintf("%2d", $spot->[8]) if defined $spot->[8]; 
        } elsif ($self->{user}->wantdxcq) {
-               $loc = ' ' . sprintf("%2d", $_[11]) if defined $_[11];
-               $comment = substr($comment, 0,  $self->{consort} eq 'local' ? 26 : 27) . ' ' . sprintf("%2d", $_[9]) if defined $_[9]; 
+               $loc = ' ' . sprintf("%2d", $spot->[11]) if defined $spot->[11];
+               $comment = substr($comment, 0,  $self->{consort} eq 'local' ? 26 : 27) . ' ' . sprintf("%2d", $spot->[9]) if defined $spot->[9]; 
        } elsif ($self->{user}->wantusstate) {
-               $loc = ' ' . $_[13] if $_[13];
-               $comment = substr($comment, 0,  $self->{consort} eq 'local' ? 26 : 27) . ' ' . $_[12] if $_[12]; 
+               $loc = ' ' . $spot->[13] if $spot->[13];
+               $comment = substr($comment, 0,  $self->{consort} eq 'local' ? 26 : 27) . ' ' . $spot->[12] if $spot->[12]; 
        }
 
-       return sprintf "DX de %-7.7s%11.1f  %-12.12s %-s $t$loc", "$_[4]:", $_[0], $_[1], $comment;
+       return sprintf "DX de %-7.7s%11.1f  %-12.12s %-s $t$loc", "$spot->[4]:", $spot->[0], $spot->[1], $comment;
 }
 
 # send a dx spot
index 416dea0a9e79caadb7e923c2e2d2585b5ca04f09..30fe2b25d4dee2f6cd1383c674dca655be6f12f3 100644 (file)
@@ -11,7 +11,7 @@ package DXDebug;
 
 require Exporter;
 @ISA = qw(Exporter);
-@EXPORT = qw(dbginit dbg dbgadd dbgsub dbglist dbgdump isdbg dbgclose confess croak cluck);
+@EXPORT = qw(dbginit dbg dbgadd dbgsub dbglist dbgdump dbglog isdbg dbgclose confess croak cluck);
 
 use strict;
 use vars qw(%dbglevel $fp $callback $cleandays $keepdays);
@@ -186,6 +186,13 @@ sub dbgclean
        }
 }
 
+sub dbglog
+{
+       my $sort = shift;
+       my $l = shift;
+       dbg($l);
+       DXLog::Log($sort, $l);
+}
 1;
 __END__
 
index 5e324fa47f2af7656ebbff28e7fbcccadb834557..5580a2bee408fb954168a7ef6d4dc410683c0a30 100644 (file)
@@ -35,7 +35,8 @@ use Route::Node;
 use Script;
 use Investigate;
 use RouteDB;
-
+use Thingy;
+use Thingy::Dx;
 
 use strict;
 
@@ -219,7 +220,7 @@ sub init
        $main::me->{metric} = 0;
        $main::me->{pingave} = 0;
        $main::me->{registered} = 1;
-       $main::me->{version} = $main::version;
+       $main::me->{version} = 5251 + $main::version;
        $main::me->{build} = $main::build;
 }
 
@@ -323,20 +324,6 @@ sub sendinit
        $self->send(pc18());
 }
 
-sub removepc90
-{
-       $_[0] =~ s/^PC90\^[-A-Z0-9]+\^\d+\^//;
-       $_[0] =~ s/^PC91\^[-A-Z0-9]+\^\d+\^[-A-Z0-9]+\^//;
-}
-
-#sub send
-#{
-#      my $self = shift;
-#      while (@_) {
-#              my $line = shift;
-#              $self->SUPER::send($line);
-#      }
-#}
 
 #
 # This is the normal pcxx despatcher
@@ -345,9 +332,6 @@ sub normal
 {
        my ($self, $line) = @_;
 
-       # remove any incoming PC90 frames
-       removepc90($line);
-
        my @field = split /\^/, $line;
        return unless @field;
        
@@ -355,7 +339,6 @@ sub normal
        
 #      print join(',', @field), "\n";
                                                
-       
        # process PC frames, this will fail unless the frame starts PCnn
        my ($pcno) = $field[0] =~ /^PC(\d\d)/; # just get the number
        unless (defined $pcno && $pcno >= 10 && $pcno <= 99) {
@@ -370,6 +353,16 @@ sub normal
                return;
        }
 
+       # decrement any hop fields at this point
+       if ($line =~ /\^H(\d\d?)\^?~?$/) {
+               my $hops = $1 - 1;
+               if ($hops < 0) {
+                       dbg("PCPROT: zero hop count, dumped") if isdbg('chanerr');
+                       return;
+               }
+               $line =~ s/\^H\d\d?(\^?~?)$/^H$hops$1/;
+       }
+
        my $origin = $self->{call};
        no strict 'subs';
        my $sub = "handle_$pcno";
@@ -434,7 +427,7 @@ sub handle_10
        }
 
        # remember a route to this node and also the node on which this user is
-       RouteDB::update($_[6], $self->{call});
+       RouteDB::update($_[6], $origin);
 #      RouteDB::update($to, $_[6]);
 
        # it is here and logged on
@@ -536,26 +529,14 @@ sub handle_11
 #      RouteDB::update($_[6], $_[7]);
        
        my @spot = Spot::prepare($_[1], $_[2], $d, $_[5], $_[6], $_[7]);
-       # global spot filtering on INPUT
-       if ($self->{inspotsfilter}) {
-               my ($filter, $hops) = $self->{inspotsfilter}->it(@spot);
-               unless ($filter) {
-                       dbg("PCPROT: Rejected by input spot filter") if isdbg('chanerr');
-                       return;
-               }
-       }
+
+       my $thing = Thingy::Dx->new(origin=>$main::mycall, group=>'DX');
+       $thing->from_DXProt(DXProt=>$line,spotdata=>\@spot);
+       $thing->queue($self);
 
        # this goes after the input filtering, but before the add
        # so that if it is input filtered, it isn't added to the dup
        # list. This allows it to come in from a "legitimate" source
-       if (Spot::dup($_[1], $_[2], $d, $_[5], $_[6])) {
-               dbg("PCPROT: Duplicate Spot ignored\n") if isdbg('chanerr');
-               return;
-       }
-
-       # add it 
-       Spot::add(@spot);
-
        #
        # @spot at this point contains:-
        # freq, spotted call, time, text, spotter, spotted cc, spotters cc, orig node
@@ -622,7 +603,7 @@ sub handle_11
        return if $pcno == 26;
 
        # send out the filtered spots
-       send_dx_spot($self, $line, @spot) if @spot;
+#      send_dx_spot($self, $line, @spot) if @spot;
 }
                
 # announces
@@ -714,7 +695,7 @@ sub handle_16
                        
        # dos I want users from this channel?
        unless ($self->user->wantpc16) {
-               dbg("PCPROT: don't send users to $self->{call}") if isdbg('chanerr');
+               dbg("PCPROT: don't send users to $origin") if isdbg('chanerr');
                return;
        }
        # is it me?
@@ -723,14 +704,14 @@ sub handle_16
                return;
        }
 
-       RouteDB::update($ncall, $self->{call});
+       RouteDB::update($ncall, $origin);
 
        # do we believe this call? 
-       unless ($ncall eq $self->{call} || $self->is_believed($ncall)) {
-               if (my $ivp = Investigate::get($ncall, $self->{call})) {
+       unless ($ncall eq $origin || $self->is_believed($ncall)) {
+               if (my $ivp = Investigate::get($ncall, $origin)) {
                        $ivp->store_pcxx($pcno,$line,$origin,@_);
                } else {
-                       dbg("PCPROT: We don't believe $ncall on $self->{call}") if isdbg('chanerr');
+                       dbg("PCPROT: We don't believe $ncall on $origin") if isdbg('chanerr');
                }
                return;
        }
@@ -770,7 +751,7 @@ sub handle_16
                                                $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');
+                                                       dbg("PCPROT: PC19 from $origin trying to alter locally connected $ncall, ignored!") if isdbg('chanerr');
                                                        $parent = undef;
                                                }
                                                if ($parent) {
@@ -802,7 +783,7 @@ sub handle_16
                                
                $dxchan = $parent->dxchan;
                if ($dxchan && $dxchan ne $self) {
-                       dbg("PCPROT: PC16 from $self->{call} trying to alter locally connected $ncall, ignored!") if isdbg('chanerr');
+                       dbg("PCPROT: PC16 from $origin trying to alter locally connected $ncall, ignored!") if isdbg('chanerr');
                        return;
                }
 
@@ -871,7 +852,7 @@ sub handle_17
                        
        # do I want users from this channel?
        unless ($self->user->wantpc16) {
-               dbg("PCPROT: don't send users to $self->{call}") if isdbg('chanerr');
+               dbg("PCPROT: don't send users to $origin") if isdbg('chanerr');
                return;
        }
        if ($ncall eq $main::mycall) {
@@ -879,14 +860,14 @@ sub handle_17
                return;
        }
 
-       RouteDB::delete($ncall, $self->{call});
+       RouteDB::delete($ncall, $origin);
 
        # do we believe this call? 
-       unless ($ncall eq $self->{call} || $self->is_believed($ncall)) {
-               if (my $ivp = Investigate::get($ncall, $self->{call})) {
+       unless ($ncall eq $origin || $self->is_believed($ncall)) {
+               if (my $ivp = Investigate::get($ncall, $origin)) {
                        $ivp->store_pcxx($pcno,$line,$origin,@_);
                } else {
-                       dbg("PCPROT: We don't believe $ncall on $self->{call}") if isdbg('chanerr');
+                       dbg("PCPROT: We don't believe $ncall on $origin") if isdbg('chanerr');
                }
                return;
        }
@@ -902,7 +883,7 @@ sub handle_17
 
        $dxchan = $parent->dxchan if $parent;
        if ($dxchan && $dxchan ne $self) {
-               dbg("PCPROT: PC17 from $self->{call} trying to alter locally connected $ncall, ignored!") if isdbg('chanerr');
+               dbg("PCPROT: PC17 from $origin trying to alter locally connected $ncall, ignored!") if isdbg('chanerr');
                return;
        }
 
@@ -934,8 +915,8 @@ 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->version(52.51 + $1);
+               $self->user->version(52.51 + $1);
                $self->build(0 + $2);
                $self->user->build(0 + $2);
                unless ($self->is_spider) {
@@ -950,7 +931,7 @@ sub handle_18
        }
 
        # first clear out any nodes on this dxchannel
-       my $parent = Route::Node::get($self->{call});
+       my $parent = Route::Node::get($origin);
        my @rout = $parent->del_nodes;
        $self->route_pc21($origin, $line, @rout, $parent) if @rout;
        $self->send_local_config();
@@ -972,9 +953,9 @@ sub handle_19
        my @rout;
 
        # first get the INTERFACE node
-       my $parent = Route::Node::get($self->{call});
+       my $parent = Route::Node::get($origin);
        unless ($parent) {
-               dbg("DXPROT: my parent $self->{call} has disappeared");
+               dbg("DXPROT: my parent $origin has disappeared");
                $self->disconnect;
                return;
        }
@@ -1018,7 +999,7 @@ sub handle_19
                # 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');
+                       dbg("PCPROT: PC19 from $origin trying to alter wrong locally connected $call, ignored!") if isdbg('chanerr');
                        next;
                }
 
@@ -1033,19 +1014,19 @@ sub handle_19
                }
                $user->sort('A') unless $user->is_node;
 
-               RouteDB::update($call, $self->{call});
+               RouteDB::update($call, $origin);
 
                # 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});
+               unless ($call eq $origin || $self->is_believed($call)) {
+                       my $pt = $user->lastping($origin) || 0;
+                       if ($pt+$investigation_int < $main::systime && !Investigate::get($call, $origin)) {
+                               my $ivp  = Investigate->new($call, $origin);
                                $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');
+                               dbg("PCPROT: We don't believe $call on $origin") if isdbg('chanerr');
                        }
                        $user->put;
                        next;
@@ -1078,7 +1059,7 @@ sub handle_19
                } else {
 
                        # if he is directly connected or allowed then add him, otherwise store him up for later
-                       if ($call eq $self->{call} || $user->wantroutepc19) {
+                       if ($call eq $origin || $user->wantroutepc19) {
                                my $new = Route->new($call); # throw away
                                if ($self->in_filter_route($new)) {
                                        my $ar = $parent->add($call, $ver, $flags);
@@ -1090,7 +1071,7 @@ sub handle_19
                        } 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;
+                               push @{$pc19list{$call}}, [$origin, $ver, $flags] unless grep $_->[0] eq $origin, @$nl;
                        }
                }
 
@@ -1137,14 +1118,14 @@ sub handle_21
                return;
        }
 
-       RouteDB::delete($call, $self->{call});
+       RouteDB::delete($call, $origin);
 
        # check if we believe this
-       unless ($call eq $self->{call} || $self->is_believed($call)) {
-               if (my $ivp = Investigate::get($call, $self->{call})) {
+       unless ($call eq $origin || $self->is_believed($call)) {
+               if (my $ivp = Investigate::get($call, $origin)) {
                        $ivp->store_pcxx($pcno,$line,$origin,@_);
                } else {
-                       dbg("PCPROT: We don't believe $call on $self->{call}") if isdbg('chanerr');
+                       dbg("PCPROT: We don't believe $call on $origin") if isdbg('chanerr');
                }
                return;
        }
@@ -1153,13 +1134,13 @@ sub handle_21
        # 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 ];
+               $pc19list{$call} = [ grep {$_->[0] ne $origin} @$nl ];
                delete $pc19list{$call} unless @{$pc19list{$call}};
        } else {
                                
-               my $parent = Route::Node::get($self->{call});
+               my $parent = Route::Node::get($origin);
                unless ($parent) {
-                       dbg("DXPROT: my parent $self->{call} has disappeared");
+                       dbg("DXPROT: my parent $origin has disappeared");
                        $self->disconnect;
                        return;
                }
@@ -1169,7 +1150,7 @@ sub handle_21
                                                
                                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');
+                                       dbg("PCPROT: PC21 from $origin trying to alter locally connected $call, ignored!") if isdbg('chanerr');
                                        return;
                                }
                                                
@@ -1399,7 +1380,7 @@ sub handle_39
        my $pcno = shift;
        my $line = shift;
        my $origin = shift;
-       if ($_[1] eq $self->{call}) {
+       if ($_[1] eq $origin) {
                $self->disconnect(1);
        } else {
                dbg("PCPROT: came in on wrong channel") if isdbg('chanerr');
@@ -1515,11 +1496,11 @@ sub handle_50
 
        my $call = $_[1];
 
-       RouteDB::update($call, $self->{call});
+       RouteDB::update($call, $origin);
 
        my $node = Route::Node::get($call);
        if ($node) {
-               return unless $node->call eq $self->{call};
+               return unless $node->call eq $origin;
                $node->usercount($_[2]);
 
                # input filter if required
@@ -1577,11 +1558,11 @@ sub handle_51
                                                                $tochan->{pingave} = $tochan->{pingave} + (($t - $tochan->{pingave}) / 6);
                                                        }
                                                        $tochan->{nopings} = $nopings; # pump up the timer
-                                                       if (my $ivp = Investigate::get($from, $self->{call})) {
+                                                       if (my $ivp = Investigate::get($from, $origin)) {
                                                                $ivp->handle_ping;
                                                        }
                                                } elsif (my $rref = Route::Node::get($r->{call})) {
-                                                       if (my $ivp = Investigate::get($from, $self->{call})) {
+                                                       if (my $ivp = Investigate::get($from, $origin)) {
                                                                $ivp->handle_ping;
                                                        }
                                                }
@@ -1591,7 +1572,7 @@ sub handle_51
                }
        } else {
 
-               RouteDB::update($from, $self->{call});
+               RouteDB::update($from, $origin);
 
                if (eph_dup($line)) {
                        dbg("PCPROT: dup PC51 detected") if isdbg('chanerr');
@@ -2160,7 +2141,7 @@ sub adjust_hops
                        $s =~ s/\^H(\d+)(\^~?)$/\^H$newhops$2/ if $newhops;
                } else {
                        # simply decrement it
-                       $hops--;
+#                      $hops--;               this is done on receipt now
                        return "" if !$hops;
                        $s =~ s/\^H(\d+)(\^~?)$/\^H$hops$2/ if $hops;
                }
index a5f6bc433b677fc3ac126e105fe56c578e97eb3c..98fd201fe0cf07a20f2bd6168a1bff4fd5d89c9d 100644 (file)
@@ -15,7 +15,7 @@ package DXProt;
 $pc50_interval = 14*60;
 
 # the version of DX cluster (tm) software I am masquerading as
-$myprot_version = 5300;
+$myprot_version = 5251;
 
 # default hopcount to use
 $def_hopcount = 30;
index a5498a0c8a45568675d23eb7fc5fea38094dd3e3..a8a609b96d76cfbdc2024d49453477f35d792161 100644 (file)
@@ -123,7 +123,8 @@ sub pc17
 # Request init string
 sub pc18
 {
-       return "PC18^DXSpider Version: $main::version Build: $main::build^$DXProt::myprot_version^";
+       my $v = $DXProt::myprot_version + $main::version;
+       return "PC18^DXSpider Version: $main::version Build: $main::build^$v^";
 }
 
 #
index 133a1513acdef46cba5bb2cefc808f601e104716..f08a07c919f1fed68b2c2a95f0c4fadcf5d36cae 100644 (file)
@@ -159,7 +159,7 @@ sub to_connected
        delete $conn->{timeout};
        $conn->nolinger;
        &{$conn->{rproc}}($conn, "$dir$call|$sort");
-       $conn->_send_file("$main::data/connected") unless $conn->{outgoing};
+       $conn->_send_file("$main::data/connected") unless $conn->{outbound};
 }
 
 sub new_client {
@@ -212,12 +212,9 @@ sub start_connect
        my $call = shift;
        my $fn = shift;
        my $conn = ExtMsg->new(\&main::new_channel); 
-       $conn->{outgoing} = 1;
+       $conn->{outbound} = 1;
        $conn->conns($call);
-       
-       my $f = new IO::File $fn;
-       push @{$conn->{cmd}}, <$f>;
-       $f->close;
+       push @{$conn->{cmd}}, @_;
        $conn->{state} = 'WC';
        $conn->_dotimeout($deftimeout);
        $conn->_docmd;
@@ -264,11 +261,17 @@ sub _doconnect
        dbg("CONNECT $conn->{cnum} sort: $sort command: $line") if isdbg('connect');
        if ($sort eq 'telnet') {
                # this is a straight network connect
-               my ($host, $port) = split /\s+/, $line;
+               my ($host, $port, $type) = split /\s+/, $line;
+               if ($type && ref($conn) ne $type) {
+                       bless $conn, $type;
+                       $conn->set_newchannel_rproc;
+                       dbg("$conn->{cnum} to $host $port reblessed as $type") if isdbg('connect');
+               }
                $port = 23 if !$port;
                $r = $conn->connect($host, $port);
                if ($r) {
                        dbg("Connected $conn->{cnum} to $host $port") if isdbg('connect');
+
                } else {
                        dbg("***Connect $conn->{cnum} Failed to $host $port $!") if isdbg('connect');
                }
index 4443fc5570ac2360d40af67587c5d10f028aeec4..ff4ab2e868e95aff35aa6014edaa2018c98045c5 100644 (file)
@@ -198,6 +198,7 @@ sub it
        my $key;
        my $type = 'Dunno';
        my $asc = '?';
+       my $data = ref $_[0] ? shift : \@_;
 
        my $r = @keys > 0 ? 0 : 1;
        foreach $key (@keys) {
@@ -205,7 +206,7 @@ sub it
                if ($filter->{reject} && exists $filter->{reject}->{code}) {
                        $type = 'reject';
                        $asc = $filter->{reject}->{user};
-                       if (&{$filter->{reject}->{code}}(\@_)) {
+                       if (&{$filter->{reject}->{code}}($data)) {
                                $r = 0;
                                last;
                        } else {
@@ -215,7 +216,7 @@ sub it
                if ($filter->{accept} && exists $filter->{accept}->{code}) {
                        $type = 'accept';
                        $asc = $filter->{accept}->{user};
-                       if (&{$filter->{accept}->{code}}(\@_)) {
+                       if (&{$filter->{accept}->{code}}($data)) {
                                $r = 1;
                                last;
                        } else {
@@ -228,7 +229,7 @@ sub it
        my $hops = $self->{hops} if exists $self->{hops};
 
        if (isdbg('filter')) {
-               my $args = join '\',\'', map {defined $_ ? $_ : 'undef'} @_;
+               my $args = join '\',\'', map {defined $_ ? $_ : 'undef'} @$data;
                my $true = $r ? "OK " : "REJ";
                my $sort = $self->{sort};
                my $dir = $self->{name} =~ /^in_/i ? "IN " : "OUT";
index 8708ac4df79e953639ea5851bb7d7b97768f1fa8..e918c0c6c711b7a09522ae023bf75bb043552d2c 100644 (file)
@@ -122,7 +122,7 @@ sub prepare
        $out[4] =~ s/-\d+$//o;
 
        # remove leading and trailing spaces
-       $_[3] = unpad($_[3]);
+       unpad($out[3]);
        
        
        # add the 'dxcc' country on the end for both spotted and spotter, then the cluster call
index 61068e06b2f7e5df80cd4275b33627eca633edd6..c358389fd0318f1f96632f52e06553d41089d97f 100644 (file)
@@ -2,6 +2,9 @@
 # Thingy handling
 #
 # This is the new fundamental protocol engine handler
+# 
+# This is where all the new things (and eventually all the old things
+# as well) happen.
 #
 # $Id$
 #
@@ -12,12 +15,27 @@ use strict;
 
 package Thingy;
 
-use vars qw($VERSION $BRANCH);
+use vars qw($VERSION $BRANCH @queue @permin @persec);
 $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;
 
+@queue = ();                                   # the input / processing queue
+
+#
+# these are set up using the Thingy->add_second_process($addr, $name)
+# and Thingy->add_minute_process($addr, $name)
+#
+# They replace the old cycle in cluster.pl
+#
+
+@persec = ();                                  # this replaces the cycle in cluster.pl
+@permin = ();                                  # this is an extra per minute cycle
+
+my $lastsec = time;
+my $lastmin = time;
+
 use DXChannel;
 use DXDebug;
 
@@ -35,12 +53,17 @@ sub new
 sub send
 {
        my $thing = shift;
-       my $chan = shift;
+       my $dxchan = shift;
        my $class;
        if (@_) {
                $class = shift;
-       } elsif ($chan->isa('DXChannel')) {
-               $class = ref $chan;
+       } elsif ($dxchan->isa('DXChannel')) {
+               $class = ref $dxchan;
+       }
+
+       # do output filtering
+       if ($thing->can('out_filter')) {
+               return unless $thing->out_filter;
        }
 
        # generate the line which may (or not) be cached
@@ -50,11 +73,92 @@ sub send
        } else {
                no strict 'refs';
                my $sub = "gen_$class";
-               push @out, $thing->$sub() if $thing->can($sub);
+               push @out, $thing->$sub($dxchan) if $thing->can($sub);
+       }
+       $dxchan->send(@out) if @out;
+}
+
+# broadcast to all except @_
+sub broadcast
+{
+       my $thing = shift;
+       dbg("Thingy::broadcast: " . $thing->ascii) if isdbg('thing'); 
+
+       foreach my $dxchan (DXChannel::get_all()) {
+               next if $dxchan == $main::me;
+               next if grep $dxchan == $_, @_;
+               $thing->send($dxchan); 
+       }
+}
+
+# queue this thing for processing
+sub queue
+{
+       my $thing = shift;
+       my $dxchan = shift;
+       $thing->{dxchan} = $dxchan->call;
+       push @queue, $thing;
+}
+
+# this is the main commutator loop. In due course it will
+# become the *only* commutator loop
+sub process
+{
+       my $thing;
+       while (@queue) {
+               $thing = shift @queue;
+               my $dxchan = DXChannel->get($thing->{dxchan});
+               if ($dxchan) {
+                       if ($thing->can('in_filter')) {
+                               next unless $thing->in_filter($dxchan);
+                       }
+                       $thing->handle($dxchan);
+               }
+       }
+
+       # per second and per minute processing
+       if ($main::systime != $lastsec) {
+               if ($main::systime >= $lastmin+60) {
+                       foreach my $r (@permin) {
+                               &{$r->[0]}();
+                       }
+                       $lastmin = $main::systime;
+               }
+               foreach my $r (@persec) {
+                       &{$r->[0]}();
+               }
+               $lastsec = $main::systime;
        }
-       $chan->send(@out) if @out;
 }
 
+sub add_minute_process
+{
+       my $pkg = shift;
+       my $addr = shift;
+       my $name = shift;
+       dbg('Adding $name to Thingy per minute queue');
+       push @permin, [$addr, $name];
+}
+
+sub add_second_process
+{
+       my $pkg = shift;
+       my $addr = shift;
+       my $name = shift;
+       dbg('Adding $name to Thingy per second queue');
+       push @persec, [$addr, $name];
+}
 
+
+sub ascii
+{
+       my $thing = shift;
+       my $dd = new Data::Dumper([$thing]);
+       $dd->Indent(0);
+       $dd->Terse(1);
+       $dd->Sortkeys(1);
+    $dd->Quotekeys($] < 5.005 ? 1 : 0);
+       return $dd->Dumpxs;
+}
 1;
 
diff --git a/perl/Thingy/Dx.pm b/perl/Thingy/Dx.pm
new file mode 100644 (file)
index 0000000..9b7a181
--- /dev/null
@@ -0,0 +1,158 @@
+#
+# Dx Thingy handling
+#
+# $Id$
+#
+# Copyright (c) 2005 Dirk Koopman G1TLH
+#
+
+use strict;
+
+package Thingy::Dx;
+
+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 DXChannel;
+use DXDebug;
+use DXUtil;
+use Thingy;
+use Spot;
+
+use vars qw(@ISA);
+@ISA = qw(Thingy);
+
+sub gen_Aranea
+{
+       my $thing = shift;
+       unless ($thing->{Aranea}) {
+               my $sd = $thing->{spotdata};
+               my @items = (
+                                        f=>$sd->[0],
+                                        c=>$sd->[1],
+                                       );
+               push @items, ('b', $sd->[4]) unless $thing->{user};
+               push @items, ('st', sprintf("%X", $sd->[2] / 60), 'o', $sd->[7]) unless $sd->[7] eq $main::mycall;
+               push @items, ('i', $sd->[3]) if $sd->[3];
+               $thing->{Aranea} = Aranea::genmsg($thing, 'DX', @items);
+       }
+       return $thing->{Aranea};
+}
+
+sub from_Aranea
+{
+       my $thing = shift;
+       return unless $thing;
+       my $t = hex($thing->{st}) if exists $thing->{st};
+       $t ||= $thing->{time} / 60;
+       my @spot = Spot::prepare(
+                                                        $thing->{f},
+                                                        $thing->{c},
+                                                        $t*60,
+                                                        ($thing->{i} || ''),
+                                                        ($thing->{b} || $thing->{fromuser} || $thing->{user} || $thing->{origin}),
+                                                        ($thing->{o} || $thing->{origin}),
+                                                       );
+       $thing->{spotdata} = \@spot;
+       return $thing;
+}
+
+sub gen_DXProt
+{
+       my $thing = shift;
+       unless ($thing->{DXProt}) {
+               my $sd = $thing->{spotdata};
+               my $hops = $thing->{hops} || DXProt::get_hops(11);
+               my $text = $sd->[3] || ' ';
+               $text =~ s/\^/%5E/g;
+               my $t = $sd->[2];
+               $thing->{DXProt} = sprintf "PC11^%.1f^$sd->[1]^%s^%s^$text^$sd->[4]^$sd->[7]^$hops^~", $sd->[0], cldate($t), ztime($t);
+       }
+       return $thing->{DXProt};
+}
+
+sub gen_DXCommandmode
+{
+       my $thing = shift;
+       my $dxchan = shift;
+       
+       # these are always generated, never cached
+       return unless $dxchan->{dx};
+       
+       my $buf;
+       if ($dxchan->{ve7cc}) {
+               $buf = VE7CC::dx_spot($dxchan, $thing->{spotdata});
+       } else {
+               $buf = $dxchan->format_dx_spot($thing->{spotdata});
+               $buf .= "\a\a" if $dxchan->{beep};
+               $buf =~ s/\%5E/^/g;
+       }
+       return $buf;
+}
+
+sub from_DXProt
+{
+       my $thing = shift;
+       while (@_) {
+               my $k = shift;
+               $thing->{$k} = shift;
+       }
+       ($thing->{hops}) = $thing->{DXProt} =~ /\^H(\d+)\^?~?$/ if exists $thing->{DXProt};
+       return $thing;
+}
+
+sub handle
+{
+       my $thing = shift;
+       my $dxchan = shift;
+
+       my $spot = $thing->{spotdata};
+       if (Spot::dup(@$spot[0..4])) {
+               dbg("PCPROT: Duplicate Spot ignored\n") if isdbg('chanerr');
+               return;
+       }
+
+       # add it 
+       Spot::add(@$spot);
+
+       $thing->broadcast($dxchan);
+}
+
+sub in_filter
+{
+       my $thing = shift;
+       my $dxchan = shift;
+       
+       # global spot filtering on INPUT
+       if ($dxchan->{inspotsfilter}) {
+               my ($filter, $hops) = $dxchan->{inspotsfilter}->it($thing->{spotdata});
+               unless ($filter) {
+                       dbg("PCPROT: Rejected by input spot filter") if isdbg('chanerr');
+                       return;
+               }
+       }
+       return 1;
+}
+
+sub out_filter
+{
+       my $thing = shift;
+       my $dxchan = shift;
+       
+       # global spot filtering on INPUT
+       if ($dxchan->{inspotsfilter}) {
+               my ($filter, $hops) = $dxchan->{inspotsfilter}->it($thing->{spotdata});
+               unless ($filter) {
+                       dbg("PCPROT: Rejected by input spot filter") if isdbg('chanerr');
+                       return;
+               }
+               $thing->{hops} = $hops if $hops;
+       } elsif ($dxchan->{isolate}) {
+               return;
+       }
+       return 1;
+}
+1;
index 111abf8b2a46cc48e05ff1b60a025193055b6d28..f2d2d5d1a27b7545efa203336c250dcef28fdc34 100644 (file)
@@ -21,27 +21,57 @@ use DXDebug;
 use Verify;
 use Thingy;
 
-use vars qw(@ISA);
+use vars qw(@ISA $verify_on_login);
 @ISA = qw(Thingy);
 
+$verify_on_login = 1;                  # make sure that a HELLO coming from
+                                # the dxchan call is authentic
+
 sub gen_Aranea
 {
        my $thing = shift;
        unless ($thing->{Aranea}) {
-               my $auth = $thing->{auth} = Verify->new($main::mycall, $main::systime);
-               $thing->{Aranea} = Aranea::genmsg($thing, 'HELLO', sw=>'DXSpider',
+               my $s = sprintf "%X", int(rand() * 100000000);
+               my $auth = Verify->new("DXSp,$main::mycall,$s,$main::version,$main::build");
+               $thing->{Aranea} = Aranea::genmsg($thing, 'HELLO', sw=>'DXSp',
                                                                                  v=>$main::version,
                                                                                  b=>$main::build,
+                                                                                 's'=>$s,
                                                                                  auth=>$auth->challenge($main::me->user->passphrase)
                                                                          );
        }
        return $thing->{Aranea};
 }
 
-sub from_Aranea
+sub handle
 {
-       my $line = shift;
-       my $thing = Aranea::input($line);
-       return unless $thing;
+       my $thing = shift;
+       my $dxchan = shift;
+       
+       # verify authenticity
+       if ($dxchan->call eq $thing->{origin}) {
+               if ($verify_on_login) {
+                       my $pp = $dxchan->user->passphrase;
+                       unless ($pp) {
+                               dbglog('err', "Thingy::Hello::handle: verify on and $thing->{origin} has no passphrase");
+                               $dxchan->disconnect;
+                               return;
+                       }
+                       my $auth = Verify->new("DXSp,$thing->{origin},$thing->{s},$thing->{v},$thing->{b}");
+                       unless ($auth->verify($thing->{auth}, $dxchan->user->passphrase)) {
+                               dbglog('err', "Thingy::Hello::handle: verify on and $thing->{origin} failed auth check");
+                               $dxchan->disconnect;
+                               return;
+                       }
+               }
+               if ($dxchan->{state} ne 'normal') {
+                       $dxchan->start($dxchan->{conn}->{csort}, $dxchan->{conn}->{outbound} ? 'O' : 'A');
+                       if ($dxchan->{outbound}) {
+                               my $thing = Thingy::Hello->new(origin=>$main::mycall, group=>'ROUTE');
+                               $thing->send($dxchan);
+                       }
+               }
+       }
+       $thing->broadcast($dxchan);
 }
 1;
index 5e0fffe1d7e38e3a38927d23caf5f09b262b5a1d..849b2ed22e86b95e61f31c41a5a46618a21c4bee 100644 (file)
@@ -25,45 +25,31 @@ sub new
 {
        my $class = shift;
        my $self = bless {}, ref($class) || $class; 
-       if (@_) {
-               $self->newseed(@_);
-               $self->newsalt;
-       }
+       $self->newsalt(@_);
        return $self;
 }
 
-sub newseed
-{
-       my $self = shift;
-       return $self->{seed} = sha1_base64('RbG4tST2dYPWnh6bfAaq7pPSL04', @_);
-}
-
 sub newsalt
 {
        my $self = shift;
-       return $self->{salt} = substr sha1_base64($self->{seed}, rand, rand, rand), 0, 6;
+       return $self->{salt} = sha1_base64('RbG4tST2dYPWnh6bfAaq7pPSL04', @_);
 }
 
 sub challenge
 {
        my $self = shift;
-       return $self->{salt} . sha1_base64($self->{salt}, $self->{seed}, @_);
+       my $p = substr(sha1_base64($self->{salt}, @_), -6, 6);
+       return $p;
 }
 
 sub verify
 {
        my $self = shift;
        my $answer = shift;
-       my $p = sha1_base64($self->{salt}, $self->{seed}, @_);
+       my $p = substr(sha1_base64($self->{salt}, @_), -6, 6);
        return $p eq $answer;
 }
 
-sub seed
-{
-       my $self = shift;
-       return @_ ? $self->{seed} = shift : $self->{seed};
-}
-
 sub salt
 {
        my $self = shift;
index 1448ba9180a73748bf3faaa48cd131e47e884182..eea057db5c8efe318e11f6ce0c4e867a21e88de7 100755 (executable)
@@ -121,7 +121,7 @@ use vars qw(@inqueue $systime $version $starttime $lockfn @outstanding_connects
 
 @inqueue = ();                                 # the main input queue, an array of hashes
 $systime = 0;                                  # the time now (in seconds)
-$version = "1.51";                             # the version no of the software
+$version = "2.01";                             # the version no of the software
 $starttime = 0;                 # the starting time of the cluster   
 #@outstanding_connects = ();     # list of outstanding connects
 @listeners = ();                               # list of listeners
@@ -178,7 +178,7 @@ sub new_channel
                        already_conn($conn, $call, DXM::msg($lang, 'concluster', $call, $main::mycall));
                        return;
                }
-               if ($bumpexisting) {
+               if ($bumpexisting && $call ne $main::mycall) {
                        my $ip = $conn->{peerhost} || 'unknown';
                        $dxchan->send_now('D', DXM::msg($lang, 'conbump', $call, $ip));
                        Log('DXCommand', "$call bumped off by $ip, disconnected");
@@ -448,7 +448,7 @@ DXProt->init();
 Aranea->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)) {
@@ -491,11 +491,13 @@ for (;;) {
        my $timenow = time;
 
        DXChannel::process();
+       Thingy::process();
        
 #      $DB::trace = 0;
        
        # do timed stuff, ongoing processing happens one a second
        if ($timenow != $systime) {
+               rand();                                 # keep randomising to reduce (but not eliminate) predictability
                reap if $zombies;
                $systime = $timenow;
                DXCron::process();      # do cron jobs