1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250
|
package POE::Component::IRC::Plugin::AutoJoin;
BEGIN {
$POE::Component::IRC::Plugin::AutoJoin::AUTHORITY = 'cpan:HINRIK';
}
BEGIN {
$POE::Component::IRC::Plugin::AutoJoin::VERSION = '6.35';
}
use strict;
use warnings;
use Carp;
use POE::Component::IRC::Plugin qw(:ALL);
use POE::Component::IRC::Common qw(parse_user l_irc);
sub new {
my ($package) = shift;
croak "$package requires an even number of arguments" if @_ & 1;
my %self = @_;
return bless \%self, $package;
}
sub PCI_register {
my ($self, $irc) = @_;
if (!$irc->isa('POE::Component::IRC::State')) {
die __PACKAGE__ . ' requires PoCo::IRC::State or a subclass thereof';
}
if (!$self->{Channels}) {
for my $chan (keys %{ $irc->channels() }) {
my $lchan = l_irc($chan, $irc->isupport('MAPPING'));
my $key = $irc->is_channel_mode_set($chan, 'k')
? $irc->channel_key($chan)
: ''
;
$self->{Channels}->{$lchan} = $key;
}
}
elsif (ref $self->{Channels} eq 'ARRAY') {
my %channels;
$channels{l_irc($_, $irc->isupport('MAPPING'))} = '' for @{ $self->{Channels} };
$self->{Channels} = \%channels;
}
$self->{tried_keys} = { };
$self->{Rejoin_delay} = 5 if !defined $self->{Rejoin_delay};
$irc->plugin_register($self, 'SERVER', qw(001 004 474 isupport chan_mode join kick part));
$irc->plugin_register($self, 'USER', qw(join));
return 1;
}
sub PCI_unregister {
return 1;
}
sub S_001 {
my ($self, $irc) = splice @_, 0, 2;
delete $self->{masked_key};
return PCI_EAT_NONE;
}
# RPL_MYINFO
sub S_004 {
my ($self, $irc) = splice @_, 0, 2;
my $version = ${ $_[2] }->[1];
# ircu returns '*' to non-ops instead of the real channel key
$self->{masked_key} = 1 if $version =~ /^u\d/;
return PCI_EAT_NONE;
}
# we join channels after irc_isupport for two reasons:
# a) the NickServID plugin needs to waits for irc_004 before identifying,
# and users may want to be cloaked before joining any channels,
# b) if the server supports CAPAB IDENTIFY-MSG (FreeNode), that will be
# checked for after the irc_isupport (right before we try to join channels)
sub S_isupport {
my ($self, $irc) = splice @_, 0, 2;
while (my ($chan, $key) = each %{ $self->{Channels} }) {
$irc->yield(join => $chan => $key);
}
return PCI_EAT_NONE;
}
# ERR_BANNEDFROMCHAN
sub S_474 {
my ($self, $irc) = splice @_, 0, 2;
my $chan = ${ $_[2] }->[0];
my $lchan = l_irc($chan, $irc->isupport('MAPPING'));
return PCI_EAT_NONE if !$self->{Retry_when_banned};
my $key = $self->{Channels}{$lchan};
$key = $self->{tried_keys}{$lchan} if defined $self->{tried_keys}{$lchan};
$irc->delay([join => $chan => $key], $self->{Retry_when_banned});
return PCI_EAT_NONE;
}
sub S_chan_mode {
my ($self, $irc) = splice @_, 0, 2;
my $chan = ${ $_[1] };
my $mode = ${ $_[2] };
my $arg = ${ $_[3] };
my $lchan = l_irc($chan, $irc->isupport('MAPPING'));
$self->{Channels}->{$lchan} = $arg if $mode eq '+k';
$self->{Channels}->{$lchan} = '' if $mode eq '-k';
return PCI_EAT_NONE;
}
sub S_join {
my ($self, $irc) = splice @_, 0, 2;
my $joiner = parse_user(${ $_[0] });
my $chan = ${ $_[1] };
my $lchan = l_irc($chan, $irc->isupport('MAPPING'));
return PCI_EAT_NONE if $joiner ne $irc->nick_name();
if (defined $self->{tried_keys}{$lchan}) {
$self->{Channels}->{$lchan} = $self->{tried_keys}{$lchan};
delete $self->{tried_keys}{$lchan};
}
else {
$self->{Channels}->{$lchan} = '';
}
return PCI_EAT_NONE;
}
sub S_kick {
my ($self, $irc) = splice @_, 0, 2;
my $chan = ${ $_[1] };
my $victim = ${ $_[2] };
my $lchan = l_irc($chan, $irc->isupport('MAPPING'));
if ($victim eq $irc->nick_name()) {
if ($self->{RejoinOnKick}) {
$irc->delay([join => $chan => $self->{Channels}->{$lchan}], $self->{Rejoin_delay});
}
delete $self->{Channels}->{$lchan};
}
return PCI_EAT_NONE;
}
sub S_part {
my ($self, $irc) = splice @_, 0, 2;
my $parter = parse_user(${ $_[0] });
my $chan = ${ $_[1] };
my $lchan = l_irc($chan, $irc->isupport('MAPPING'));
delete $self->{Channels}->{$lchan} if $parter eq $irc->nick_name();
return PCI_EAT_NONE;
}
sub U_join {
my ($self, $irc) = splice @_, 0, 2;
my (undef, $chan, $key) = split /\s/, ${ $_[0] }, 3;
my $lchan = l_irc($chan, $irc->isupport('MAPPING'));
$self->{tried_keys}->{$lchan} = $key if defined $key;
return PCI_EAT_NONE;
}
1;
__END__
=encoding utf8
=head1 NAME
POE::Component::IRC::Plugin::AutoJoin - A PoCo-IRC plugin which
keeps you on your favorite channels
=head1 SYNOPSIS
use POE qw(Component::IRC::State Component::IRC::Plugin::AutoJoin);
my $nickname = 'Chatter';
my $server = 'irc.blahblahblah.irc';
my %channels = (
'#Blah' => '',
'#Secret' => 'secret_password',
'#Foo' => '',
);
POE::Session->create(
package_states => [
main => [ qw(_start irc_join) ],
],
);
$poe_kernel->run();
sub _start {
my $irc = POE::Component::IRC::State->spawn(
Nick => $nickname,
Server => $server,
) or die "Oh noooo! $!";
$irc->plugin_add('AutoJoin', POE::Component::IRC::Plugin::AutoJoin->new( Channels => \%channels ));
$irc->yield(register => qw(join);
$irc->yield(connect => { } );
}
sub irc_join {
my $chan = @_[ARG1];
$irc->yield(privmsg => $chan => "hi $channel!");
}
=head1 DESCRIPTION
POE::Component::IRC::Plugin::AutoJoin is a L<POE::Component::IRC|POE::Component::IRC>
plugin. If you get disconnected, the plugin will join all the channels you were
on the next time it gets connected to the IRC server. It can also rejoin a
channel if the IRC component gets kicked from it. It keeps track of channel
keys so it will be able to rejoin keyed channels in case of reconnects/kicks.
This plugin requires the IRC component to be
L<POE::Component::IRC::State|POE::Component::IRC::State> or a subclass thereof.
=head1 METHODS
=head2 C<new>
Two optional arguments:
B<'Channels'>, either an array reference of channel names, or a hash reference
keyed on channel name, containing the password for each channel. By default it
uses the channels the component is already on, if any.
B<'RejoinOnKick'>, set this to 1 if you want the plugin to try to rejoin a
channel (once) if you get kicked from it. Default is 0.
B<'Rejoin_delay'>, the time, in seconds, to wait before rejoining a channel
after being kicked (if B<'RejoinOnKick'> is on). Default is 5.
B<'Retry_when_banned'>, if you can't join a channel due to a ban, set this
to the number of seconds to wait between retries. Default is 0 (disabled).
Returns a plugin object suitable for feeding to
L<POE::Component::IRC|POE::Component::IRC>'s C<plugin_add> method.
=head1 AUTHOR
Hinrik E<Ouml>rn SigurE<eth>sson, hinrik.sig@gmail.com
=cut
|