Merge branch 'test' into mojo
[spider.git] / perl / DXCommandmode.pm
index 8720e940ac016e4ec5e8da04346f106d80722787..bc362456f568d28f85f598ad0283aa8994b1a2e1 100644 (file)
@@ -50,7 +50,7 @@ use DXCIDR;
 use strict;
 use vars qw(%Cache %cmd_cache $errstr %aliases $scriptbase %nothereslug
        $maxbadcount $msgpolltime $default_pagelth $cmdimportdir $users $maxusers
-    $maxcmdlth
+    $maxcmdlth $maxcmdcount $cmdinterval
 );
 
 %Cache = ();                                   # cache of dynamically loaded routine's mod times
@@ -64,8 +64,9 @@ $cmdimportdir = "$main::root/cmd_import"; # the base directory for importing com
                                           # this does not exist as default, you need to create it manually
 $users = 0;                                      # no of users on this node currently
 $maxusers = 0;                           # max no users on this node for this run
-
 $maxcmdlth = 512;                              # max length of incoming cmd line (including the command and any arguments
+$maxcmdcount = 27;                             # max no cmds entering $cmdinterval seconds
+$cmdinterval = 20;                             # if user enters more than $maxcmdcount in $cmdinterval seconds, they are logged off
 
 #
 # obtain a new connection this is derived from dxchannel
@@ -174,25 +175,12 @@ sub start
        # sort out privilege reduction
        $self->{priv} = 0 unless $self->{hostname} eq '127.0.0.1' || $self->conn->peerhost eq '127.0.0.1' || $self->{hostname} eq '::1' || $self->conn->{usedpasswd};
 
-       # get the filters
-       my $nossid = $call;
-       $nossid =~ s/-\d+$//;
        
-       $self->{spotsfilter} = Filter::read_in('spots', $call, 0) 
-               || Filter::read_in('spots', $nossid, 0)
-                       || Filter::read_in('spots', 'user_default', 0);
-       $self->{wwvfilter} = Filter::read_in('wwv', $call, 0) 
-               || Filter::read_in('wwv', $nossid, 0) 
-                       || Filter::read_in('wwv', 'user_default', 0);
-       $self->{wcyfilter} = Filter::read_in('wcy', $call, 0) 
-               || Filter::read_in('wcy', $nossid, 0) 
-                       || Filter::read_in('wcy', 'user_default', 0);
-       $self->{annfilter} = Filter::read_in('ann', $call, 0) 
-               || Filter::read_in('ann', $nossid, 0) 
-                       || Filter::read_in('ann', 'user_default', 0) ;
-       $self->{rbnfilter} = Filter::read_in('rbn', $call, 0) 
-               || Filter::read_in('rbn', $nossid, 0)
-               || Filter::read_in('rbn', 'user_default', 0);
+       Filter::load_dxchan($self, 'spots', 0);
+       Filter::load_dxchan($self, 'wwv', 0);
+       Filter::load_dxchan($self, 'wcy', 0);
+       Filter::load_dxchan($self, 'ann', 0);
+       Filter::load_dxchan($self, 'rbn', 0);
        
        # clean up qra locators
        my $qra = $user->qra;
@@ -254,6 +242,10 @@ sub start
        $self->lastmsgpoll($main::systime);
        $self->{user_interval} = $self->user->user_interval || $main::user_interval; # allow user to change idle time between prompts
        $self->prompt;
+
+       $self->{cmdintstart} = 0; # set when systime > this + cmdinterval and a command entered, cmdcount set to 0
+       $self->{cmdcount} = 0;             # incremented on a coming in. If this value > $maxcmdcount, disconnect
+
 }
 
 #
@@ -343,28 +335,36 @@ sub normal
                        for (@{$self->{talklist}}) {
                                if ($self->{state} eq 'talk') {
                                        $self->send_talks($_,  $self->msg('talkend'));
+                               } elsif ($self->{state} eq 'chat') {
+                                       $self->send_talks($_,  $self->msg('chatend'));
                                } else {
                                        $self->local_send('C', $self->msg('chatend', $_));
                                }
                        }
                        $self->state('prompt');
                        delete $self->{talklist};
-               } elsif ($cmdline =~ m|^/+\w+|) {
+               } elsif ($cmdline =~ m|^[/\w\\]+|) {
                        $cmdline =~ s|^/||;
-                       my $sendit = $cmdline =~ s|^/+||;
+                       my $sendit = ($cmdline = unpad($cmdline));
                        if (@bad = BadWords::check($cmdline)) {
                                $self->badcount(($self->badcount||0) + @bad);
                                LogDbg('DXCommand', "$self->{call} swore: '$cmdline' with badwords: '" . join(',', @bad) . "'");
                        } else {
-                               my @in = $self->run_cmd($cmdline);
-                               $self->send_ans(@in);
-                               if ($sendit && $self->{talklist} && @{$self->{talklist}}) {
-                                       foreach my $l (@in) {
-                                               for (@{$self->{talklist}}) {
-                                                       if ($self->{state} eq 'talk') {
-                                                               $self->send_talks($_, $l);
-                                                       } else {
-                                                               send_chats($self, $_, $l)
+                               my $c;
+                               my @in;
+                               if (($c) = $cmdline =~ /^cmd\s+(.*)$/) {
+                                       @in = $self->run_cmd($c);
+                                       $self->send_ans(@in);
+                               } else {
+                                       push @in, $cmdline;
+                                       if ($sendit && $self->{talklist} && @{$self->{talklist}}) {
+                                               foreach my $l (@in) {
+                                                       for (@{$self->{talklist}}) {
+                                                               if ($self->{state} eq 'talk') {
+                                                                       $self->send_talks($_, $l);
+                                                               } else {
+                                                                       send_chats($self, $_, $l)
+                                                               }
                                                        }
                                                }
                                        }
@@ -410,8 +410,25 @@ sub normal
 #              if (@bad = BadWords::check($cmdline)) {
 #                      $self->badcount(($self->badcount||0) + @bad);
 #                      LogDbg('DXCommand', "$self->{call} swore: '$cmdline' with badwords: '" . join(',', @bad) . "'");
-#              } else {
-                       $self->send_ans(run_cmd($self, $cmdline));
+               #               } else {
+               my @cmd = split /\s*\\n\s*/, $cmdline;
+               foreach my $l (@cmd) {
+
+                       # rate limiting code
+                       
+                       if (($self->{cmdintstart} + $cmdinterval <= $main::systime) || $self->{inscript}) {
+                               $self->{cmdintstart} = $main::systime;
+                               $self->{cmdcount} = 1;
+                               dbg("$self->{call} started cmdinterval") if isdbg('cmdcount');
+                       } else {
+                               if (++$self->{cmdcount} > $maxcmdcount) {
+                                       LogDbg('baduser', qq{User $self->{call} sent $self->{cmdcount} (>= $maxcmdcount) cmds in $cmdinterval seconds starting at } . atime($self->{cmdintstart}) . ", disconnected" );
+                                       $self->disconnect;
+                               }
+                               dbg("$self->{call} cmd: '$l' cmdcount = $self->{cmdcount} in $cmdinterval secs") if isdbg('cmdcount');
+                       }
+                       $self->send_ans(run_cmd($self, $l));
+               }
 #              }
        } 
 
@@ -426,41 +443,6 @@ sub normal
        $self->prompt() if $self->{state} =~ /^prompt/o;
 }
 
-# send out the talk messages taking into account vias and connectivity
-sub send_talks
-{
-       my ($self, $ent, $line) = @_;
-       
-       my ($to, $via) = $ent =~ /(\S+)>(\S+)/;
-       $to = $ent unless $to;
-       my $call = $via && $via ne '*' ? $via : $to;
-       my $clref = Route::get($call);
-       my $dxchan = $clref->dxchan if $clref;
-       if ($dxchan) {
-               $dxchan->talk($self->{call}, $to, undef, $line);
-       } else {
-               $self->send($self->msg('disc2', $via ? $via : $to));
-               my @l = grep { $_ ne $ent } @{$self->{talklist}};
-               if (@l) {
-                       $self->{talklist} = \@l;
-               } else {
-                       delete $self->{talklist};
-                       $self->state('prompt');
-               }
-       }
-}
-
-sub send_chats
-{
-       my $self = shift;
-       my $target = shift;
-       my $text = shift;
-
-       my $msgid = DXProt::nextchatmsgid();
-       $text = "#$msgid $text";
-       my $ipaddr = alias_localhost($self->hostname || '127.0.0.1');
-       $main::me->normal(DXProt::pc93($target, $self->{call}, undef, $text, undef, $ipaddr));
-}
 
 sub special_prompt
 {
@@ -598,7 +580,11 @@ sub run_cmd
        if ($ok) {
                delete $self->{errors};
        } else {
-               return $self->_error_out('e26');
+               if ($self != $main::me && ++$self->{errors} > $DXChannel::maxerrors) {
+                       $self->send($self->msg('e26'));
+                       $self->disconnect;
+                       return ();
+               } 
        }
        return map {s/([^\s])\s+$/$1/; $_} @ans;
 }
@@ -878,7 +864,6 @@ sub find_cmd_name {
                
                if (isdbg('eval')) {
                        my @list = split /\n/, $eval;
-                       my $line;
                        for (@list) {
                                dbg($_ . "\n") if isdbg('eval');
                        }
@@ -929,33 +914,6 @@ sub local_send
        }
 }
 
-# send a talk message here
-sub talk
-{
-       my ($self, $from, $to, $via, $line, $onode) = @_;
-       $line =~ s/\\5E/\^/g;
-       if ($self->{talk}) {
-               if ($self->{gtk}) {
-                       $self->local_send('T', dd(['talk',$to,$from,$via,$line]));
-               } else {
-                       $self->local_send('T', "$to de $from: $line");
-               }
-       }
-       Log('talk', $to, $from, '<' . ($onode || '*'), $line);
-       # send a 'not here' message if required
-       unless ($self->{here} && $from ne $to) {
-               my $key = "$to$from";
-               unless (exists $nothereslug{$key}) {
-                       my ($ref, $dxchan);
-                       if (($ref = Route::get($from)) && ($dxchan = $ref->dxchan)) {
-                               my $name = $self->user->name || $to;
-                               my $s = $self->user->nothere || $dxchan->msg('nothere', $name);
-                               $nothereslug{$key} = $main::systime;
-                               $dxchan->talk($to, $from, undef, $s);
-                       }
-               }
-       }
-}
 
 # send an announce
 sub announce
@@ -993,6 +951,22 @@ sub announce
        $self->local_send($target eq 'WX' ? 'W' : 'N', $buf);
 }
 
+# send a talk message here
+sub talk
+{
+       my ($self, $from, $to, $via, $line, $onode) = @_;
+       $line =~ s/^\#\d+ //;
+       $line =~ s/\\5E/\^/g;
+       if ($self->{talk}) {
+               if ($self->{gtk}) {
+                       $self->local_send('T', dd(['talk',$to,$from,$via,$line]));
+               } else {
+                       $self->local_send('T', "$to de $from: $line");
+               }
+       }
+       Log('talk', $to, $from, '<' . ($onode || '*'), $line);
+}
+
 # send a chat
 sub chat
 {
@@ -1018,6 +992,31 @@ sub chat
        $self->local_send('C', $buf);
 }
 
+# send out the talk messages taking into account vias and connectivity
+sub send_talks
+{
+       my ($self, $target, $text) = @_;
+       
+       my $msgid = DXProt::nextchatmsgid();
+       $text = "#$msgid $text";
+       my $ipaddr = alias_localhost($self->hostname || '127.0.0.1');
+       $main::me->normal(DXProt::pc93($target, $self->{call}, undef, $text, undef, $ipaddr));  
+
+}
+
+sub send_chats
+{
+       my $self = shift;
+       my $target = shift;
+       my $text = shift;
+
+       my $msgid = DXProt::nextchatmsgid();
+       $text = "#$msgid $text";
+       my $ipaddr = alias_localhost($self->hostname || '127.0.0.1');
+       $main::me->normal(DXProt::pc93($target, $self->{call}, undef, $text, undef, $ipaddr));
+}
+
+
 sub format_dx_spot
 {
        my $self = shift;