File Coverage

blib/lib/POE/Component/IRC/Plugin/AutoJoin.pm
Criterion Covered Total %
statement 97 122 79.5
branch 26 50 52.0
condition n/a
subroutine 15 17 88.2
pod 1 12 8.3
total 139 201 69.1


line stmt bran cond sub pod time code
1             package POE::Component::IRC::Plugin::AutoJoin;
2             $POE::Component::IRC::Plugin::AutoJoin::VERSION = '6.95';
3 9     9   8373 use strict;
  9         27  
  9         464  
4 9     9   54 use warnings FATAL => 'all';
  9         17  
  9         713  
5 9     9   59 use Carp;
  9         20  
  9         1072  
6 9     9   90 use IRC::Utils qw(parse_user lc_irc);
  9         26  
  9         777  
7 9     9   58 use POE::Component::IRC::Plugin qw(:ALL);
  9         18  
  9         19060  
8              
9             sub new {
10 6     6 1 15650 my ($package) = shift;
11 6 50       145 croak "$package requires an even number of arguments" if @_ & 1;
12 6         68 my %self = @_;
13 6         46 return bless \%self, $package;
14             }
15              
16             sub PCI_register {
17 6     6 0 1222 my ($self, $irc) = @_;
18              
19 6 100       65 if (!$self->{Channels}) {
    100          
20 2 100       25 if ($irc->isa('POE::Component::IRC::State')) {
21 1         3 for my $chan (keys %{ $irc->channels() }) {
  1         8  
22 0         0 my $lchan = lc_irc($chan, $irc->isupport('MAPPING'));
23             # note that this will not get the real key on ircu servers
24             # in channels where we don't have ops
25 0 0       0 my $key = $irc->is_channel_mode_set($chan, 'k')
26             ? $irc->channel_key($chan)
27             : ''
28             ;
29              
30 0         0 $self->{Channels}->{$lchan} = $key;
31             }
32             }
33             else {
34 1         4 $self->{Channels} = {};
35             }
36             }
37             elsif (ref $self->{Channels} eq 'ARRAY') {
38 2         5 my %channels;
39 2         5 $channels{lc_irc($_, $irc->isupport('MAPPING'))} = undef for @{ $self->{Channels} };
  2         17  
40 2         44 $self->{Channels} = \%channels;
41             }
42              
43 6         27 $self->{tried_keys} = { };
44 6 100       50 $self->{Rejoin_delay} = 5 if !defined $self->{Rejoin_delay};
45 6 50       42 $self->{NickServ_delay} = 5 if !defined $self->{NickServ_delay};
46 6         37 $irc->plugin_register($self, 'SERVER', qw(001 474 isupport chan_mode join kick part identified));
47 6         496 $irc->plugin_register($self, 'USER', qw(join));
48 6         217 return 1;
49             }
50              
51             sub PCI_unregister {
52 6     6 0 3634 return 1;
53             }
54              
55             sub S_001 {
56 5     5 0 305 my ($self, $irc) = splice @_, 0, 2;
57 5         18 delete $self->{alarm_ids};
58 5         17 return PCI_EAT_NONE;
59             }
60              
61             # we join channels after S_isupport in case the server supports
62             # CAPAB IDENTIFY-MSG, so pocoirc can turn it on before we join channels
63             sub S_isupport {
64 5     5 0 276 my ($self, $irc) = splice @_, 0, 2;
65              
66 5 50       16 if (!grep { $_->isa('POE::Component::IRC::Plugin::NickServID') } values %{ $irc->plugin_list() }) {
  20         535  
  5         80  
67             # we don't have to wait for NickServ, so let's join
68 5         18 while (my ($chan, $key) = each %{ $self->{Channels} }) {
  10         904  
69 5 100       34 $irc->yield(join => $chan => (defined $key ? $key : ()));
70             }
71             }
72             else {
73 0         0 while (my ($chan, $key) = each %{ $self->{Channels} }) {
  0         0  
74 0         0 push @{ $self->{alarm_ids} }, $irc->delay(
75             [join => $chan => (defined $key ? $key : ())],
76             $self->{NickServ_delay},
77 0 0       0 );
78             }
79             }
80 5         35 return PCI_EAT_NONE;
81             }
82              
83             sub S_identified {
84 0     0 0 0 my ($self, $irc) = splice @_, 0, 2;
85              
86 0 0       0 if ($self->{alarm_ids}) {
87 0         0 $irc->delay_remove($_) for @{ $self->{alarm_ids} };
  0         0  
88 0         0 delete $self->{alarm_ids};
89              
90 0         0 while (my ($chan, $key) = each %{ $self->{Channels} }) {
  0         0  
91 0 0       0 $irc->yield(join => $chan => (defined $key ? $key : ()));
92             }
93             }
94 0         0 return PCI_EAT_NONE;
95             }
96              
97             # ERR_BANNEDFROMCHAN
98             sub S_474 {
99 4     4 0 209 my ($self, $irc) = splice @_, 0, 2;
100 4         9 my $chan = ${ $_[2] }->[0];
  4         13  
101 4         18 my $lchan = lc_irc($chan, $irc->isupport('MAPPING'));
102 4 50       73 return PCI_EAT_NONE if !$self->{Retry_when_banned};
103              
104 4         13 my $key = $self->{Channels}{$lchan};
105 4 50       18 $key = $self->{tried_keys}{$lchan} if defined $self->{tried_keys}{$lchan};
106 4 50       70 $irc->delay([join => $chan => (defined $key ? $key : ())], $self->{Retry_when_banned});
107 4         1332 return PCI_EAT_NONE;
108             }
109              
110             sub S_chan_mode {
111 3     3 0 171 my ($self, $irc) = splice @_, 0, 2;
112 3         10 pop @_;
113 3         8 my $chan = ${ $_[1] };
  3         8  
114 3         9 my $mode = ${ $_[2] };
  3         7  
115 3 50       13 my $arg = defined $_[3] ? ${ $_[3] } : '';
  3         9  
116 3         15 my $lchan = lc_irc($chan, $irc->isupport('MAPPING'));
117              
118 3 100       68 $self->{Channels}->{$lchan} = $arg if $mode eq '+k';
119 3 50       14 $self->{Channels}->{$lchan} = '' if $mode eq '-k';
120 3         11 return PCI_EAT_NONE;
121             }
122              
123             sub S_join {
124 11     11 0 612 my ($self, $irc) = splice @_, 0, 2;
125 11         32 my $joiner = parse_user(${ $_[0] });
  11         68  
126 11         228 my $chan = ${ $_[1] };
  11         32  
127 11         54 my $lchan = lc_irc($chan, $irc->isupport('MAPPING'));
128              
129 11 50       223 return PCI_EAT_NONE if $joiner ne $irc->nick_name();
130 11         37 delete $self->{alarm_ids};
131              
132 11 50       55 if (defined $self->{tried_keys}{$lchan}) {
133 11         46 $self->{Channels}->{$lchan} = $self->{tried_keys}{$lchan};
134 11         33 delete $self->{tried_keys}{$lchan};
135             }
136             else {
137 0         0 $self->{Channels}->{$lchan} = '';
138             }
139              
140 11         43 return PCI_EAT_NONE;
141             }
142              
143             sub S_kick {
144 4     4 0 331 my ($self, $irc) = splice @_, 0, 2;
145 4         11 my $chan = ${ $_[1] };
  4         13  
146 4         11 my $victim = ${ $_[2] };
  4         10  
147 4         23 my $lchan = lc_irc($chan, $irc->isupport('MAPPING'));
148              
149 4 50       88 if ($victim eq $irc->nick_name()) {
150 4 50       40 if ($self->{RejoinOnKick}) {
151             $irc->delay([
152             'join',
153             $chan,
154             (defined $self->{Channels}->{$lchan} ? $self->{Channels}->{$lchan} : ())
155 4 50       67 ], $self->{Rejoin_delay});
156             }
157 4         4713 delete $self->{Channels}->{$lchan};
158             }
159 4         25 return PCI_EAT_NONE;
160             }
161              
162             sub S_part {
163 0     0 0 0 my ($self, $irc) = splice @_, 0, 2;
164 0         0 my $parter = parse_user(${ $_[0] });
  0         0  
165 0         0 my $chan = ${ $_[1] };
  0         0  
166 0         0 my $lchan = lc_irc($chan, $irc->isupport('MAPPING'));
167              
168 0 0       0 delete $self->{Channels}->{$lchan} if $parter eq $irc->nick_name();
169 0         0 return PCI_EAT_NONE;
170             }
171              
172             sub U_join {
173 15     15 0 2255 my ($self, $irc) = splice @_, 0, 2;
174 15         43 my (undef, $chan, $key) = split /\s/, ${ $_[0] }, 3;
  15         147  
175 15         120 my $lchan = lc_irc($chan, $irc->isupport('MAPPING'));
176              
177 15 50       378 $self->{tried_keys}->{$lchan} = $key if defined $key;
178 15         65 return PCI_EAT_NONE;
179             }
180              
181             1;
182              
183             =encoding utf8
184              
185             =head1 NAME
186              
187             POE::Component::IRC::Plugin::AutoJoin - A PoCo-IRC plugin which
188             keeps you on your favorite channels
189              
190             =head1 SYNOPSIS
191              
192             use POE qw(Component::IRC::State Component::IRC::Plugin::AutoJoin);
193              
194             my $nickname = 'Chatter';
195             my $server = 'irc.blahblahblah.irc';
196              
197             my %channels = (
198             '#Blah' => '',
199             '#Secret' => 'secret_password',
200             '#Foo' => '',
201             );
202              
203             POE::Session->create(
204             package_states => [
205             main => [ qw(_start irc_join) ],
206             ],
207             );
208              
209             $poe_kernel->run();
210              
211             sub _start {
212             my $irc = POE::Component::IRC::State->spawn(
213             Nick => $nickname,
214             Server => $server,
215             ) or die "Oh noooo! $!";
216              
217             $irc->plugin_add('AutoJoin', POE::Component::IRC::Plugin::AutoJoin->new( Channels => \%channels ));
218             $irc->yield(register => qw(join);
219             $irc->yield(connect => { } );
220             }
221              
222             sub irc_join {
223             my $chan = @_[ARG1];
224             $irc->yield(privmsg => $chan => "hi $channel!");
225             }
226              
227              
228             =head1 DESCRIPTION
229              
230             POE::Component::IRC::Plugin::AutoJoin is a L
231             plugin. If you get disconnected, the plugin will join all the channels you were
232             on the next time it gets connected to the IRC server. It can also rejoin a
233             channel if the IRC component gets kicked from it. It keeps track of channel
234             keys so it will be able to rejoin keyed channels in case of reconnects/kicks.
235              
236             If a L
237             plugin has been added to the IRC component, then AutoJoin will wait for a
238             reply from NickServ before joining channels on connect.
239              
240             This plugin requires the IRC component to be
241             L or a subclass thereof.
242              
243             =head1 METHODS
244              
245             =head2 C
246              
247             Takes the following optional arguments:
248              
249             B<'Channels'>, either an array reference of channel names, or a hash reference
250             keyed on channel name, containing the password for each channel. By default it
251             uses the channels the component is already on if you are using
252             L.
253              
254             B<'RejoinOnKick'>, set this to 1 if you want the plugin to try to rejoin a
255             channel (once) if you get kicked from it. Default is 0.
256              
257             B<'Rejoin_delay'>, the time, in seconds, to wait before rejoining a channel
258             after being kicked (if B<'RejoinOnKick'> is on). Default is 5.
259              
260             B<'Retry_when_banned'>, if you can't join a channel due to a ban, set this
261             to the number of seconds to wait between retries. Default is 0 (disabled).
262              
263             B<'NickServ_delay'>, how long (in seconds) to wait for a reply from NickServ
264             before joining channels. Default is 5.
265              
266             Returns a plugin object suitable for feeding to
267             L's C method.
268              
269             =head1 AUTHOR
270              
271             Hinrik Ern SigurEsson, hinrik.sig@gmail.com
272              
273             =cut