File Coverage

blib/lib/Bot/R9K.pm
Criterion Covered Total %
statement 18 66 27.2
branch 0 6 0.0
condition 0 2 0.0
subroutine 6 19 31.5
pod 1 6 16.6
total 25 99 25.2


line stmt bran cond sub pod time code
1             package Bot::R9K;
2              
3 1     1   21684 use warnings;
  1         3  
  1         38  
4 1     1   5 use strict;
  1         32  
  1         37  
5 1     1   22 use 5.010;
  1         8  
  1         42  
6              
7 1     1   906 use POE;
  1         56635  
  1         7  
8 1     1   107920 use POE::Component::IRC::Plugin qw(:ALL);
  1         523  
  1         171  
9              
10 1     1   954 use List::MoreUtils qw(any);
  1         1303  
  1         810  
11              
12             our $VERSION = 0.01;
13              
14             =head1 NAME
15              
16             Bot::R9K
17              
18             =head1 SYNOPSIS
19              
20             use POE qw(Component::IRC);
21             use Bot::R9K;
22              
23             my $irc = POE::Component::IRC->spawn(
24             nick => 'Bot-R9K',
25             server => 'irc.botnet.org',
26             port => 6667,
27             ircname => 'R9K',
28             username => 'r9k',
29             debug => 1,
30             );
31              
32             POE::Session->create(
33             package_states => [
34             main => [ qw(_start irc_001) ],
35             ],
36             );
37              
38             $poe_kernel->run;
39              
40             sub _start {
41             $irc->yield( register => 'all' );
42            
43             $irc->plugin_add(
44             'R9K' =>
45             Bot::R9K->new
46             );
47              
48             $irc->yield( connect => {} );
49             }
50              
51             sub irc_001 {
52             $_[kernel]->post( $_[sender] => join => '#channel' );
53             }
54              
55             =head1 DESCRIPTION
56              
57             Bot::R9K is a PoCo::IRC plugin that runs an R9K bot for you. The R9K bot watches
58             for repeated messages and silences anyone who says something that has been said
59             before. The more times it has been said, the longer the silence.
60              
61             Remember to op your bot when it joins.
62              
63             =head1 METHODS
64              
65             =head2 new
66              
67             Create a new bot: see L.
68              
69             =head3 Options
70              
71             =over
72              
73             =item ignore
74              
75             An array ref of regexes to ignore. They are tested against the full nick (with
76             the ! and the @ and everything).
77              
78             =item exceptions
79              
80             An array ref of regexes defining exempt messages.
81              
82             =item punishment
83              
84             A subref. This will be passed [c]$self[/c], [c]$nick[/c] and [c]$chan[/c]. Do
85             what you want; the default is to remove voice and ban (but not kick).
86              
87             =item unpunishment
88              
89             A subref. Receives the same info as [c]punishment[/c]. Use this to reverse the
90             punishment. By default it removes the ban and sets voice, regardless of whether
91             the user originally had voice (the point of the bot is rather that you can
92             silence people, so everyone who is not silenced should have voice).
93              
94             =back
95              
96             =cut
97              
98             sub new {
99 0     0 1   my $package = shift;
100              
101 0   0       my $options = shift // {};
102              
103             my %default = (
104             ignore => [],
105             exceptions => [],
106             punishment => sub {
107 0     0     my ($self, $nick, $chan) = @_;
108 0           my $smallnick = (split /!/, $nick)[0];
109              
110 0           say "Punishing $nick in $chan";
111 0           $self->{irc}->yield(mode => "$chan -v+b $smallnick $nick");
112             },
113             unpunishment => sub {
114 0     0     my ($self, $nick, $chan) = @_;
115 0           my $smallnick = (split /!/, $nick)[0];
116              
117 0           say "Pardoning $nick in $chan";
118 0           $self->{irc}->yield(mode => "$chan +v-b $smallnick $nick");
119             },
120             f => sub {
121 0     0     return shift() ** 2;
122             }
123 0           );
124 0           $options = { %default, %$options };
125 0           return bless $options, $package;
126             }
127              
128             sub PCI_register {
129 0     0 0   my ($self, $irc) = @_;
130              
131 0           $irc->plugin_register($self, 'SERVER', 'public');
132 0           $self->{irc} = $irc;
133 0           return 1;
134             }
135              
136 0     0 0   sub PCI_unregister { 1 }
137              
138             sub S_public {
139 0     0 0   my $self = shift;
140 0           my $irc = shift;
141              
142 0           my $nick = ${ $_[0] };
  0            
143 0           my $chan = ${ $_[1] }->[0];
  0            
144 0           my $msg = ${ $_[2] };
  0            
145              
146 0 0   0     return PCI_EAT_NONE if any { $nick =~ $_ } @{ $self->{ignore} };
  0            
  0            
147 0 0   0     return PCI_EAT_NONE if any { $msg =~ $_ } @{ $self->{exceptions} };
  0            
  0            
148              
149 0           my $penalty = $self->{channel}->{$chan}->{message}->{$msg}++;
150 0 0         return PCI_EAT_NONE unless $penalty;
151              
152 0           say "punishing $nick in $chan for saying -- $msg --";
153              
154 0           $self->punish($nick, $chan, $penalty);
155 0           return PCI_EAT_NONE;
156             }
157              
158             sub punish {
159 0     0 0   my ($self, $nick, $chan, $penalty) = @_;
160              
161 0           my $timeout = int($self->{f}->($penalty));
162 0           my $punishment = $self->{punishment};
163              
164 0           $self->$punishment($nick, $chan);
165              
166             POE::Session->create(
167             inline_states => {
168             _start => sub {
169 0     0     $_[KERNEL]->alarm(unpunish => int(time + $timeout));
170             },
171             unpunish => sub {
172 0     0     $self->unpunish($nick, $chan);
173             },
174             },
175 0           );
176             }
177              
178             sub unpunish {
179 0     0 0   my ($self, $nick, $chan) = @_;
180 0           my $unpunishment = $self->{unpunishment};
181              
182 0           $self->$unpunishment($nick, $chan);
183             }
184              
185             1;
186              
187             __END__