2. Add full individual checking for all PC protocol fields in all messages
[spider.git] / perl / DXProt.pm
index 65ad93f930a1bcb164ea623c1fe4f15be8ed19a1..4f9e22202f88b044668590f58b06c0fd4339ac12 100644 (file)
@@ -34,7 +34,7 @@ use strict;
 use vars qw($me $pc11_max_age $pc23_max_age
                        $last_hour %pings %rcmds
                        %nodehops @baddx $baddxfn 
-                       $allowzero $decode_dk0wcy $send_opernam);
+                       $allowzero $decode_dk0wcy $send_opernam @checklist);
 
 $me = undef;                                   # the channel id for this cluster
 $pc11_max_age = 1*3600;                        # the maximum age for an incoming 'real-time' pc11
@@ -49,6 +49,121 @@ $last_hour = time;                          # last time I did an hourly periodic update
 
 $baddxfn = "$main::data/baddx.pl";
 
+@checklist = 
+(
+ qw(c c m p bc c),                             # pc10
+ qw(f c m d t c c h),                  # pc11
+ qw(c bc m p c p h),                   # pc12
+ qw(c h),
+ qw(c h),
+ qw(c m h),
+ undef,                                                        # pc16 has to be validated manually
+ qw(c c h),                                            # pc17
+ qw(c m n),                                            # pc18
+ undef,                                                        # pc19 has to be validated manually
+ undef,                                                        # pc20 no validation
+ qw(c m h),                                            # pc21
+ undef,                                                        # pc22 no validation
+ qw(d t n n n m c c h),                        # pc23
+ qw(c p h),                                            # pc24
+ qw(c c n n),                                  # pc25
+ qw(f c m d t c c),                            # pc26
+ qw(d t n n n m c c),                  # pc27
+ qw(c c c c d t p m bp n p bp c), # pc28
+ qw(c c n m),                                  # pc29
+ qw(c c n),                                            # pc30
+ qw(c c n),                                            # pc31
+ qw(c c n),                                            # pc32
+ qw(c c n),                                            # pc33
+ qw(c c m),                                            # pc34
+ qw(c c m),                                            # pc35
+ qw(c c m),                                            # pc36
+ qw(c c n m),                                  # pc37
+ qw(c m),                                              # pc39
+ qw(c c m p n),                                        # pc40
+ qw(c n m h),                                  # pc41
+ qw(c c n),                                            # pc42
+ undef,                                                        # pc43 don't handle it
+ qw(c c n m m c),                              # pc44
+ qw(c c n m),                                  # pc45
+ qw(c c n),                                            # pc46
+ undef,                                                        # pc47
+ undef,                                                        # pc48
+ qw(c m h),                                            # pc49
+ qw(c n h),                                            # pc50
+ qw(c c n),                                            # pc51
+ undef,
+ undef,
+ undef,
+ undef,
+ undef,
+ undef,
+ undef,
+ undef,
+ undef,                                                        # pc60
+ undef,
+ undef,
+ undef,
+ undef,
+ undef,
+ undef,
+ undef,
+ undef,
+ undef,
+ undef,                                                        # pc70
+ undef,
+ undef,
+ qw(d t n n n n n n m m m c c),        # pc73
+ undef,
+ undef,
+ undef,
+ undef,
+ undef,
+ undef,
+ undef,                                                        # pc80
+ undef,
+ undef,
+ undef,
+ qw(c c c m),                                  # pc84
+ qw(c c c m),                                  # pc85
+);
+
+# use the entry in the check list to check the field list presented
+# return OK if line NOT in check list (for now)
+sub check
+{
+       my $n = shift;
+       $n -= 10;
+       return 0 if $n < 10 || $n > @checklist; 
+       my $ref = $checklist[$n];
+       return 0 unless ref $ref;
+       
+       my $i;
+       shift;    # not interested in the first field
+       for ($i = 0; $i < @_; $i++) {
+               my ($blank, $act) = $$ref[$i] =~ /^(b?)(\w)$/;
+               next if $blank && $_[$i] eq ' ';
+               if ($act eq 'c') {
+                       return $i+1 unless is_callsign($_[$i]);
+               } elsif ($act eq 'm') {
+                       return $i+1 unless is_pctext($_[$i]);
+               } elsif ($act eq 'p') {
+                       return $i+1 unless is_pcflag($_[$i]);
+               } elsif ($act eq 'f') {
+                       return $i+1 unless is_freq($_[$i]);
+               } elsif ($act eq 'n') {
+                       return $i+1 if $_[$i] !~ /^[^\d ]$/;
+               } elsif ($act eq 'h') {
+                       return $i+1 unless $_[$i] =~ /^H\d\d?$/;
+               } elsif ($act eq 'd') {
+                       return $i+1 unless $_[$i] =~ /^\s*\d+-\w\w\w-[12][90]\d\d$/;
+               } elsif ($act eq 't') {
+                       return $i+1 unless $_[$i] =~ /^[012]\d[012345]\dZ$/;
+               }
+       }
+       return 0;
+}
+
 sub init
 {
        my $user = DXUser->get($main::mycall);
@@ -158,9 +273,10 @@ sub normal
        return unless $pcno;
        return if $pcno < 10 || $pcno > 99;
 
-       # dump bad protocol messages unless it is a PC29
-       if ($line =~ /\%[0-9A-F][0-9A-F]/o && $pcno != 29) {
-               dbg('chan', "CORRUPT protocol message - dumped");
+       # check for and dump bad protocol messages
+       my $n = check($pcno, @field);
+       if ($n) {
+               dbg('chan', "bad field $n, dumped (" . parray($checklist[$pcno-10]) . ")");
                return;
        }
 
@@ -176,15 +292,19 @@ sub normal
                if ($pcno == 10) {              # incoming talk
                        
                        # is it for me or one of mine?
-                       my $call = ($field[5] gt ' ') ? $field[5] : $field[2];
-                       if ($call eq $main::mycall || grep $_ eq $call, DXChannel::get_all_user_calls()) {
-                               
-                               # yes, it is
-                               my $text = unpad($field[3]);
-                               Log('talk', $call, $field[1], $field[6], $text);
-                               $call = $main::myalias if $call eq $main::mycall;
-                               my $ref = DXChannel->get($call);
-                               $ref->send("$call de $field[1]: $text") if $ref && $ref->{talk};
+                       my ($to, $via, $call, $dxchan);
+                       if ($field[5] gt ' ') {
+                               $call = $via = $field[2];
+                               $to = $field[5];
+                               unless (is_callsign($to)) {
+                                       dbg('chan', "Corrupt talk, rejected");
+                                       return;
+                               }
+                       } else {
+                               $call = $to = $field[2];
+                       }
+                       if ($dxchan = DXChannel->get($call)) {
+                               $dxchan->talk($field[1], $to, $via, $field[3]);
                        } else {
                                $self->route($field[2], $line); # relay it on its way
                        }
@@ -220,12 +340,6 @@ sub normal
                                dbg('chan', "Bad DX spot, ignored");
                                return;
                        }
-
-                       # are any of the crucial fields invalid?
-            if ($field[2] =~ /(?:^\s*$|[a-z])/ || $field[6] =~ /(?:^\s*$|[a-z])/ || $field[7] =~ /(?:^\s*$|[a-z])/) {
-                               dbg('chan', "Spot contains lower case callsigns or blanks, rejected");
-                               return;
-                       }
                        
                        # do some de-duping
                        $field[5] =~ s/^\s+//;      # take any leading blanks off
@@ -619,7 +733,7 @@ sub normal
                                my $ref = DXUser->get_current($field[2]);
                                my $cref = DXCluster->get($field[2]);
                                Log('rcmd', 'in', $ref->{priv}, $field[2], $field[3]);
-                               unless ($field[3] =~ /rcmd/i || !$cref || !$ref || $cref->mynode->call ne $ref->homenode) {    # not allowed to relay RCMDS!
+                               unless (!$cref || !$ref || $cref->mynode->call ne $ref->homenode) {    # not allowed to relay RCMDS!
                                        if ($ref->{priv}) {     # you have to have SOME privilege, the commands have further filtering
                                                $self->{remotecmd} = 1; # for the benefit of any command that needs to know
                                                my $oldpriv = $self->{priv};
@@ -1409,6 +1523,7 @@ sub disconnect
        $self->SUPER::disconnect;
 }
 
+
 # 
 # send a talk message to this thingy
 #