Skip to content

Commit

Permalink
Only process the first CTCP chunk we find in a message
Browse files Browse the repository at this point in the history
  • Loading branch information
hinrik committed Sep 3, 2010
1 parent 666b1ee commit e824846
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 1 deletion.
3 changes: 3 additions & 0 deletions Changes
@@ -1,6 +1,9 @@
Revision history for Perl extension POE::Component::IRC.

{{$NEXT}}
- Only process the first CTCP chunk we find in a message. This prevents
someone from flooding our outgoing queue by having us e.g. reply to 20
VERSION requests at a time.

6.37 Tue Aug 17 22:53:22 GMT 2010
- Make all warnings fatal
Expand Down
6 changes: 5 additions & 1 deletion lib/POE/Filter/IRC/Compat.pm
Expand Up @@ -296,7 +296,11 @@ sub _get_ctcp {

my $events = [ ];
my ($name, $args);
CTCP: for my $string (@$ctcp) {

# We only process the first CTCP. The only people who send multiple ones
# are those who are trying to flood our outgoing queue anyway (e.g. by
# having us reply to 20 VERSION requests at a time).
CTCP: for my $string ($ctcp->[0]) {
if (!(($name, $args) = $string =~ /^(\w+)(?: +(.*))?/)) {
defined $nick
? do { warn "Received malformed CTCP message from $nick: $string\n" if $self->{debug} }
Expand Down
130 changes: 130 additions & 0 deletions t/02_behavior/15_no_stacked_ctcp.t
@@ -0,0 +1,130 @@
use strict;
use warnings FATAL => 'all';
use lib 't/inc';
use POE qw(Wheel::SocketFactory);
use Socket;
use POE::Component::IRC;
use POE::Component::Server::IRC;
use Test::More tests => 6;

my $bot1 = POE::Component::IRC->spawn(
Flood => 1,
plugin_debug => 1,
);
my $bot2 = POE::Component::IRC->spawn(
Flood => 1,
plugin_debug => 1,
);
my $ircd = POE::Component::Server::IRC->spawn(
Auth => 0,
AntiFlood => 0,
);

POE::Session->create(
package_states => [
main => [qw(
_start
_config_ircd
_shutdown
irc_001
irc_ctcp_version
irc_msg
irc_disconnected
)],
],
);

$poe_kernel->run();

sub _start {
my ($kernel) = $_[KERNEL];

my $ircd_port = get_port() or $kernel->yield(_shutdown => 'No free port');
$kernel->yield(_config_ircd => $ircd_port);
$kernel->delay(_shutdown => 60, 'Timed out');
}

sub get_port {
my $wheel = POE::Wheel::SocketFactory->new(
BindAddress => '127.0.0.1',
BindPort => 0,
SuccessEvent => '_fake_success',
FailureEvent => '_fake_failure',
);

return if !$wheel;
return unpack_sockaddr_in($wheel->getsockname()) if wantarray;
return (unpack_sockaddr_in($wheel->getsockname))[0];
}

sub _config_ircd {
my ($kernel, $port) = @_[KERNEL, ARG0];

$ircd->yield(add_listener => Port => $port);

$bot1->yield(register => 'all');
$bot1->yield(connect => {
nick => 'TestBot1',
server => '127.0.0.1',
port => $port,
});

$bot2->yield(register => 'all');
$bot2->yield(connect => {
nick => 'TestBot2',
server => '127.0.0.1',
port => $port,
});
}

sub irc_001 {
my $heap = $_[HEAP];
my $irc = $_[SENDER]->get_heap();

pass('Logged in');
$heap->{connected}++;
return if $heap->{connected} != 2;

$bot1->yield(privmsg => $bot2->nick_name(), "\001VERSION\001\001VERSION\001");
$bot1->yield(privmsg => $bot2->nick_name(), "goodbye");
$irc->yield(join => '#testchannel');
}

sub irc_ctcp_version {
my ($sender, $heap) = @_[SENDER, HEAP];
my $irc = $sender->get_heap();

$heap->{got_ctcp}++;
if ($heap->{got_ctcp} == 1) {
pass('Got first CTCP VERSION');
}
elsif ($heap->{got_ctcp} == 2) {
fail('Got second CTCP VERSION');
}
}

sub irc_msg {
my ($sender, $heap, $msg) = @_[SENDER, HEAP, ARG2];
my $irc = $sender->get_heap();

is($msg, 'goodbye', 'Got private message');
$bot1->yield('quit');
$bot2->yield('quit');
}
sub irc_disconnected {
my ($kernel, $heap) = @_[KERNEL, HEAP];
pass('irc_disconnected');
$heap->{count}++;
$kernel->yield('_shutdown') if $heap->{count} == 2;
}

sub _shutdown {
my ($kernel, $error) = @_[KERNEL, ARG0];
fail($error) if defined $error;

$kernel->alarm_remove_all();
$ircd->yield('shutdown');
$bot1->yield('shutdown');
$bot2->yield('shutdown');
}

0 comments on commit e824846

Please sign in to comment.