Skip to content

Commit

Permalink
Added Console.pm from gumbynet source. Added applicable test for it.
Browse files Browse the repository at this point in the history
  • Loading branch information
bingos committed Nov 24, 2005
1 parent 1fac6c2 commit 916af58
Show file tree
Hide file tree
Showing 5 changed files with 390 additions and 0 deletions.
2 changes: 2 additions & 0 deletions Changes
Expand Up @@ -12,6 +12,8 @@ Revision history for Perl extension POE::Component::IRC.
- Added raw_events() method to enable/disable/display current irc_raw.
- README updates. Notably to mention PoCo-SSLify for SSL links.
- Stole japhy's ISupport plugin for .. erm .. new ISupport plugin >;]
- Added CTCP.pm from gumbynet source. Added applicable test for it.
- Added Console.pm from gumbynet source. Added applicable test for it.

4.74 Wed Oct 26 09:15:21 BST 2005
- *sigh* another problem fixed with the new dns code.
Expand Down
2 changes: 2 additions & 0 deletions MANIFEST
Expand Up @@ -4,6 +4,7 @@ lib/POE/Component/IRC/Test/Plugin.pm
lib/POE/Component/IRC/Plugin/BotAddressed.pm
lib/POE/Component/IRC/Plugin/BotTraffic.pm
lib/POE/Component/IRC/Plugin/Connector.pm
lib/POE/Component/IRC/Plugin/Console.pm
lib/POE/Component/IRC/Plugin/CTCP.pm
lib/POE/Component/IRC/Plugin/ISupport.pm
lib/POE/Component/IRC/Plugin/Whois.pm
Expand Down Expand Up @@ -50,4 +51,5 @@ t/plugins/02_botaddressed.t
t/plugins/03_bottraffic.t
t/plugins/04_isupport.t
t/plugins/05_ctcp.t
t/plugins/06_console.t
t/testsuite_01_plugin.t
5 changes: 5 additions & 0 deletions examples/simpleclient.pl
Expand Up @@ -38,12 +38,14 @@ sub _start {
POE::Wheel::ReadLine->new( InputEvent => 'got_input' );
$heap->{readline_wheel}->get("> ");
$irc->yield( register => 'all' );
undef;
}

sub _stop {
delete $_[HEAP]->{readline_wheel};
$irc->yield( unregister => 'all' );
$irc->yield( 'shutdown' );
undef;
}

sub got_input {
Expand Down Expand Up @@ -71,6 +73,7 @@ sub got_input {
}

$heap->{readline_wheel}->get("> ") if ( $heap->{readline_wheel} );
undef;
}

sub parse_input {
Expand All @@ -95,6 +98,7 @@ sub parse_input {
$heap->{readline_wheel}->put($cmd . " " . join(' ',@args) );
}
}
undef;
}

sub _default {
Expand Down Expand Up @@ -126,4 +130,5 @@ sub irc_public {
my ($chan) = $where->[0];

$heap->{readline_wheel}->put($chan . ':<' . $nick . '> ' . $what);
undef;
}
310 changes: 310 additions & 0 deletions lib/POE/Component/IRC/Plugin/Console.pm
@@ -0,0 +1,310 @@
package POE::Component::IRC::Plugin::Console;

use strict;
use warnings;
use POE qw(Wheel::SocketFactory Wheel::ReadWrite Filter::IRCD Filter::Line Filter::Stackable);
use POE::Component::IRC::Plugin qw( :ALL );

sub new {
my ($package) = shift;

my $self = bless { @_ }, $package;

return $self;
}

sub PCI_register {
my ($self,$irc) = splice @_, 0, 2;

$self->{irc} = $irc;

$irc->plugin_register( $self, 'SERVER', qw(all) );
$irc->plugin_register( $self, 'USER', qw(all) );

$self->{SESSION_ID} = POE::Session->create(
object_states => [
$self => [ qw(_client_error _client_flush _client_input _listener_accept _listener_failed _start _shutdown) ],
],
)->ID();

return 1;
}

sub PCI_unregister {
my ($self,$irc) = splice @_, 0, 2;

delete ( $self->{irc} );

$poe_kernel->post( $self->{SESSION_ID} => '_shutdown' );
$poe_kernel->refcount_decrement( $self->{SESSION_ID}, __PACKAGE__ );
return 1;
}

sub _default {
my ($self,$irc) = splice @_, 0, 2;
my ($event) = shift;
my (@args) = map { $$_ } @_;
my (@output) = ( "$event: " );

foreach my $arg ( @args ) {
if ( ref($arg) eq 'ARRAY' ) {
push( @output, "[" . join(" ,", @$arg ) . "]" );
} else {
push ( @output, "'$arg'" );
}
}

foreach my $wheel_id ( keys %{ $self->{wheels} } ) {
next if ( $self->{exit}->{ $wheel_id } or ( not defined ( $self->{wheels}->{ $wheel_id } ) ) );
$self->{wheels}->{ $wheel_id }->put( join(' ', @output ) );
}
return PCI_EAT_NONE;
}

sub _start {
my ($kernel,$self) = @_[KERNEL,OBJECT];

$self->{SESSION_ID} = $_[SESSION]->ID();
$kernel->refcount_increment( $self->{SESSION_ID}, __PACKAGE__ );
$self->{ircd_filter} = POE::Filter::Stackable->new();
$self->{ircd_filter}->push( POE::Filter::Line->new(), POE::Filter::IRCD->new() );

$self->{listener} = POE::Wheel::SocketFactory->new(
BindAddress => 'localhost',
BindPort => $self->{bindport} || 0,
SuccessEvent => '_listener_accept',
FailureEvent => '_listener_failed',
Reuse => 'yes',
);
if ( $self->{listener} ) {
$self->{irc}->_send_event( 'irc_console_service' => $self->{listener}->getsockname() );
} else {
my $irc = $self->{irc};
$irc->plugin_del( $self );
}
undef;
}

sub _listener_accept {
my ($kernel,$self,$socket,$peeradr,$peerport) = @_[KERNEL,OBJECT,ARG0 .. ARG2];

my ($wheel) = POE::Wheel::ReadWrite->new(
Handle => $socket,
InputFilter => $self->{ircd_filter},
OutputFilter => POE::Filter::Line->new(),
InputEvent => '_client_input',
ErrorEvent => '_client_error',
FlushedEvent => '_client_flush',
);

unless ( $wheel ) {
$self->{irc}->_send_event( 'irc_console_rw_fail' => $peeradr => $peerport );
return undef;
}

my $wheel_id = $wheel->ID();
$self->{wheels}->{ $wheel_id } = $wheel;
$self->{authed}->{ $wheel_id } = 0;
$self->{exit}->{ $wheel_id } = 0;
$self->{irc}->_send_event( 'irc_console_connect' => $peeradr => $peerport => $wheel_id );
undef;
}

sub _listener_failed {
delete ( $_[OBJECT]->{listener} );
undef;
}

sub _client_input {
my ($kernel,$self,$input,$wheel_id) = @_[KERNEL,OBJECT,ARG0,ARG1];

if ( $self->{authed}->{ $wheel_id } and lc ( $input->{command} ) eq 'exit' ) {
$self->{exit}->{ $wheel_id } = 1;
$self->{wheels}->{ $wheel_id }->put("ERROR * quiting *") if ( defined ( $self->{wheels}->{ $wheel_id } ) );
return;
}
if ( $self->{authed}->{ $wheel_id } ) {
$self->{irc}->yield( lc ( $input->{command} ) => @{ $input->{params} } );
return;
}
if ( lc ( $input->{command} ) eq 'pass' and $input->{params}->[0] eq $self->{password} ) {
$self->{authed}->{ $wheel_id } = 1;
$self->{wheels}->{ $wheel_id }->put("NOTICE * Password accepted *");
$self->{irc}->_send_event( 'irc_console_authed' => $wheel_id );
return;
}
$self->{wheels}->{ $wheel_id }->put("NOTICE * Password required * enter PASS <password> *");
undef;
}

sub _client_flush {
my ($self,$wheel_id) = @_[OBJECT,ARG0];

return unless ( $self->{exit}->{ $wheel_id } );
delete $self->{wheels}->{ $wheel_id };
undef;
}

sub _client_error {
my ($self,$wheel_id) = @_[OBJECT,ARG3];

delete ( $self->{wheels}->{ $wheel_id } );
delete ( $self->{authed}->{ $wheel_id } );
$self->{irc}->_send_event( 'irc_console_close' => $wheel_id );
undef;
}

sub _shutdown {
my ($kernel,$self) = @_[KERNEL,OBJECT];

delete ( $self->{listener} );
delete ( $self->{wheels} );
delete ( $self->{authed} );
undef;
}

sub getsockname {
my ($self) = shift;
return undef unless $self->{listener};
return $self->{listener}->getsockname();
}

1;
__END__
=head1 NAME
POE::Component::IRC::Plugin::Console - a lightweight debugging and control console for L<POE::Component::IRC> bots.
=head1 SYNOPSIS
use POE qw(Component::IRC Component::IRC::Plugin::Console);
my ($nickname) = 'Flibble' . $$;
my ($ircname) = 'Flibble the Sailor Bot';
my ($ircserver) = 'irc.blahblahblah.irc';
my ($port) = 6667;
my ($bindport) = 6969;
my (@channels) = ( '#Blah', #Foo', '#Bar' );
my ($irc) = POE::Component::IRC->spawn(
nick => $nickname,
server => $ircserver,
port => $port,
ircname => $ircname,
) or die "Oh noooo! $!";
POE::Session->create(
package_states => [
'main' => [ qw(_start irc_001 irc_console_service irc_console_connect
irc_console_authed irc_console_close irc_console_rw_fail) ],
],
);
$poe_kernel->run();
exit 0;
sub _start {
$irc->plugin_add( 'Console' => POE::Component::IRC::Plugin::Console->new(
bindport => $bindport, password => "opensesame" );
$irc->yield( register => 'all' );
$irc->yield( connect => { } );
undef;
}
sub irc_001 {
$irc->yield( join => $_ ) for @channels;
undef;
}
sub irc_console_service {
my ($getsockname) = $_[ARG0];
undef;
}
sub irc_console_connect {
my ($peeradr,$peerport,$wheel_id) = @_[ARG0,ARG1,ARG2];
undef;
}
sub irc_console_authed {
my ($wheel_id) = $_[ARG0];
undef;
}
sub irc_console_close {
my ($wheel_id) = $_[ARG0];
undef;
}
sub irc_console_rw_fail {
my ($peeradr,$peerport) = @_[ARG0,ARG1];
undef;
}
=head1 DESCRIPTION
POE::Component::IRC::Plugin::Console is a L<POE::Component::IRC> plugin that provides an interactive console running over
the loopback network. One connects to the listening socket using a telnet client ( or equivalent ), authenticate using
the applicable password. Once authed one will receive all events that are processed through the component. One may also
issue all the documented component commands.
=head1 CONSTRUCTOR
=over
=item new
Takes two arguments:
'password', the password to set for *all* console connections;
'bindport', specify a particular port to bind to, defaults to 0, ie. randomly allocated;
=back
=head1 METHODS
=over
=item getsockname
Gives access to the underlying listener's getsockname() method. See L<POE::Wheel::SocketFactory> for details.
=back
=head1 EVENTS
The plugin generates the following additional L<POE::Component::IRC> events:
=over
=item irc_console_service
Emitted when a listener is successfully spawned. ARG0 is the result of getsockname(), see above for details.
=item irc_console_connect
Emitted when a client connects to the console. ARG0 is the peeradr, ARG1 is the peer port and ARG2 is the wheel id of the connection.
=item irc_console_authed
Emitted when a client has successfully provided a valid password. ARG0 is the wheel id of the connection.
=item irc_console_close
Emitted when a client terminates a connection. ARG0 is the wheel id of the connection.
=item irc_console_rw_fail
Emitted when a wheel::rw could not be created on a socket. ARG0 is the peeradr, ARG1 is the peer port.
=back
=head1 AUTHOR
Chris 'BinGOs' Williams
=head1 SEE ALSO
L<POE::Component::IRC>, L<POE::Wheel::SocketFactory>.

0 comments on commit 916af58

Please sign in to comment.