]> git.somenet.org - irc/bugbot.git/blob - BotModules/Flood.bm
GITOLITE.txt
[irc/bugbot.git] / BotModules / Flood.bm
1 # -*- Mode: perl; indent-tabs-mode: nil -*-
2 # $Id: Flood.bm,v 1.2 2003/10/03 15:46:54 ian%hixie.ch Exp $
3 ###########################
4 # Flood Protection module #
5 ###########################
6
7 package BotModules::Flood;
8 use vars qw(@ISA);
9 @ISA = qw(BotModules);
10 1;
11
12 sub RegisterConfig {
13     my $self = shift;
14     $self->SUPER::RegisterConfig(@_);
15
16     foreach my $chan (@{$self->{'channels'}}) {
17         $self->registerVariables( ["join_$chan", 0, 0, []] );
18     }
19     $self->registerVariables(
20         ['numberOfJoins', 1, 1, '7'],
21         ['secondsToTrigger', 1, 1, '2'],
22         ['minutesToProtect', 1, 1, '5'],
23     );
24 }
25
26 sub Help {
27     my $self = shift;
28     my ($event) = @_;
29     return {
30         '' => 'This module will help control "join flood" attacks on IRC',
31     };
32 }
33
34 # Set - called to set a variable to a particular value.
35 sub Set {
36     my $self = shift;
37     my ($event, $variable, $value) = @_;
38     # If changing the setting for numberOfJoins make sure
39     # that the arrays are empty.  Otherwise, reducing the
40     # numberOfJoins value would not work properly.
41     if ($variable eq 'numberOfJoins') {
42         foreach my $chan (@{$self->{'channels'}}) {
43             @{$self->{"join_$chan"}} = ();
44         }
45     }
46     # now actually do the setting of the variable
47     return $self->SUPER::Set($event, $variable, $value);
48 }
49
50 sub JoinedChannel {
51     my $self = shift;
52     my ($event, $channel) = @_;
53     $self->registerVariables( ["join_$channel", 0, 0, []] );
54     return $self->SUPER::JoinedChannel($event, $channel); # call inherited method
55 }
56
57 sub SpottedJoin {
58     my $self = shift;
59     my ($event, $channel, $who) = @_;
60     # If numberOfJoins or secondsToTrigger is not a positive Integer, don't do anything
61     if ($self->{'numberOfJoins'} !~ m/^[1-9][0-9]*$/o || $self->{'secondsToTrigger'} !~ m/^[1-9][0-9]*$/o) {
62         # We didn't do anything, so don't pretend like we did :)
63         return $self->SUPER::SpottedJoin($event, $channel, $who);
64     }
65     # Here we have the 'join_times' array to push and shift to/from
66     push(@{$self->{"join_$channel"}}, $event->{'time'});
67     if (scalar(@{$self->{"join_$channel"}}) >= $self->{'numberOfJoins'}) {
68         my $oldest = shift(@{$self->{"join_$channel"}});
69         my $timechange = $event->{'time'} - $oldest;
70         if ($self->{'secondsToTrigger'} >= $timechange) {
71             # We have just seen many joins happen very quickly.  This channel should
72             # have its mode set to +i until an op can figure out what went wrong.
73             $self->mode($event, $event->{'channel'}, '+i');
74             my $extra_text = "";
75             # If minutesToProtect is a positive integer we should set mode -i after
76             # that number of minutes has passed.
77             if ($self->{'minutesToProtect'} =~ m/^[1-9][0-9]*$/o) {
78                 my $seconds = $self->{'minutesToProtect'} * 60;
79                 my @mode = ('mode', $event->{'channel'}, '-i');
80                 $self->schedule($event, $seconds, 1, @mode);
81                 $extra_text = "I'll set it -i in $self->{'minutesToProtect'} minutes";
82             }
83             $self->say($event, "I just saw a lot of joins happen very quickly.  Because of " .
84                        "that I set this channel's mode to be Invite Only... $extra_text");
85         }
86     }
87     # By returning 0 we ensure that a join won't be processed more than once.
88     return 0;
89 }
90
91 sub Scheduled {
92     my $self = shift;
93     my ($event, @data) = @_;
94
95     my $what = shift(@data);
96     if ($what eq 'mode') {
97         $self->mode($event, @data);
98     } else {
99         # Call the inherited event
100         return $self->SUPER::Schedule(@_);
101     }
102 }