File Coverage

blib/lib/POEx/IRC/Client/Lite.pm
Criterion Covered Total %
statement 102 171 59.6
branch 16 38 42.1
condition 6 20 30.0
subroutine 31 52 59.6
pod 11 20 55.0
total 166 301 55.1


line stmt bran cond sub pod time code
1             package POEx::IRC::Client::Lite;
2             $POEx::IRC::Client::Lite::VERSION = '0.004002';
3 1     1   586 use strictures 2;
  1         7  
  1         40  
4              
5 1     1   182 use Carp 'confess';
  1         1  
  1         43  
6              
7 1     1   4 use POE;
  1         1  
  1         8  
8 1     1   252 use POEx::IRC::Backend;
  1         1  
  1         22  
9              
10 1     1   4 use IRC::Message::Object 'ircmsg';
  1         1  
  1         10  
11 1     1   682 use IRC::Toolkit::Case;
  1         1840  
  1         9  
12 1     1   290 use IRC::Toolkit::CTCP;
  1         1  
  1         8  
13              
14 1     1   202 use POE::Filter::IRCv3;
  1         1  
  1         22  
15              
16 1     1   3 use Scalar::Util 'blessed';
  1         1  
  1         36  
17              
18 1     1   4 use Types::Standard -all;
  1         1  
  1         10  
19              
20 1     1   24207 use MooX::Role::Pluggable::Constants;
  1         300  
  1         51  
21              
22              
23 1     1   5 use Moo;
  1         2  
  1         6  
24             with 'MooX::Role::POE::Emitter';
25              
26              
27             =for Pod::Coverage has_(\w+)
28              
29             =cut
30              
31              
32             has server => (
33             required => 1,
34             is => 'ro',
35             isa => Str,
36             writer => 'set_server',
37             );
38              
39             has nick => (
40             required => 1,
41             is => 'ro',
42             isa => Str,
43             writer => 'set_nick',
44             );
45              
46             after set_nick => sub {
47             my ($self, $nick) = @_;
48             if ($self->_has_conn && $self->conn->has_wheel) {
49             ## Try to change IRC nickname as well.
50             $self->nick($nick)
51             }
52             };
53              
54             has bindaddr => (
55             lazy => 1,
56             is => 'ro',
57             isa => Defined,
58             writer => 'set_bindaddr',
59             predicate => 'has_bindaddr',
60             builder => sub {
61 0     0   0 my ($self) = @_;
62 0 0 0     0 $self->has_ipv6 && $self->ipv6 ?
63             '::0' : '0.0.0.0'
64             },
65             );
66              
67             has ipv6 => (
68             lazy => 1,
69             is => 'ro',
70             isa => Bool,
71             writer => 'set_ipv6',
72             predicate => 'has_ipv6',
73 0     0   0 builder => sub { 0 },
74             );
75              
76             has ssl => (
77             lazy => 1,
78             is => 'ro',
79             isa => Bool,
80             writer => 'set_ssl',
81 1     1   981 builder => sub { 0 },
82             );
83              
84             has ssl_opts => (
85             lazy => 1,
86             is => 'ro',
87             isa => Maybe[ArrayRef],
88             writer => 'set_ssl_opts',
89 1     1   551 builder => sub { undef },
90             );
91              
92             has pass => (
93             lazy => 1,
94             is => 'ro',
95             isa => Str,
96             writer => 'set_pass',
97             predicate => 'has_pass',
98             clearer => 'clear_pass',
99 0     0   0 builder => sub { '' },
100             );
101              
102             has port => (
103             lazy => 1,
104             is => 'ro',
105             isa => Num,
106             writer => 'set_port',
107             predicate => 'has_port',
108 0     0   0 builder => sub { 6667 },
109             );
110              
111             has realname => (
112             lazy => 1,
113             is => 'ro',
114             isa => Str,
115             writer => 'set_realname',
116             predicate => 'has_realname',
117 1     1   914 builder => sub { __PACKAGE__ },
118             );
119              
120             has reconnect => (
121             lazy => 1,
122             is => 'ro',
123             isa => Num,
124             writer => 'set_reconnect',
125 0     0   0 builder => sub { 120 },
126             );
127              
128             has username => (
129             lazy => 1,
130             is => 'ro',
131             isa => Str,
132             writer => 'set_username',
133             predicate => 'has_username',
134 0     0   0 builder => sub { 'ircplug' },
135             );
136              
137             ### Typically internal:
138             has backend => (
139             lazy => 1,
140             is => 'ro',
141             isa => InstanceOf['POEx::IRC::Backend'],
142             builder => sub {
143 1     1   488 my $filter = POE::Filter::IRCv3->new(colonify => 0);
144 1         33 POEx::IRC::Backend->new(filter_irc => $filter)
145             }
146              
147             );
148              
149             has conn => (
150             lazy => 1,
151             weak_ref => 1,
152             is => 'ro',
153             isa => Object,
154             writer => '_set_conn',
155             predicate => '_has_conn',
156             clearer => '_clear_conn',
157             );
158              
159              
160             sub BUILD {
161 1     1 0 16088 my ($self) = @_;
162              
163             $self->set_object_states(
164             [
165             $self => [ qw/
166             ircsock_input
167             ircsock_connector_open
168             ircsock_connector_failure
169             ircsock_disconnect
170             / ],
171             $self => {
172             emitter_started => '_emitter_started',
173             connect => '_connect',
174             disconnect => '_disconnect',
175             send => '_send',
176             privmsg => '_privmsg',
177             ctcp => '_ctcp',
178             notice => '_notice',
179             mode => '_mode',
180             join => '_join',
181             part => '_part',
182             },
183             (
184 1 50       13 $self->has_object_states ? @{ $self->object_states } : ()
  0         0  
185             ),
186             ],
187             );
188              
189 1         1537 $self->_start_emitter;
190             }
191              
192             sub _emitter_started {
193 1     1   8477 my ($kernel, $self) = @_[KERNEL, OBJECT];
194 1 50       4 $self->backend->spawn(
195             ( $self->ssl_opts ? (ssl_opts => $self->ssl_opts) : () ),
196             );
197 1         432 $kernel->post( $self->backend->session_id => 'register' );
198             }
199              
200             sub stop {
201 1     1 1 448629 my ($self) = @_;
202 1         54 $poe_kernel->post( $self->backend->session_id => 'shutdown' );
203 1         66 $self->_shutdown_emitter;
204             }
205              
206             ### ircsock_*
207              
208             sub ircsock_connector_open {
209 1     1 0 12562 my (undef, $self, $conn) = @_[KERNEL, OBJECT, ARG0];
210              
211 1         3 $self->_set_conn( $conn );
212              
213 1 50       499 if ($self->process( preregister => $conn ) == EAT_ALL) {
214 0         0 $self->_clear_conn;
215 0         0 $self->emit( irc_connector_killed => $conn );
216             return
217 0         0 }
218              
219 1         92 my @pre;
220 1 50 33     8 if ($self->has_pass && (my $pass = $self->pass)) {
221 0         0 push @pre, ircmsg(
222             command => 'pass',
223             params => [
224             $pass
225             ],
226             )
227             }
228             $self->send(
229 1         4 @pre,
230             ircmsg(
231             command => 'user',
232             params => [
233             $self->username,
234             '*', '*',
235             $self->realname
236             ],
237             ),
238             ircmsg(
239             command => 'nick',
240             params => [ $self->nick ],
241             ),
242             );
243              
244 1         82 $self->emit( irc_connected => $conn );
245             }
246              
247             sub ircsock_connector_failure {
248 0     0 0 0 my (undef, $self) = @_[KERNEL, OBJECT];
249             #my $connector = $_[ARG0];
250             #my ($op, $errno, $errstr) = @_[ARG1 .. ARG3];
251              
252 0 0       0 $self->_clear_conn if $self->_has_conn;
253              
254 0         0 $self->emit( irc_connector_failed => @_[ARG0 .. $#_] );
255            
256 0 0       0 $self->timer( $self->reconnect => 'connect') if $self->reconnect;
257             }
258              
259             sub ircsock_disconnect {
260 1     1 0 1262 my (undef, $self) = @_[KERNEL, OBJECT];
261 1         3 my ($conn, $str) = @_[ARG0, ARG1];
262            
263 1 50       8 $self->_clear_conn if $self->_has_conn;
264              
265 1         301 $self->emit( irc_disconnected => $str, $conn );
266             }
267              
268             sub ircsock_input {
269 3     3 0 2238 my (undef, $self, $ircev) = @_[KERNEL, OBJECT, ARG1];
270              
271 3 50       11 return unless $ircev->command;
272 3         14 $self->emit( 'irc_'.lc($ircev->command) => $ircev)
273             }
274              
275              
276             ### Our IRC-related handlers.
277              
278             sub N_irc_433 {
279             ## Nickname in use.
280 0     0 0 0 my (undef, $self) = splice @_, 0, 2;
281 0         0 my $ircev = ${ $_[0] };
  0         0  
282              
283 0   0     0 my $taken = $ircev->params->[1] || $self->nick;
284              
285 0         0 $self->send(
286             ircmsg(
287             command => 'nick',
288             params => [ $taken . '_' ],
289             )
290             );
291              
292 0         0 EAT_NONE
293             }
294              
295             sub N_irc_ping {
296 0     0 0 0 my (undef, $self) = splice @_, 0, 2;
297 0         0 my $ircev = ${ $_[0] };
  0         0  
298              
299             $self->send(
300             ircmsg(
301             command => 'pong',
302 0         0 params => [ @{ $ircev->params } ],
  0         0  
303             )
304             );
305              
306 0         0 EAT_NONE
307             }
308              
309             sub N_irc_privmsg {
310 2     2 0 518 my (undef, $self) = splice @_, 0, 2;
311 2         3 my $ircev = ${ $_[0] };
  2         3  
312              
313 2 100       5 if (my $ctcp_ev = ctcp_extract($ircev)) {
314 1         861 $self->emit_now( 'irc_'.$ctcp_ev->command => $ctcp_ev );
315 1         385 return EAT_ALL
316             }
317              
318 1 50 33     472 if ($ircev->has_tags && $ircev->get_tag('intent') eq 'ACTION') {
319 0         0 $self->emit_now( irc_ctcp_action => $ircev );
320 0         0 return EAT_ALL
321             }
322              
323 1         15 my $prefix = substr $ircev->params->[0], 0, 1;
324             ## FIXME
325             ## parse isupports as we get them, attempt to find chan prefixes
326             ## attrib defaulting to following:
327 1 50       7 if (grep {; $_ eq $prefix } ('#', '&', '+') ) {
  3         5  
328 1         5 $self->emit_now( irc_public_msg => $ircev )
329             } else {
330 0         0 $self->emit_now( irc_private_msg => $ircev )
331             }
332              
333 1         311 EAT_ALL
334             }
335              
336             sub N_irc_notice {
337 0     0 0 0 my (undef, $self) = splice @_, 0, 2;
338 0         0 my $ircev = ${ $_[0] };
  0         0  
339              
340 0 0       0 if (my $ctcp_ev = ctcp_extract($ircev)) {
341 0         0 $self->emit_now( 'irc_'.$ctcp_ev->command => $ctcp_ev );
342 0         0 return EAT_ALL
343             }
344              
345             EAT_NONE
346 0         0 }
347              
348              
349              
350             ### Public
351              
352             ## Since the retval of yield() is $self, many of these can be chained:
353             ## $client->connect->join(@channels)->privmsg(
354             ## join(',', @channels), 'hello!'
355             ## );
356              
357             sub connect {
358 1     1 1 400 my $self = shift;
359 1         5 $self->yield( connect => @_ )
360             }
361              
362             sub _connect {
363 1     1   346 my (undef, $self) = @_[KERNEL, OBJECT];
364            
365 1 50       19 $self->backend->create_connector(
    50          
366             remoteaddr => $self->server,
367             remoteport => $self->port,
368             ssl => $self->ssl,
369             (
370             $self->has_ipv6 ? (ipv6 => $self->ipv6) : ()
371             ),
372             (
373             $self->has_bindaddr ? (bindaddr => $self->bindaddr) : ()
374             ),
375             );
376             }
377              
378             sub disconnect {
379 1     1 1 996963 my $self = shift;
380 1         8 $self->yield( disconnect => @_ )
381             }
382              
383             sub _disconnect {
384 1     1   294 my ($kernel, $self) = @_[KERNEL, OBJECT];
385 1   50     4 my $message = $_[ARG0] // 'Leaving';
386              
387 1         24 $self->backend->send(
388             ircmsg(
389             command => 'quit',
390             params => [ $message ],
391             ),
392             $self->conn->wheel_id
393             );
394              
395 1         385 $kernel->alarm('connect');
396              
397 1 50 33     80 $self->backend->disconnect( $self->conn->wheel->ID )
398             if $self->_has_conn and $self->conn->has_wheel;
399             }
400              
401             sub send_raw_line {
402 0     0 1 0 my ($self, $line) = @_;
403 0 0       0 confess "Expected a raw line" unless defined $line;
404 0         0 $self->send( ircmsg(raw_line => $line) );
405             }
406              
407             sub send {
408 4     4 1 3490 my $self = shift;
409 4         11 $self->yield( send => @_ )
410             }
411              
412             sub _send {
413 4     4   1885 my (undef, $self) = @_[KERNEL, OBJECT];
414 4         20 for my $outev (@_[ARG0 .. $#_]) {
415 5 50       131 if ($self->process( outgoing => $outev ) == EAT_ALL) {
416             next
417 0         0 }
418 5         512 $self->backend->send( $outev, $self->conn->wheel_id )
419             }
420             }
421              
422             ## Sugar, and POE-dispatchable counterparts.
423             sub notice {
424 0     0 1 0 my $self = shift;
425 0         0 $self->yield( notice => @_ )
426             }
427              
428             sub _notice {
429 0     0   0 my (undef, $self) = @_[KERNEL, OBJECT];
430 0         0 my ($target, @data) = @_[ARG0 .. $#_];
431 0         0 $self->send(
432             ircmsg(
433             command => 'notice',
434             params => [ $target, join ' ', @data ]
435             )
436             )
437             }
438              
439             sub privmsg {
440 0     0 1 0 my $self = shift;
441 0         0 $self->yield( privmsg => @_ )
442             }
443              
444             sub _privmsg {
445 0     0   0 my (undef, $self) = @_[KERNEL, OBJECT];
446 0         0 my ($target, @data) = @_[ARG0 .. $#_];
447 0         0 $self->send(
448             ircmsg(
449             command => 'privmsg',
450             params => [ $target, join ' ', @data ]
451             )
452             )
453             }
454              
455             sub ctcp {
456 0     0 1 0 my $self = shift;
457 0         0 $self->yield( ctcp => @_ )
458             }
459              
460             sub _ctcp {
461 0     0   0 my (undef, $self) = @_[KERNEL, OBJECT];
462 0         0 my ($type, $target, @data) = @_[ARG0 .. $#_];
463 0         0 my $line = join ' ', uc($type), @data;
464 0         0 my $quoted = ctcp_quote($line);
465 0         0 $self->send(
466             ircmsg(
467             command => 'privmsg',
468             params => [ $target, $quoted ]
469             )
470             )
471             }
472              
473             sub mode {
474 2     2 1 1460 my $self = shift;
475 2         6 $self->yield( mode => @_ )
476             }
477              
478             sub _mode {
479 3     3   282 my (undef, $self) = @_[KERNEL, OBJECT];
480 3         4 my ($target, $mode) = @_[ARG0, ARG1];
481              
482 3 100 66     19 if (blessed $mode && $mode->isa('IRC::Mode::Set')) {
483             ## FIXME tests for same
484             ## FIXME accept an opt to allow passing in MODES= ?
485             ## don't really want to parse/store isupport here
486             ## (stateful subclasses should worry about it)
487 1         4 for my $set ($mode->split_mode_set(4)) {
488 1         1540 $self->call( mode => $target, $set->mode_string )
489             }
490 1         90 return $self
491             }
492              
493             $self->send(
494 2         6 ircmsg(
495             command => 'mode',
496             params => [ $target, $mode ],
497             )
498             )
499             }
500              
501             sub join {
502 0     0 1   my $self = shift;
503 0           $self->yield( join => @_ )
504             }
505              
506             sub _join {
507 0     0     my (undef, $self) = @_[KERNEL, OBJECT];
508 0           my $join_to = CORE::join ',', @_[ARG0 .. $#_];
509 0           $self->send(
510             ircmsg(
511             command => 'join',
512             params => [ $join_to ],
513             )
514             )
515             }
516              
517             sub part {
518 0     0 1   my $self = shift;
519 0           $self->yield( part => @_ )
520             }
521              
522             sub _part {
523 0     0     my (undef, $self) = @_[KERNEL, OBJECT];
524 0           my ($channel, $msg) = @_[ARG0, ARG1];
525 0           $self->send(
526             ircmsg(
527             command => 'part',
528             params => [ $channel, $msg ],
529             )
530             );
531             }
532              
533             1;
534              
535             =pod
536              
537             =head1 NAME
538              
539             POEx::IRC::Client::Lite - Minimalist POE IRC interface
540              
541             =head1 SYNOPSIS
542              
543             package MyClient;
544             use POE;
545             use POEx::IRC::Client::Lite;
546             use IRC::Toolkit;
547              
548             our @channels = ( '#otw', '#eris' );
549              
550             POE::Session->create(
551             package_states => [
552             MyClient => [ qw/
553             _start
554             emitted_irc_001
555             emitted_irc_public_msg
556             emitted_irc_ctcp_version
557             / ],
558             ],
559             );
560              
561             sub _start {
562             my ($kern, $heap) = @_[KERNEL, HEAP];
563              
564             $heap->{irc} = POEx::IRC::Client::Lite->new(
565             server => "irc.perl.org",
566             nick => "MyNick",
567             username => "myuser",
568             );
569              
570             $heap->{irc}->connect;
571             }
572              
573             sub emitted_irc_001 {
574             my ($kern, $heap) = @_[KERNEL, HEAP];
575              
576             $heap->{irc}->join(@channels)->privmsg(
577             join(',', @channels), "hello!"
578             );
579             }
580              
581             sub emitted_irc_public_msg {
582             my ($kern, $heap) = @_[KERNEL, HEAP];
583             my $event = $_[ARG0];
584              
585             my ($target, $string) = @{ $event->params };
586             my $from = parse_user( $event->prefix );
587              
588             if (lc($string||'') eq 'hello') {
589             $heap->{irc}->privmsg($target, "hello there, $from")
590             }
591             }
592              
593             sub emitted_irc_ctcp_version {
594             my ($kern, $heap) = @_[KERNEL, HEAP];
595             my $event = $_[ARG0];
596              
597             my $from = parse_user( $event->prefix );
598              
599             $heap->{irc}->notice( $from =>
600             ctcp_quote("VERSION a silly Client::Lite example")
601             );
602             }
603              
604             =head1 DESCRIPTION
605              
606             A very thin (but pluggable / extensible) IRC client library using
607             L and L on top of
608             L and L.
609              
610             No state is maintained; POEx::IRC::Client::Lite provides a
611             minimalist interface to IRC and serves as a base class for stateful clients.
612              
613             This is early development software pulled out of a much larger in-progress
614             project.
615             B<< See L for a more mature POE IRC client library. >>
616              
617             =head2 new
618              
619             my $irc = POEx::IRC::Client::Lite->new(
620             # event_prefix comes from MooX::Role::POE::Emitter,
621             # defaults to 'emitted_'
622             event_prefix => $prefix,
623             server => $server,
624             nick => $nickname,
625             username => $username,
626             );
627              
628             Create a new Client::Lite instance. Optional arguments, in addition to
629             attributes provided by L & L,
630             are:
631              
632             =over
633              
634             =item bindaddr
635              
636             Local address to bind to.
637              
638             =item ipv6
639              
640             Boolean value indicating whether to prefer IPv6.
641              
642             =item port
643              
644             Remote port to use (defaults to 6667).
645              
646             =item ssl
647              
648             Boolean value indicating whether to (attempt to) connect via SSL.
649              
650             Requires L.
651              
652             =item ssl_opts
653              
654             An C containing SSL options passed along to L
655             via L; see L & L.
656              
657             Not required for basic SSL operation; setting L to a true value should
658             work for most users.
659              
660             =item reconnect
661              
662             Reconnection attempt delay, in seconds.
663              
664             B<< Automatic reconnection is only triggered when an outgoing connector fails!
665             >>
666              
667             You can trigger a reconnection in your own code by handling
668             L events. For example:
669              
670             sub irc_disconnected {
671             # Immediate reconnect; you may want to use a timer (to avoid being banned)
672             # Assuming our IRC component's object lives in our session's HEAP:
673             $_[HEAP]->{irc}->connect
674             }
675              
676             =back
677              
678             =head2 stop
679              
680             $irc->stop;
681              
682             Disconnect, stop the Emitter, and purge the plugin pipeline.
683              
684             =head2 IRC Methods
685              
686             IRC-related methods can be called via normal method dispatch or sent as a POE
687             event:
688              
689             ## These are equivalent:
690             $irc->send( $ircevent );
691             $irc->yield( 'send', $ircevent );
692             $poe_kernel->post( $irc->session_id, 'send', $ircevent );
693              
694             Methods that dispatch to IRC return C<$self>, so they can be chained:
695              
696             $irc->connect->join(@channels)->privmsg(
697             join(',', @channels),
698             'hello there!'
699             );
700              
701             =head3 connect
702              
703             $irc->connect;
704              
705             Attempt an outgoing connection.
706              
707             =head3 disconnect
708              
709             $irc->disconnect($message);
710              
711             Quit IRC and shut down the wheel.
712              
713             =head3 send
714              
715             use IRC::Message::Object 'ircmsg';
716             $irc->send(
717             ircmsg(
718             command => 'oper',
719             params => [ $user, $passwd ],
720             )
721             );
722              
723             ## ... or a raw HASH:
724             $irc->send(
725             {
726             command => 'oper',
727             params => [ $user, $passwd ],
728             }
729             )
730              
731             ## ... or a raw line:
732             $irc->send_raw_line('PRIVMSG avenj :some things');
733              
734             Use C to send an L or a compatible
735             HASH; this method will also take a list of events in either of those formats.
736              
737             =head3 send_raw_line
738              
739             Use C to send a single raw IRC line. This is rarely a good
740             idea; L provides an IRCv3-capable filter.
741              
742             =head3 set_nick
743              
744             $irc->set_nick( $new_nick );
745              
746             Attempt to change the current nickname.
747              
748             =head3 privmsg
749              
750             $irc->privmsg( $target, $string );
751              
752             Sends a PRIVMSG to the specified target.
753              
754             =head3 notice
755              
756             $irc->notice( $target, $string );
757              
758             Sends a NOTICE to the specified target.
759              
760             =head3 ctcp
761              
762             $irc->ctcp( $target, $type, @params );
763              
764             Encodes and sends a CTCP B to the target.
765             (To send a CTCP B, send a L that has been quoted via
766             L.)
767              
768             =head3 mode
769              
770             $irc->mode( $channel, $modestring );
771              
772             Sends a MODE for the specified target.
773              
774             Takes a channel name as a string and a mode change as either a string or an
775             L.
776              
777             =head3 join
778              
779             $irc->join( $channel );
780              
781             Attempts to join the specified channel.
782              
783             =head3 part
784              
785             $irc->part( $channel, $message );
786              
787             Attempts to leave the specified channel with an optional PART message.
788              
789             =head2 Attributes
790              
791             =head3 conn
792              
793             The L instance for our connection.
794              
795             =head3 nick
796              
797             The nickname we were spawned with.
798              
799             This class doesn't track nick changes; if our nick is changed later, ->nick()
800             is not updated.
801              
802             =head3 server
803              
804             The server we were instructed to connect to.
805              
806             =head1 Emitted Events
807              
808             =head2 IRC events
809              
810             All IRC events are emitted as 'irc_$cmd' e.g. 'irc_005' (ISUPPORT) or
811             'irc_mode' with a few notable exceptions, detailed below.
812              
813             C<$_[ARG0]> is the L.
814              
815             =head2 Special events
816              
817             =head3 irc_connected
818              
819             Emitted when a connection has been successfully opened.
820              
821             This does not indicate successful server registration, only that the
822             connection has been opened and registration details have been sent.
823              
824             C<$_[ARG0]> is the L object.
825              
826             =head3 irc_connector_failed
827              
828             Emitted if an outgoing connection could not be established.
829              
830             C<< @_[ARG0 .. ARG3] >> are the operation, errno, and error string passed in
831             by L; see L.
832              
833             =head3 irc_connector_killed
834              
835             Emitted if a connection is terminated during L.
836              
837             C<$_[ARG0]> is the L object.
838              
839             =head3 irc_private_message
840              
841             Emitted for PRIVMSG-type messages not covered by L.
842              
843             =head3 irc_public_message
844              
845             Emitted for PRIVMSG-type messages that appear to be destined for a channel
846             target.
847              
848             =head3 irc_ctcp_TYPE
849              
850             Emitted for incoming CTCP requests. TYPE is the request type, such as
851             'version'
852              
853             C<$_[ARG0]> is the L produced by
854             L.
855              
856             An example of sending a CTCP reply lives in L.
857             See L for CTCP-related helpers.
858              
859             =head3 irc_ctcpreply_TYPE
860              
861             Emitted for incoming CTCP replies.
862              
863             Mirrors the behavior of L
864              
865             =head3 irc_disconnected
866              
867             Emitted when an IRC connection has been disconnected at the backend.
868              
869             C<$_[ARG0]> is the disconnect string from L.
870              
871             C<$_[ARG1]> is the L that was disconnected.
872              
873             =head1 Pluggable Events
874              
875             These are events explicitly dispatched to plugins
876             via L;
877             see L and L for more on
878             making use of plugins.
879              
880             =head2 preregister
881              
882             Dispatched to plugins when an outgoing connection has been established,
883             but prior to registration.
884              
885             The first argument is the L object.
886              
887             Returning EAT_ALL (see L) to Client::Lite
888             will terminate the connection without registering.
889              
890             =head2 outgoing
891              
892             Dispatched to plugins prior to sending output.
893              
894             The first argument is the item being sent. Note that no sanity checks are
895             performed on the item(s) at this stage (this is done after items are passed to
896             the L instance) -- your plugin's handler could receive a
897             HASH, an L, a raw line, or something invalid.
898              
899             Returning EAT_ALL will skip sending the item.
900              
901             =head1 SEE ALSO
902              
903             L, a fully-featured POE IRC client library
904              
905             L
906              
907             L
908              
909             L
910              
911             L
912              
913             L
914              
915             =head1 AUTHOR
916              
917             Jon Portnoy
918              
919             =begin Pod::Coverage
920              
921             BUILD
922             N_(?i:[A-Z0-9_])+
923             ircsock_(?i:[A-Z_])+
924              
925             =end Pod::Coverage
926              
927             =cut