X-Git-Url: http://dxcluster.net/gitweb/gitweb.cgi?a=blobdiff_plain;f=perl%2FFilter.pm;h=b71ee95a5b81833acb4a1fc566592b832071529f;hb=ab811a0c902225075a9bd69749f65594079433a9;hp=6a0dad7a9b5debfcdfd27168acc5284101e2481a;hpb=211b54d504170a8c9dad2bf25b9ed686d5eeac11;p=spider.git diff --git a/perl/Filter.pm b/perl/Filter.pm index 6a0dad7a..b71ee95a 100644 --- a/perl/Filter.pm +++ b/perl/Filter.pm @@ -10,7 +10,7 @@ # # Copyright (c) 1999 Dirk Koopman G1TLH # -# $Id$ +# # # The NEW INSTRUCTIONS # @@ -30,6 +30,7 @@ use DXVars; use DXUtil; use DXDebug; use Data::Dumper; +use Prefix; use strict; @@ -76,6 +77,29 @@ sub getfn # in with a 'do' statement. The 'do' statement reads the filter into # @in which is a list of references # +sub compile +{ + my $self = shift; + my $fname = shift; + my $ar = shift; + my $ref = $self->{$fname}; + my $rr; + + if ($ref->{$ar} && exists $ref->{$ar}->{asc}) { + my $s = $ref->{$ar}->{asc}; # an optimisation? + $s =~ s/\$r/\$_[0]/g; + $ref->{$ar}->{code} = eval "sub { $s }" ; + if ($@) { + my $sort = $ref->{sort}; + my $name = $ref->{name}; + dbg("Error compiling $ar $sort $name: $@"); + Log('err', "Error compiling $ar $sort $name: $@"); + } + $rr = $@; + } + return $rr; +} + sub read_in { my ($sort, $call, $flag) = @_; @@ -86,34 +110,26 @@ sub read_in $in = undef; my $s = readfilestr($fn); my $newin = eval $s; - dbg('conn', "$@") if $@; + if ($@) { + dbg($@); + unlink($fn); + return undef; + } if ($in) { $newin = new('Filter::Old', $sort, $call, $flag); $newin->{filter} = $in; - } else { + } elsif (ref $newin && $newin->can('getfilkeys')) { my $filter; my $key; foreach $key ($newin->getfilkeys) { - $filter = $newin->{$key}; - if ($filter->{reject} && exists $filter->{reject}->{asc}) { - $filter->{reject}->{code} = eval $filter->{reject}->{asc} ; - if ($@) { - my $sort = $newin->{sort}; - my $name = $newin->{name}; - dbg('err', "Error compiling reject $sort $key $name: $@"); - Log('err', "Error compiling reject $sort $key $name: $@"); - } - } - if ($filter->{accept} && exists $filter->{accept}->{asc}) { - $filter->{accept}->{code} = eval $filter->{accept}->{asc} ; - if ($@) { - my $sort = $newin->{sort}; - my $name = $newin->{name}; - dbg('err', "Error compiling accept $sort $key $name: $@"); - Log('err', "Error compiling accept $sort $key $name: $@"); - } - } + $newin->compile($key, 'reject'); + $newin->compile($key, 'accept'); } + } else { + # error on reading file, delete and exit + dbg("empty or unreadable filter: $fn, deleted"); + unlink($fn); + return undef; } return $newin; } @@ -143,12 +159,15 @@ sub getfilkeys # The filter returns 0 if an entry is matched by any reject rule and also if any # accept rule fails otherwise it returns 1 # -# Either set of rules may be missing meaning an implicit 'ok' +# Either set of rules may be missing meaning an implicit 'opposite' ie if it +# a reject then ok else if an accept then not ok. +# +# you can set a default with either an accept/xxxx all or reject/xxxx all # # Unlike the old system, this is kept as a hash of hashes so that you can # easily change them by program. # -# You can have a [any] number of 'filters', they are tried in random order until +# You can have 10 filter lines (0->9), they are tried in order until # one matches # # There is a parser that takes a Filter::Cmd object which describes all the possible @@ -177,32 +196,48 @@ sub it { my $self = shift; - my $hops = undef; - my $r = 1; - my $filter; - foreach $filter ($self->getfilters) { - $r = 0; + my @keys = sort $self->getfilkeys; + my $key; + my $type = 'Dunno'; + my $asc = '?'; + + my $r = @keys > 0 ? 0 : 1; + foreach $key (@keys) { + $filter = $self->{$key}; if ($filter->{reject} && exists $filter->{reject}->{code}) { - next if &{$filter->{reject}->{code}}(\@_); + $type = 'reject'; + $asc = $filter->{reject}->{user}; + if (&{$filter->{reject}->{code}}(\@_)) { + $r = 0; + last; + } else { + $r = 1; + } } if ($filter->{accept} && exists $filter->{accept}->{code}) { - next unless &{$filter->{accept}->{code}}(\@_); + $type = 'accept'; + $asc = $filter->{accept}->{user}; + if (&{$filter->{accept}->{code}}(\@_)) { + $r = 1; + last; + } else { + $r = 0; + } } - $r = 1; - last; } - # hops are done differently - if ($self->{hops}) { - my ($comp, $ref); - while (($comp, $ref) = each %{$self->{hops}}) { - my ($field, $h) = @$ref; - if ($_[$field] =~ m{$comp}) { - $hops = $h; - last; - } - } + # hops are done differently (simply) + my $hops = $self->{hops} if exists $self->{hops}; + + if (isdbg('filter')) { + my $args = join '\',\'', map {defined $_ ? $_ : 'undef'} @_; + my $true = $r ? "OK " : "REJ"; + my $sort = $self->{sort}; + my $dir = $self->{name} =~ /^in_/i ? "IN " : "OUT"; + + my $h = $hops || ''; + dbg("$true $dir: $type/$sort with $asc on '$args' $h") if isdbg('filter'); } return ($r, $hops); } @@ -237,20 +272,22 @@ sub write sub print { my $self = shift; + my $name = shift || $self->{name}; + my $sort = shift || $self->{sort}; + my $flag = shift || ""; my @out; - my $name = $self->{name}; $name =~ s/.pl$//; - push @out, join(' ', $name , ':', $self->{sort}); + push @out, join(' ', $name , ':', $sort, $flag); my $filter; my $key; foreach $key (sort $self->getfilkeys) { my $filter = $self->{$key}; - if ($filter->{reject} && exists $filter->{reject}->{user}) { - push @out, ' ' . join(' ', $key, 'reject', $filter->{reject}->{user}); + if (exists $filter->{reject} && exists $filter->{reject}->{user}) { + push @out, ' ' . join(' ', $key, 'reject', $filter->{reject}->{user}); } - if ($filter->{accept} && exists $filter->{accept}->{user}) { - push @out, ' ' . join(' ', $key, 'accept', $filter->{accept}->{user}); + if (exists $filter->{accept} && exists $filter->{accept}->{user}) { + push @out, ' ' . join(' ', $key, 'accept', $filter->{accept}->{user}); } } return @out; @@ -262,14 +299,27 @@ sub install my $remove = shift; my $name = uc $self->{name}; my $sort = $self->{sort}; - my ($in) = $name =~ s/^IN_//; + my $in = ""; + $in = "in" if $name =~ s/^IN_//; $name =~ s/.PL$//; - my $dxchan = DXChannel->get($name); - if ($dxchan) { - $in = lc $in if $in; + my $dxchan; + my @dxchan; + if ($name eq 'NODE_DEFAULT') { + @dxchan = DXChannel::get_all_nodes(); + } elsif ($name eq 'USER_DEFAULT') { + @dxchan = DXChannel::get_all_users(); + } else { + $dxchan = DXChannel::get($name); + push @dxchan, $dxchan if $dxchan; + } + foreach $dxchan (@dxchan) { my $n = "$in$sort" . "filter"; - $dxchan->$n($remove ? undef : $self); + my $i = $in ? 'IN_' : ''; + my $ref = $dxchan->$n(); + if (!$ref || ($ref && uc $ref->{name} eq "$i$name.PL")) { + $dxchan->$n($remove ? undef : $self); + } } } @@ -293,6 +343,7 @@ sub delete # get rid if ($filter->{hops} || $filter->getfilkeys) { $filter->install; + $filter->write; } else { $filter->install(1); unlink $fn; @@ -303,6 +354,9 @@ sub delete package Filter::Cmd; use strict; +use DXVars; +use DXUtil; +use DXDebug; use vars qw(@ISA); @ISA = qw(Filter); @@ -310,7 +364,7 @@ use vars qw(@ISA); # this is called as a subroutine not as a method sub parse { - my ($self, $dxchan, $line) = @_; + my ($self, $dxchan, $sort, $line) = @_; my $ntoken = 0; my $fno = 1; my $filter; @@ -319,7 +373,7 @@ sub parse my $user; # check the line for non legal characters - return ('ill', $dxchan->msg('e19')) if $line =~ /[^\s\w,_\*\/\(\)]/; + return ('ill', $dxchan->msg('e19')) if $line =~ /[^\s\w,_\-\*\/\(\)!]/; # add some spaces for ease of parsing $line =~ s/([\(\)])/ $1 /g; @@ -331,7 +385,7 @@ sub parse while (@f) { if ($ntoken == 0) { - if (@f && $dxchan->priv >= 8 && (DXUser->get($f[0]) || $f[0] =~ /(?:node|user)_default/)) { + if (@f && $dxchan->priv >= 8 && ((is_callsign(uc $f[0]) && DXUser::get(uc $f[0])) || $f[0] =~ /(?:node|user)_default/)) { $call = shift @f; if ($f[0] eq 'input') { shift @f; @@ -345,8 +399,8 @@ sub parse $fno = shift @f; } - $filter = Filter::read_in('spots', $call, $flag); - $filter = Filter->new('spots', $call, $flag) unless $filter; + $filter = Filter::read_in($sort, $call, $flag); + $filter = Filter->new($sort, $call, $flag) if !$filter || $filter->isa('Filter::Old'); $ntoken++; next; @@ -375,6 +429,10 @@ sub parse $s .= $tok; $user .= $tok; next; + } elsif ($tok eq 'all') { + $s .= '1'; + $user .= $tok; + last; } elsif ($tok eq 'or') { $conj = ' || ' if $conj ne ' || '; next; @@ -391,12 +449,16 @@ sub parse if ($s) { $s .= $conj ; - $s .= $not; $user .= $conj; - $user .= $not; $conj = ' && '; - $not = ""; } + + if ($not) { + $s .= $not; + $user .= $not; + $not = ''; + } + $user .= "$tok $val"; my $fref; @@ -432,6 +494,16 @@ sub parse push @t, "\$r->[$fref->[2]]==$_"; } $s .= "(" . join(' || ', @t) . ")"; + } elsif ($fref->[1] =~ /^n[ciz]$/ ) { # for DXCC, ITU, CQ Zone + my $cmd = $fref->[1]; + my @pre = Prefix::to_ciz($cmd, @val); + return ('numpre', $dxchan->msg('e27', $_)) unless @pre; + $s .= "(" . join(' || ', map {"\$r->[$fref->[2]]==$_"} @pre) . ")"; + } elsif ($fref->[1] =~ /^ns$/ ) { # for DXCC, ITU, CQ Zone + my $cmd = $fref->[1]; + my @pre = Prefix::to_ciz($cmd, @val); + return ('numpre', $dxchan->msg('e27', $_)) unless @pre; + $s .= "(" . "!\$USDB::present || grep \$r->[$fref->[2]] eq \$_, qw(" . join(' ' ,map {uc} @pre) . "))"; } elsif ($fref->[1] eq 'r') { my @t; for (@val) { @@ -439,6 +511,13 @@ sub parse push @t, "(\$r->[$fref->[2]]>=$1 && \$r->[$fref->[2]]<=$2)"; } $s .= "(" . join(' || ', @t) . ")"; + } elsif ($fref->[1] eq 't') { + my @t; + for (@val) { + s/\*//g; + push @t, "\$r->[$fref->[2]]=~/$_/i"; + } + $s .= "(" . join(' || ', @t) . ")"; } else { confess("invalid letter $fref->[1]"); } @@ -460,12 +539,45 @@ sub parse $user =~ s/\!/ not /g; $user =~ s/\s+/ /g; - return (0, $filter, $fno, $user, "sub { my \$r = shift; return $s }"); + return (0, $filter, $fno, $user, "$s"); +} + +# a filter accept/reject command +sub cmd +{ + my ($self, $dxchan, $sort, $type, $line) = @_; + + return $dxchan->msg('filter5') unless $line; + + my ($r, $filter, $fno, $user, $s) = $self->parse($dxchan, $sort, $line); + my $u = DXUser::get_current($user); + return (1, $dxchan->msg('isow', $user)) if $u && $u->isolate; + return (1, $filter) if $r; + + my $fn = "filter$fno"; + + $filter->{$fn} = {} unless exists $filter->{$fn}; + $filter->{$fn}->{$type} = {} unless exists $filter->{$fn}->{$type}; + + $filter->{$fn}->{$type}->{user} = $user; + $filter->{$fn}->{$type}->{asc} = $s; + $r = $filter->compile($fn, $type); + return (1,$r) if $r; + + $r = $filter->write; + return (1,$r) if $r; + + $filter->install; + + return (0, $filter, $fno); } package Filter::Old; use strict; +use DXVars; +use DXUtil; +use DXDebug; use vars qw(@ISA); @ISA = qw(Filter); @@ -532,6 +644,14 @@ sub it } } +sub print +{ + my $self = shift; + my $call = shift; + my $sort = shift; + my $flag = shift || ""; + return "$call: Old Style Filter $flag $sort"; +} 1; __END__