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
# 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
# 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;
}
$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
+
}
#
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)
+ }
}
}
}
# 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));
+ }
# }
}
$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
{
# check for length of whole command line and any invalid characters
if (length $cmdline > $maxcmdlth || $cmd =~ m|\.| || $cmd !~ m|^\w+(?:/\w+){0,1}(?:/\d+)?$|) {
LogDbg('DXCommand', "cmd: $self->{call} - invalid characters in '$cmd'");
- return $self->_error_out('e40');
+ return $self->_error_out('e40');
}
my ($path, $fcmd);
return $self->_error_out('e1');
}
} else {
- dbg("cmd: $cmd not found") if isdbg('command');
+ LogDbg('DXCommand', "$self->{call} cmd: '$cmd' not found");
return $self->_error_out('e1');
}
}
if ($ok) {
delete $self->{errors};
} else {
- if (++$self->{errors} > $DXChannel::maxerrors) {
+ if ($self != $main::me && ++$self->{errors} > $DXChannel::maxerrors) {
$self->send($self->msg('e26'));
$self->disconnect;
return ();
- }
+ }
}
return map {s/([^\s])\s+$/$1/; $_} @ans;
}
}
# send a prompt if no activity out on this channel
- if ($t >= $dxchan->t + $main::user_interval) {
+ if ($t >= $dxchan->t + $dxchan->{user_interval}) {
$dxchan->prompt() if $dxchan->{state} =~ /^prompt/o;
$dxchan->t($t);
}
if (isdbg('eval')) {
my @list = split /\n/, $eval;
- my $line;
for (@list) {
dbg($_ . "\n") if isdbg('eval');
}
}
}
-# 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
$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
{
$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;