File Coverage

blib/lib/AnyEvent/IRC/Client.pm
Criterion Covered Total %
statement 21 521 4.0
branch 0 152 0.0
condition 0 56 0.0
subroutine 7 85 8.2
pod 32 63 50.7
total 60 877 6.8


line stmt bran cond sub pod time code
1             package AnyEvent::IRC::Client;
2 1     1   2019 use common::sense;
  1         2  
  1         7  
3              
4 1     1   54 use Scalar::Util qw/weaken/;
  1         2  
  1         58  
5              
6 1     1   14 use Encode;
  1         3  
  1         82  
7 1     1   5 use AnyEvent::Socket;
  1         2  
  1         181  
8 1     1   14 use AnyEvent::Handle;
  1         2  
  1         27  
9             use AnyEvent::IRC::Util
10 1         86 qw/prefix_nick decode_ctcp split_prefix
11             is_nick_prefix join_prefix encode_ctcp
12 1     1   6 split_unicode_string mk_msg/;
  1         1  
13              
14 1     1   5 use base AnyEvent::IRC::Connection::;
  1         7  
  1         10819  
15              
16             =head1 NAME
17              
18             AnyEvent::IRC::Client - A highlevel IRC connection
19              
20             =head1 SYNOPSIS
21              
22             use AnyEvent;
23             use AnyEvent::IRC::Client;
24              
25             my $c = AnyEvent->condvar;
26              
27             my $timer;
28             my $con = new AnyEvent::IRC::Client;
29              
30             $con->reg_cb (connect => sub {
31             my ($con, $err) = @_;
32             if (defined $err) {
33             warn "connect error: $err\n";
34             return;
35             }
36             });
37             $con->reg_cb (registered => sub { print "I'm in!\n"; });
38             $con->reg_cb (disconnect => sub { print "I'm out!\n"; $c->broadcast });
39             $con->reg_cb (
40             sent => sub {
41             my ($con) = @_;
42              
43             if ($_[2] eq 'PRIVMSG') {
44             print "Sent message!\n";
45              
46             $timer = AnyEvent->timer (
47             after => 1,
48             cb => sub {
49             undef $timer;
50             $con->disconnect ('done')
51             }
52             );
53             }
54             }
55             );
56              
57             $con->send_srv (
58             PRIVMSG => 'elmex',
59             "Hello there I'm the cool AnyEvent::IRC test script!"
60             );
61              
62             $con->connect ("localhost", 6667, { nick => 'testbot' });
63             $c->wait;
64             $con->disconnect;
65              
66             =head1 DESCRIPTION
67              
68             L<AnyEvent::IRC::Client> is a (nearly) highlevel client connection,
69             that manages all the stuff that noone wants to implement again and again
70             when handling with IRC. For example it PONGs the server or keeps track
71             of the users on a channel.
72              
73             This module also implements the ISUPPORT (command 005) extension of the IRC protocol
74             (see http://www.irc.org/tech_docs/005.html) and will enable the NAMESX and UHNAMES
75             extensions when supported by the server.
76              
77             Also CTCP support is implemented, all CTCP messages will be decoded and events
78             for them will be generated. You can configure auto-replies to certain CTCP commands
79             with the C<ctcp_auto_reply> method, or you can generate the replies yourself.
80              
81             =head2 A NOTE TO CASE MANAGEMENT
82              
83             The case insensitivity of channel names and nicknames can lead to headaches
84             when dealing with IRC in an automated client which tracks channels and nicknames.
85              
86             I tried to preserve the case in all channel and nicknames
87             AnyEvent::IRC::Client passes to his user. But in the internal
88             structures I'm using lower case for the channel names.
89              
90             The returned hash from C<channel_list> for example has the lower case of the
91             joined channels as keys.
92              
93             But I tried to preserve the case in all events that are emitted.
94             Please keep this in mind when handling the events.
95              
96             For example a user might joins #TeSt and parts #test later.
97              
98             =head1 EVENTS
99              
100             The following events are emitted by L<AnyEvent::IRC::Client>.
101             Use C<reg_cb> as described in L<Object::Event> to register to such an event.
102              
103             =over 4
104              
105             =item registered
106              
107             Emitted when the connection got successfully registered and the end of the MOTD
108             (IRC command 376 or 422 (No MOTD file found)) was seen, so you can start sending
109             commands and all ISUPPORT/PROTOCTL handshaking has been done.
110              
111             =item channel_add => $msg, $channel, @nicks
112              
113             Emitted when C<@nicks> are added to the channel C<$channel>,
114             this happens for example when someone JOINs a channel or when you
115             get a RPL_NAMREPLY (see RFC1459).
116              
117              
118             C<$msg> is the IRC message hash that as returned by C<parse_irc_msg>.
119              
120             =item channel_remove => $msg, $channel, @nicks
121              
122             Emitted when C<@nicks> are removed from the channel C<$channel>,
123             happens for example when they PART, QUIT or get KICKed.
124              
125             C<$msg> is the IRC message hash that as returned by C<parse_irc_msg>
126             or undef if the reason for the removal was a disconnect on our end.
127              
128             =item channel_change => $msg, $channel, $old_nick, $new_nick, $is_myself
129              
130             Emitted when a nickname on a channel changes. This is emitted when a NICK
131             change occurs from C<$old_nick> to C<$new_nick> give the application a chance
132             to quickly analyze what channels were affected. C<$is_myself> is true when
133             yourself was the one who changed the nick.
134              
135             =item channel_nickmode_update => $channel, $dest
136              
137             This event is emitted when the (user) mode (eg. op status) of an occupant of
138             a channel changes. C<$dest> is the nickname on the C<$channel> who's mode was
139             updated.
140              
141             =item channel_topic => $channel, $topic, $who
142              
143             This is emitted when the topic for a channel is discovered. C<$channel>
144             is the channel for which C<$topic> is the current topic now.
145             Which is set by C<$who>. C<$who> might be undefined when it's not known
146             who set the channel topic.
147              
148             =item ident_change => $nick, $ident
149              
150             Whenever the user and host of C<$nick> has been determined or a change
151             happened this event is emitted.
152              
153             =item join => $nick, $channel, $is_myself
154              
155             Emitted when C<$nick> enters the channel C<$channel> by JOINing.
156             C<$is_myself> is true if yourself are the one who JOINs.
157              
158             =item part => $nick, $channel, $is_myself, $msg
159              
160             Emitted when C<$nick> PARTs the channel C<$channel>.
161             C<$is_myself> is true if yourself are the one who PARTs.
162             C<$msg> is the PART message.
163              
164             =item kick => $kicked_nick, $channel, $is_myself, $msg, $kicker_nick
165              
166             Emitted when C<$kicked_nick> is KICKed from the channel C<$channel> by
167             C<$kicker_nick>. C<$is_myself> is true if yourself are the one who got KICKed.
168             C<$msg> is the KICK message.
169              
170             =item nick_change => $old_nick, $new_nick, $is_myself
171              
172             Emitted when C<$old_nick> is renamed to C<$new_nick>.
173             C<$is_myself> is true when yourself was the one who changed the nick.
174              
175             =item away_status_change => $bool
176              
177             Emitted whenever a presence/away status change for you was detected.
178             C<$bool> is true if you are now away, or false/undef if you are not
179             away anymore.
180              
181             You can change your away status by emitting the C<AWAY> IRC command:
182              
183             $cl->send_srv (AWAY => "I'm not here right now");
184              
185             Or reset it:
186              
187             $cl->send_srv ('AWAY');
188              
189             =item ctcp => $src, $target, $tag, $msg, $type
190              
191             Emitted when a CTCP message was found in either a NOTICE or PRIVMSG
192             message. C<$tag> is the CTCP message tag. (eg. "PING", "VERSION", ...).
193             C<$msg> is the CTCP message and C<$type> is either "NOTICE" or "PRIVMSG".
194              
195             C<$src> is the source nick the message came from.
196             C<$target> is the target nickname (yours) or the channel the ctcp was sent
197             on.
198              
199             =item "ctcp_$tag", => $src, $target, $msg, $type
200              
201             Emitted when a CTCP message was found in either a NOTICE or PRIVMSG
202             message. C<$tag> is the CTCP message tag (in lower case). (eg. "ping", "version", ...).
203             C<$msg> is the CTCP message and C<$type> is either "NOTICE" or "PRIVMSG".
204              
205             C<$src> is the source nick the message came from.
206             C<$target> is the target nickname (yours) or the channel the ctcp was sent
207             on.
208              
209             =item dcc_ready => $id, $dest, $type, $local_ip, $local_port
210              
211             Whenever a locally initiated DCC request is made this event is emitted
212             after the listening socket has been setup.
213              
214             C<$id> is the DCC connection ID.
215              
216             C<$dest> and C<$type> are the destination and type of the DCC request.
217              
218             C<$local_ip> is the C<$local_ip> argument passed to C<start_dcc> or
219             the IP the socket is bound to.
220              
221             C<$local_port> is the TCP port is the socket is listening on.
222              
223             =item dcc_request => $id, $src, $type, $arg, $addr, $port
224              
225             Whenever we receive a DCC offer from someone else this event is emitted.
226             C<$id> is the DCC connection ID, C<$src> is his nickname, C<$type> is the DCC
227             type in lower cases (eg. 'chat'). C<$arg> is the DCC type argument. C<$addr>
228             is the IP address we can reach him at in ASCII encoded human readable form (eg.
229             something like "127.0.0.1"). And C<$port> is the TCP port we have to connect
230             to.
231              
232             To answer to his request you can just call C<dcc_accept> with the C<$id>.
233              
234             =item dcc_accepted => $id, $type, $hdl
235              
236             When the locally listening DCC socket has received a connection this event is emitted.
237              
238             C<$id> and C<$type> are the DCC connection ID and type of the DCC request.
239              
240             C<$hdl> is a pre-configured L<AnyEvent::Handle> object, which you only
241             need to care about in case you want to implement your own DCC protocol.
242             (This event has the on_error and on_eof events pre-configured to cleanup
243             the data structures in this connection).
244              
245             =item dcc_connected => $id, $type, $hdl
246              
247             Whenever we accepted a DCC offer and connected by using C<dcc_accept> this
248             event is emitted. C<$id> is the DCC connection ID. C<$type> is the dcc type in
249             lower case. C<$hdl> is the L<AnyEvent::Handle> object of the connection (see
250             also C<dcc_accepted> above).
251              
252             =item dcc_close => $id, $type, $reason
253              
254             This event is emitted whenever a DCC connection is terminated.
255              
256             C<$id> and C<$type> are the DCC connection ID and type of the DCC request.
257              
258             C<$reason> is a human readable string indicating the reason for the end of
259             the DCC request.
260              
261             =item dcc_chat_msg => $id, $msg
262              
263             This event is emitted for a DCC CHAT message. C<$id> is the DCC connection
264             ID we received the message on. And C<$msg> is the message he sent us.
265              
266             =item quit => $nick, $msg
267              
268             Emitted when the nickname C<$nick> QUITs with the message C<$msg>.
269              
270             =item publicmsg => $channel, $ircmsg
271              
272             Emitted for NOTICE and PRIVMSG where the target C<$channel> is a channel.
273             C<$ircmsg> is the original IRC message hash like it is returned by C<parse_irc_msg>.
274              
275             The last parameter of the C<$ircmsg> will have all CTCP messages stripped off.
276              
277             =item privatemsg => $nick, $ircmsg
278              
279             Emitted for NOTICE and PRIVMSG where the target C<$nick> (most of the time you) is a nick.
280             C<$ircmsg> is the original IRC message hash like it is returned by C<parse_irc_msg>.
281              
282             The last parameter of the C<$ircmsg> will have all CTCP messages stripped off.
283              
284             =item error => $code, $message, $ircmsg
285              
286             Emitted when any error occurs. C<$code> is the 3 digit error id string from RFC
287             1459 or the string 'ERROR'. C<$message> is a description of the error.
288             C<$ircmsg> is the complete error irc message.
289              
290             You may use AnyEvent::IRC::Util::rfc_code_to_name to convert C<$code> to the error
291             name from the RFC 2812. eg.:
292              
293             rfc_code_to_name ('471') => 'ERR_CHANNELISFULL'
294              
295             NOTE: This event is also emitted when a 'ERROR' message is received.
296              
297             =item debug_send => $command, @params
298              
299             Is emitted everytime some command is sent.
300              
301             =item debug_recv => $ircmsg
302              
303             Is emitted everytime some command was received.
304              
305             =back
306              
307             =head1 METHODS
308              
309             =over 4
310              
311             =item $cl = AnyEvent::IRC::Client->new (%args)
312              
313             This is the constructor of a L<AnyEvent::IRC::Client> object,
314             which stands logically for a client connected to ONE IRC server.
315             You can reuse it and call C<connect> once it disconnected.
316              
317             B<NOTE:> You are free to use the hash member C<heap> to store any associated
318             data with this object. For example retry timers or anything else.
319              
320             C<%args> may contain these options:
321              
322             =over 4
323              
324             =item send_initial_whois => $bool
325              
326             If this option is enabled an initial C<WHOIS> command is sent to your own
327             NICKNAME to determine your own I<ident>. See also the method C<nick_ident>.
328             This is necessary to ensure that the information about your own nickname
329             is available as early as possible for the C<send_long_message> method.
330              
331             C<$bool> is C<false> by default.
332              
333             =back
334              
335             =cut
336              
337             my %LOWER_CASEMAP = (
338             rfc1459 => sub { tr/A-Z[]\\\^/a-z{}|~/ },
339             'strict-rfc1459' => sub { tr/A-Z[]\\/a-z{}|/ },
340             ascii => sub { tr/A-Z/a-z/ },
341             );
342              
343             sub new {
344 0     0 1   my $this = shift;
345 0   0       my $class = ref($this) || $this;
346 0           my $self = $class->SUPER::new (@_);
347              
348 0           $self->reg_cb (irc_001 => \&welcome_cb);
349 0           $self->reg_cb (irc_376 => \&welcome_cb);
350 0           $self->reg_cb (irc_422 => \&welcome_cb);
351 0           $self->reg_cb (irc_005 => \&isupport_cb);
352 0           $self->reg_cb (irc_join => \&join_cb);
353 0           $self->reg_cb (irc_nick => \&nick_cb);
354 0           $self->reg_cb (irc_part => \&part_cb);
355 0           $self->reg_cb (irc_kick => \&kick_cb);
356 0           $self->reg_cb (irc_quit => \&quit_cb);
357 0           $self->reg_cb (irc_mode => \&mode_cb);
358 0           $self->reg_cb (irc_353 => \&namereply_cb);
359 0           $self->reg_cb (irc_366 => \&endofnames_cb);
360 0           $self->reg_cb (irc_352 => \&whoreply_cb);
361 0           $self->reg_cb (irc_311 => \&whoisuser_cb);
362 0           $self->reg_cb (irc_305 => \&away_change_cb);
363 0           $self->reg_cb (irc_306 => \&away_change_cb);
364 0           $self->reg_cb (irc_ping => \&ping_cb);
365 0           $self->reg_cb (irc_pong => \&pong_cb);
366              
367 0           $self->reg_cb (irc_privmsg => \&privmsg_cb);
368 0           $self->reg_cb (irc_notice => \&privmsg_cb);
369              
370 0           $self->reg_cb ('irc_*' => \&debug_cb);
371 0           $self->reg_cb ('irc_*' => \&anymsg_cb);
372 0           $self->reg_cb ('irc_*' => \&update_ident_cb);
373              
374 0           $self->reg_cb (disconnect => \&disconnect_cb);
375              
376 0           $self->reg_cb (irc_332 => \&rpl_topic_cb);
377 0           $self->reg_cb (irc_topic => \&topic_change_cb);
378              
379 0           $self->reg_cb (ctcp => \&ctcp_auto_reply_cb);
380              
381 0           $self->reg_cb (registered => \&registered_cb);
382              
383 0           $self->reg_cb (nick_change => \&update_ident_nick_change_cb);
384              
385             $self->{def_nick_change} = $self->{nick_change} =
386             sub {
387 0     0     my ($old_nick) = @_;
388 0           "${old_nick}_"
389 0           };
390              
391 0           $self->_setup_internal_dcc_handlers;
392              
393 0           $self->cleanup;
394              
395 0           return $self;
396             }
397              
398             sub cleanup {
399 0     0 0   my ($self) = @_;
400              
401 0           $self->{channel_list} = { };
402 0           $self->{isupport} = { };
403 0           $self->{casemap_func} = $LOWER_CASEMAP{rfc1459};
404 0           $self->{prefix_chars} = '@+';
405 0           $self->{prefix2mode} = { '@' => 'o', '+' => 'v' };
406 0           $self->{channel_chars} = '#&';
407              
408 0           $self->{change_nick_cb_guard} =
409             $self->reg_cb (
410             irc_437 => \&change_nick_login_cb,
411             irc_433 => \&change_nick_login_cb,
412             );
413              
414 0           delete $self->{away_status};
415 0           delete $self->{dcc};
416 0           delete $self->{dcc_id};
417 0           delete $self->{_tmp_namereply};
418 0           delete $self->{last_pong_recv};
419 0           delete $self->{last_ping_sent};
420 0           delete $self->{_ping_timer};
421 0           delete $self->{con_queue};
422 0           delete $self->{chan_queue};
423 0           delete $self->{registered};
424 0           delete $self->{idents};
425 0           delete $self->{nick};
426 0           delete $self->{user};
427 0           delete $self->{real};
428 0           delete $self->{server_pass};
429 0           delete $self->{register_cb_guard};
430             }
431              
432             =item $cl->connect ($host, $port)
433              
434             =item $cl->connect ($host, $port, $info)
435              
436             This method does the same as the C<connect> method of L<AnyEvent::Connection>,
437             but if the C<$info> parameter is passed it will automatically register with the
438             IRC server upon connect for you, and you won't have to call the C<register>
439             method yourself. If C<$info> only contains the timeout value it will not
440             automatically connect, this way you can pass a custom connect timeout value
441             without having to register.
442              
443             The keys of the hash reference you can pass in C<$info> are:
444              
445             nick - the nickname you want to register as
446             user - your username
447             real - your realname
448             password - the server password
449             timeout - the TCP connect timeout
450              
451             All keys, except C<nick> are optional.
452              
453             =cut
454              
455             sub connect {
456 0     0 1   my ($self, $host, $port, $info) = @_;
457              
458 0           my $timeout = delete $info->{timeout};
459              
460 0 0 0       if (defined $info and keys %$info) {
461             $self->{register_cb_guard} = $self->reg_cb (
462             ext_before_connect => sub {
463 0     0     my ($self, $err) = @_;
464              
465 0 0         unless ($err) {
466 0           $self->register (
467             $info->{nick}, $info->{user}, $info->{real}, $info->{password}
468             );
469             }
470              
471 0           delete $self->{register_cb_guard};
472             }
473 0           );
474             }
475              
476 0           $self->SUPER::connect ($host, $port, $timeout);
477             }
478              
479             =item $cl->register ($nick, $user, $real, $server_pass)
480              
481             Sends the IRC registration commands NICK and USER.
482             If C<$server_pass> is passed also a PASS command is generated.
483              
484             NOTE: If you passed the nick, user, etc. already to the C<connect> method
485             you won't need to call this method, as L<AnyEvent::IRC::Client> will do that
486             for you.
487              
488             =cut
489              
490             sub register {
491 0     0 1   my ($self, $nick, $user, $real, $pass) = @_;
492              
493 0           $self->{nick} = $nick;
494 0           $self->{user} = $user;
495 0           $self->{real} = $real;
496 0           $self->{server_pass} = $pass;
497              
498 0 0         $self->send_msg ("PASS", $pass) if defined $pass;
499 0           $self->send_msg ("NICK", $nick);
500 0   0       $self->send_msg ("USER", $user || $nick, "*", "0", $real || $nick);
      0        
501             }
502              
503             =item $cl->set_nick_change_cb ($callback)
504              
505             This method lets you modify the nickname renaming mechanism when registering
506             the connection. C<$callback> is called with the current nickname as first
507             argument when a ERR_NICKNAMEINUSE or ERR_UNAVAILRESOURCE error occurs on login.
508             The return value of C<$callback> will then be used to change the nickname.
509              
510             If C<$callback> is not defined the default nick change callback will be used
511             again.
512              
513             The default callback appends '_' to the end of the nickname supplied in the
514             C<register> routine.
515              
516             If the callback returns the same nickname that was given it the connection
517             will be terminated.
518              
519             =cut
520              
521             sub set_nick_change_cb {
522 0     0 1   my ($self, $cb) = @_;
523 0 0         $cb = $self->{def_nick_change} unless defined $cb;
524 0           $self->{nick_change} = $cb;
525             }
526              
527             =item $cl->nick ()
528              
529             Returns the current nickname, under which this connection
530             is registered at the IRC server. It might be different from the
531             one that was passed to C<register> as a nick-collision might happened
532             on login.
533              
534             =cut
535              
536 0     0 1   sub nick { $_[0]->{nick} }
537              
538             =item $cl->is_my_nick ($string)
539              
540             This returns true if C<$string> is the nick of ourself.
541              
542             =cut
543              
544             sub is_my_nick {
545 0     0 1   my ($self, $string) = @_;
546 0           $self->eq_str ($string, $self->nick);
547             }
548              
549             =item $cl->registered ()
550              
551             Returns a true value when the connection has been registered successful and
552             you can send commands.
553              
554             =cut
555              
556 0     0 1   sub registered { $_[0]->{registered} }
557              
558             =item $cl->channel_list ()
559              
560             =item $cl->channel_list ($channel)
561              
562             Without C<$channel> parameter: This returns a hash reference. The keys are the
563             currently joined channels in lower case. The values are hash references which
564             contain the joined nicks as key (NOT in lower case!) and the nick modes as
565             values (as returned from C<nick_modes ()>).
566              
567             If the C<$channel> parameter is given it returns the hash reference of the channel
568             occupants or undef if the channel does not exist.
569              
570             =cut
571              
572             sub channel_list {
573 0     0 1   my ($self, $chan) = @_;
574              
575 0 0         if (defined $chan) {
576 0           return $self->{channel_list}->{$self->lower_case ($chan)}
577             } else {
578 0   0       return $self->{channel_list} || {};
579             }
580             }
581              
582             =item $cl->nick_modes ($channel, $nick)
583              
584             This returns the mode map of the C<$nick> on C<$channel>.
585             Returns undef if the channel isn't joined or the user is not on it.
586             Returns a hash reference with the modes the user has as keys and 1's as values.
587              
588             =cut
589              
590             sub nick_modes {
591 0     0 1   my ($self, $channel, $nick) = @_;
592              
593 0 0         my $c = $self->channel_list ($channel)
594             or return undef;
595              
596 0           my (%lcc) = map { $self->lower_case ($_) => $c->{$_} } keys %$c;
  0            
597 0           return $lcc{$self->lower_case ($nick)};
598             }
599              
600             =item $cl->send_msg (...)
601              
602             See also L<AnyEvent::IRC::Connection>.
603              
604             =cut
605              
606             sub send_msg {
607 0     0 1   my ($self, @a) = @_;
608 0           $self->event (debug_send => @a);
609 0           $self->SUPER::send_msg (@a);
610             }
611              
612             =item $cl->send_srv ($command, @params)
613              
614             This function sends an IRC message that is constructed by C<mk_msg (undef,
615             $command, @params)> (see L<AnyEvent::IRC::Util>). If the C<registered> event
616             has NOT yet been emitted the messages are queued until that event is emitted,
617             and then sent to the server.
618              
619             B<NOTE:> If you stop the registered event (with C<stop_event>, see L<Object::Event>)
620             in a callback registered to the C<before_registered> event, the C<send_srv> queue
621             will B<NOT> be flushed and B<NOT> sent to the server!
622              
623             This allows you to simply write this:
624              
625             my $cl = AnyEvent::IRC::Client->new;
626             $cl->connect ('irc.freenode.net', 6667, { nick => 'testbot' });
627             $cl->send_srv (PRIVMSG => 'elmex', 'Hi there!');
628              
629             Instead of:
630              
631             my $cl = AnyEvent::IRC::Client->new;
632             $cl->reg_cb (
633             registered => sub {
634             $cl->send_msg (PRIVMSG => 'elmex', 'Hi there!');
635             }
636             );
637             $cl->connect ('irc.freenode.net', 6667, { nick => 'testbot' });
638              
639             =cut
640              
641             sub send_srv {
642 0     0 1   my ($self, @msg) = @_;
643              
644 0 0         if ($self->registered) {
645 0           $self->send_msg (@msg);
646              
647             } else {
648 0           push @{$self->{con_queue}}, \@msg;
  0            
649             }
650             }
651              
652             =item $cl->clear_srv_queue ()
653              
654             Clears the server send queue.
655              
656             =cut
657              
658             sub clear_srv_queue {
659 0     0 1   my ($self) = @_;
660 0           $self->{con_queue} = [];
661             }
662              
663              
664             =item $cl->send_chan ($channel, $command, @params)
665              
666             This function sends a message (constructed by C<mk_msg (undef, $command,
667             @params)> to the server, like C<send_srv> only that it will queue
668             the messages if it hasn't joined the channel C<$channel> yet. The queued
669             messages will be send once the connection successfully JOINed the C<$channel>.
670              
671             C<$channel> will be lowercased so that any case that comes from the server matches.
672             (Yes, IRC handles upper and lower case as equal :-(
673              
674             Be careful with this, there are chances you might not join the channel you
675             wanted to join. You may wanted to join #bla and the server redirects that
676             and sends you that you joined #blubb. You may use C<clear_chan_queue> to
677             remove the queue after some timeout after joining, so that you don't end up
678             with a memory leak.
679              
680             =cut
681              
682             sub send_chan {
683 0     0 1   my ($self, $chan, @msg) = @_;
684              
685 0 0         if ($self->{channel_list}->{$self->lower_case ($chan)}) {
686 0           $self->send_msg (@msg);
687              
688             } else {
689 0           push @{$self->{chan_queue}->{$self->lower_case ($chan)}}, \@msg;
  0            
690             }
691             }
692              
693             =item $cl->clear_chan_queue ($channel)
694              
695             Clears the channel queue of the channel C<$channel>.
696              
697             =cut
698              
699             sub clear_chan_queue {
700 0     0 1   my ($self, $chan) = @_;
701 0           $self->{chan_queue}->{$self->lower_case ($chan)} = [];
702             }
703              
704             =item my (@lines) = $cl->send_long_message ($encoding, $overhead, $cmd, @params, $msg)
705              
706             As IRC only allows 512 byte blocks of messages and sometimes
707             your messages might get longer, you have a problem. This method
708             will solve your problem:
709              
710             This method can be used to split up long messages into multiple
711             commands.
712              
713             C<$cmd> and C<@params> are the IRC command and it's first parameters,
714             except the last one: the C<$msg>. C<$msg> can be a Unicode string,
715             which will be encoded in C<$encoding> before sending.
716              
717             If you want to send a CTCP message you can encode it in the C<$cmd> by
718             appending the CTCP command with a C<"\001">. For example if you want to
719             send a CTCP ACTION you have to give this C<$cmd>:
720              
721             $cl->send_long_message (undef, 0, "PRIVMSG\001ACTION", "#test", "rofls");
722              
723             C<$encoding> can be undef if you don't need any recoding of C<$msg>.
724             But in case you want to send Unicode it is necessary to determine where
725             to split a message exactly, to not break the encoding.
726              
727             Please also note that the C<nick_ident> for your own nick is necessary to
728             compute this. To ensure best performance as possible use the
729             C<send_initial_whois> option if you want to use this method.
730              
731             But note that this method might not work 100% correct and you might still get
732             at least partially chopped off lines if you use C<send_long_message> before the
733             C<WHOIS> reply to C<send_initial_whois> arrived.
734              
735             To be on the safest side you might want to wait until that initial C<WHOIS>
736             reply arrived.
737              
738             The return value of this method is the list of the actually sent lines (but
739             without encoding applied).
740              
741             =cut
742              
743             sub send_long_message {
744 0     0 1   my ($self, $encoding, $overhead, $cmd, @params) = @_;
745 0           my $msg = pop @params;
746              
747 0           my $ctcp;
748 0           ($cmd, $ctcp) = split /\001/, $cmd;
749              
750 0           my $id = $self->nick_ident ($self->nick);
751 0 0         if ($id eq '') {
752 0           $id = "X" x 60; # just in case the ident is not available...
753             }
754              
755 0           my $init_len = length mk_msg ($id, $cmd, @params, " "); # i know off by 1
756              
757 0 0         if ($ctcp ne '') {
758 0           $init_len += length ($ctcp) + 3; # CTCP cmd + " " + "\001" x 2
759             }
760              
761 0           my $max_len = 500; # give 10 bytes extra margin
762              
763 0           my $line_len = $max_len - $init_len;
764              
765             # split up the multiple lines in the message:
766 0           my @lines = split /\n/, $msg;
767              
768             # splitup long lines into multiple ones:
769 0           @lines =
770             map split_unicode_string ($encoding, $_, $line_len), @lines;
771              
772             # send lines line-by-line:
773 0           for my $line (@lines) {
774 0           my $smsg = encode ($encoding, $line);
775              
776 0 0         if ($ctcp ne '') {
777 0           $smsg = encode_ctcp ([$ctcp, $smsg])
778             }
779              
780 0           $self->send_srv ($cmd => @params, $smsg);
781             }
782              
783             @lines
784 0           }
785              
786             =item $cl->enable_ping ($interval, $cb)
787              
788             This method enables a periodical ping to the server with an interval of
789             C<$interval> seconds. If no PONG was received from the server until the next
790             interval the connection will be terminated or the callback in C<$cb> will be called.
791              
792             (C<$cb> will have the connection object as it's first argument.)
793              
794             Make sure you call this method after the connection has been established.
795             (eg. in the callback for the C<registered> event).
796              
797             =cut
798              
799             sub enable_ping {
800 0     0 1   my ($self, $int, $cb) = @_;
801              
802 0           $self->{last_pong_recv} = 0;
803 0           $self->{last_ping_sent} = time;
804              
805 0           $self->send_srv (PING => "AnyEvent::IRC");
806              
807             $self->{_ping_timer} =
808             AE::timer $int, 0, sub {
809 0 0   0     if ($self->{last_pong_recv} < $self->{last_ping_sent}) {
810 0           delete $self->{_ping_timer};
811 0 0         if ($cb) {
812 0           $cb->($self);
813             } else {
814 0           $self->disconnect ("Server timeout");
815             }
816              
817             } else {
818 0           $self->enable_ping ($int, $cb);
819             }
820 0           };
821             }
822              
823             =item $cl->lower_case ($str)
824              
825             Converts the given string to lowercase according to CASEMAPPING setting given by
826             the IRC server. If none was sent, the default - rfc1459 - will be used.
827              
828             =cut
829              
830             sub lower_case {
831 0     0 1   my($self, $str) = @_;
832 0           local $_ = $str;
833 0           $self->{casemap_func}->();
834 0           return $_;
835             }
836              
837             =item $cl->eq_str ($str1, $str2)
838              
839             This function compares two strings, whether they are describing the same
840             IRC entity. They are lower cased by the networks case rules and compared then.
841              
842             =cut
843              
844             sub eq_str {
845 0     0 1   my ($self, $a, $b) = @_;
846 0           $self->lower_case ($a) eq $self->lower_case ($b)
847             }
848              
849             =item $cl->isupport ()
850              
851             =item $cl->isupport ($key)
852              
853             Provides access to the ISUPPORT variables sent by the IRC server. If $key is
854             given this method will return its value only, otherwise a hashref with all values
855             is returned
856              
857             =cut
858              
859             sub isupport {
860 0     0 1   my($self, $key) = @_;
861 0 0         if (defined ($key)) {
862 0           return $self->{isupport}->{$key};
863             } else {
864 0           return $self->{isupport};
865             }
866             }
867              
868             =item $cl->split_nick_mode ($prefixed_nick)
869              
870             This method splits the C<$prefix_nick> (eg. '+elmex') up into the
871             mode of the user and the nickname.
872              
873             This method returns 2 values: the mode map and the nickname.
874              
875             The mode map is a hash reference with the keys being the modes the nick has set
876             and the values being 1.
877              
878             NOTE: If you feed in a prefixed ident ('@elmex!elmex@fofofof.de') you get 3 values
879             out actually: the mode map, the nickname and the ident, otherwise the 3rd value is undef.
880              
881             =cut
882              
883             sub split_nick_mode {
884 0     0 1   my ($self, $prefixed_nick) = @_;
885              
886 0           my $pchrs = $self->{prefix_chars};
887              
888 0           my %mode_map;
889              
890             my $nick;
891              
892 0 0         if ($prefixed_nick =~ /^([\Q$pchrs\E]+)(.+)$/) {
893 0           my $p = $1;
894 0           $nick = $2;
895 0           for (split //, $p) { $mode_map{$self->map_prefix_to_mode ($_)} = 1 }
  0            
896             } else {
897 0           $nick = $prefixed_nick;
898             }
899              
900 0           my (@n) = split_prefix ($nick);
901              
902 0 0 0       if (@n > 1 && defined $n[1]) {
903 0           return (\%mode_map, $n[0], $nick);
904             } else {
905 0           return (\%mode_map, $nick, undef);
906             }
907             }
908              
909             =item $cl->map_prefix_to_mode ($prefix)
910              
911             Maps the nick prefix (eg. '@') to the corresponding mode (eg. 'o').
912             Returns undef if no such prefix exists (on the connected server).
913              
914             =cut
915              
916             sub map_prefix_to_mode {
917 0     0 1   my ($self, $prefix) = @_;
918 0           $self->{prefix2mode}->{$prefix}
919             }
920              
921             =item $cl->map_mode_to_prefix ($mode)
922              
923             Maps the nick mode (eg. 'o') to the corresponding prefix (eg. '@').
924             Returns undef if no such mode exists (on the connected server).
925              
926             =cut
927              
928             sub map_mode_to_prefix {
929 0     0 1   my ($self, $mode) = @_;
930 0           for (keys %{$self->{prefix2mode}}) {
  0            
931 0 0         return $_ if $self->{prefix2mode}->{$_} eq $mode;
932             }
933              
934 0           return undef;
935             }
936              
937             =item $cl->available_nick_modes ()
938              
939             Returns a list of possible modes on this IRC server. (eg. 'o' for op).
940              
941             =cut
942              
943             sub available_nick_modes {
944 0     0 1   my ($self) = @_;
945 0           map { $self->map_prefix_to_mode ($_) } split //, $self->{prefix_chars}
  0            
946             }
947              
948             =item $cl->is_channel_name ($string)
949              
950             This return true if C<$string> is a channel name. It analyzes the prefix
951             of the string (eg. if it is '#') and returns true if it finds a channel prefix.
952             Those prefixes might be server specific, so ISUPPORT is checked for that too.
953              
954             =cut
955              
956             sub is_channel_name {
957 0     0 1   my ($self, $string) = @_;
958              
959 0           my $cchrs = $self->{channel_chars};
960 0           $string =~ /^([\Q$cchrs\E]+)(.+)$/;
961             }
962              
963             =item $cl->nick_ident ($nick)
964              
965             This method returns the whole ident of the C<$nick> if the information is available.
966             If the nick's ident hasn't been seen yet, undef is returned.
967              
968             B<NOTE:> If you want to rely on the C<nick_ident> of your own nick you should
969             make sure to enable the C<send_initial_whois> option in the constructor.
970              
971             =cut
972              
973             sub nick_ident {
974 0     0 1   my ($self, $nick) = @_;
975 0           $self->{idents}->{$self->lower_case ($nick)}
976             }
977              
978             =item my $bool = $cl->away_status
979              
980             Returns a true value if you are away or undef if you are not away.
981              
982             =cut
983              
984 0     0 1   sub away_status { $_[0]->{away_status} }
985              
986             =item $cl->ctcp_auto_reply ($ctcp_command, @msg)
987              
988             =item $cl->ctcp_auto_reply ($ctcp_command, $coderef)
989              
990             This method installs an auto-reply for the reception of the C<$ctcp_command>
991             via PRIVMSG, C<@msg> will be used as argument to the C<encode_ctcp> function of
992             the L<AnyEvent::IRC::Util> package. The replies will be sent with the NOTICE
993             IRC command.
994              
995             If C<$coderef> was given and is a code reference, it will called each time a
996             C<$ctcp_command> is received, this is useful for eg. CTCP PING reply
997             generation. The arguments will be the same arguments that the C<ctcp> event
998             callbacks get. (See also C<ctcp> event description above). The return value of
999             the called subroutine should be a list of arguments for C<encode_ctcp>.
1000              
1001             Currently you can only configure one auto-reply per C<$ctcp_command>.
1002              
1003             Example:
1004              
1005             $cl->ctcp_auto_reply ('VERSION', ['VERSION', 'ScriptBla:0.1:Perl']);
1006              
1007             $cl->ctcp_auto_reply ('PING', sub {
1008             my ($cl, $src, $target, $tag, $msg, $type) = @_;
1009             ['PING', $msg]
1010             });
1011              
1012             =cut
1013              
1014             sub ctcp_auto_reply {
1015 0     0 1   my ($self, $ctcp_command, @msg) = @_;
1016              
1017 0           $self->{ctcp_auto_replies}->{$ctcp_command} = \@msg;
1018             }
1019              
1020             sub _setup_internal_dcc_handlers {
1021 0     0     my ($self) = @_;
1022              
1023             $self->reg_cb (ctcp_dcc => sub {
1024 0     0     my ($self, $src, $target, $msg, $type) = @_;
1025              
1026 0 0         if ($self->is_my_nick ($target)) {
1027 0           my ($dcc_type, $arg, $addr, $port) = split /\x20/, $msg;
1028              
1029 0           $dcc_type = lc $dcc_type;
1030              
1031 0 0         if ($dcc_type eq 'send') {
1032 0 0         if ($msg =~ /SEND (.*?) (\d+) (\d+)/) {
1033 0           ($arg, $addr, $port) = ($1, $2, $3);
1034 0           $arg =~ s/^\"(.*)\"$/\1/;
1035             }
1036             }
1037              
1038 0           $addr = format_address (pack "N", $addr);
1039              
1040 0           my $id = ++$self->{dcc_id};
1041              
1042 0           $self->{dcc}->{$id} = {
1043             type => lc ($dcc_type),
1044             dest => $self->lower_case ($src),
1045             ip => $addr,
1046             port => $port,
1047             arg => $arg,
1048             };
1049              
1050 0           $self->event (dcc_request => $id, $src, $dcc_type, $arg, $addr, $port);
1051             }
1052 0           });
1053              
1054             $self->reg_cb (dcc_ready => sub {
1055 0     0     my ($self, $id, $dest, $type, $local_ip, $local_port) = @_;
1056              
1057 0           $local_ip = unpack ("N", parse_address ($local_ip));
1058              
1059 0 0         if ($type eq 'chat') {
    0          
1060 0           $self->send_msg (
1061             PRIVMSG => $dest,
1062             encode_ctcp ([DCC => "CHAT", "CHAT", $local_ip, $local_port]));
1063              
1064             } elsif ($type eq 'send') {
1065 0           $self->send_msg (
1066             PRIVMSG => $dest,
1067             encode_ctcp ([DCC => "SEND", "NOTHING", $local_ip, $local_port]));
1068             }
1069 0           });
1070              
1071             $self->reg_cb (dcc_accepted => sub {
1072 0     0     my ($self, $id, $type, $hdl) = @_;
1073              
1074 0 0         if ($type eq 'chat') {
1075             $hdl->on_read (sub {
1076 0           my ($hdl) = @_;
1077              
1078             $hdl->push_read (line => sub {
1079 0           my ($hdl, $line) = @_;
1080 0           $self->event (dcc_chat_msg => $id, $line);
1081 0           });
1082 0           });
1083             }
1084 0           });
1085              
1086             $self->reg_cb (dcc_connected => sub {
1087 0     0     my ($self, $id, $type, $hdl) = @_;
1088              
1089 0 0         if ($type eq 'chat') {
1090             $hdl->on_read (sub {
1091 0           my ($hdl) = @_;
1092              
1093             $hdl->push_read (line => sub {
1094 0           my ($hdl, $line) = @_;
1095 0           $self->event (dcc_chat_msg => $id, $line);
1096 0           });
1097 0           });
1098             }
1099 0           });
1100             }
1101              
1102             =item $cl->dcc_initiate ($dest, $type, $timeout, $local_ip, $local_port)
1103              
1104             This function will initiate a DCC TCP connection to C<$dest> of type C<$type>.
1105             It will setup a listening TCP socket on C<$local_port>, or a random port if
1106             C<$local_port> is undefined. C<$local_ip> is the IP that is being sent to the
1107             receiver of the DCC connection. If it is undef the local socket will be bound
1108             to 0 (or "::" in case of IPv6) and C<$local_ip> will probably be something like
1109             "0.0.0.0". It is always advisable to set C<$local_ip> to a (from the "outside",
1110             what ever that might be) reachable IP Address.
1111              
1112             C<$timeout> is the time in seconds after which the listening socket will be
1113             closed if the receiver didn't connect yet. The default is 300 (5 minutes).
1114              
1115             When the local listening socket has been setup the C<dcc_ready> event is
1116             emitted. When the receiver connects to the socket the C<dcc_accepted> event is
1117             emitted. And whenever a dcc connection is closed the C<dcc_close> event is
1118             emitted.
1119              
1120             For canceling the DCC offer or closing the connection see C<dcc_disconnect> below.
1121              
1122             The return value of this function will be the ID of the initiated DCC connection,
1123             which can be used for functions such as C<dcc_disconnect>, C<send_dcc_chat> or
1124             C<dcc_handle>.
1125              
1126             =cut
1127              
1128             sub dcc_initiate {
1129 0     0 1   my ($self, $dest, $type, $timeout, $local_ip, $local_port) = @_;
1130              
1131 0           $dest = $self->lower_case ($dest);
1132 0           $type = lc $type;
1133              
1134 0           my $id = ++$self->{dcc_id};
1135 0           my $dcc = $self->{dcc}->{$id} = { id => $id, type => $type, dest => $dest };
1136              
1137 0           weaken $dcc;
1138 0           weaken $self;
1139              
1140             $dcc->{timeout} = AnyEvent->timer (after => $timeout || 5 * 60, cb => sub {
1141 0 0   0     $self->dcc_disconnect ($id, "TIMEOUT") if $self;
1142 0   0       });
1143              
1144             $dcc->{listener} = tcp_server undef, $local_port, sub {
1145 0     0     my ($fh, $h, $p) = @_;
1146 0 0 0       return unless $dcc && $self;
1147              
1148             $dcc->{handle} = AnyEvent::Handle->new (
1149             fh => $fh,
1150             on_eof => sub {
1151 0           $self->dcc_disconnect ($id, "EOF");
1152             },
1153             on_error => sub {
1154 0           $self->dcc_disconnect ($id, "ERROR: $!");
1155             }
1156 0           );
1157              
1158 0           $self->event (dcc_accepted => $id, $type, $dcc->{handle});
1159              
1160 0           delete $dcc->{listener};
1161 0           delete $dcc->{timeout};
1162              
1163             }, sub {
1164 0     0     my ($fh, $host, $port) = @_;
1165 0 0 0       return unless $dcc && $self;
1166              
1167 0 0         $local_ip = $host unless defined $local_ip;
1168 0           $local_port = $port;
1169              
1170 0           $dcc->{local_ip} = $local_ip;
1171 0           $dcc->{local_port} = $local_port;
1172              
1173 0           $self->event (dcc_ready => $id, $dest, $type, $local_ip, $local_port);
1174 0           };
1175              
1176 0           $id
1177             }
1178              
1179              
1180             =item $cl->dcc_disconnect ($id, $reason)
1181              
1182             In case you want to withdraw a DCC offer sent by C<start_dcc> or close
1183             a DCC connection you call this function.
1184              
1185             C<$id> is the DCC connection ID. C<$reason> should be a human readable reason
1186             why you ended the dcc offer, but it's only used for local logging purposes (see
1187             C<dcc_close> event).
1188              
1189             =cut
1190              
1191             sub dcc_disconnect {
1192 0     0 1   my ($self, $id, $reason) = @_;
1193              
1194 0 0         if (my $dcc = delete $self->{dcc}->{$id}) {
1195 0           delete $dcc->{handle};
1196 0           $self->event (dcc_close => $id, $dcc->{type}, $reason);
1197             }
1198             }
1199              
1200             =item $cl->dcc_accept ($id, $timeout)
1201              
1202             This will accept an incoming DCC request as received by the C<dcc_request>
1203             event. The C<dcc_connected> event will be emitted when we successfully
1204             connected. And the C<dcc_close> event when the connection was disconnected.
1205              
1206             C<$timeout> is the connection try timeout in seconds. The default is 300 (5 minutes).
1207              
1208             =cut
1209              
1210             sub dcc_accept {
1211 0     0 1   my ($self, $id, $timeout) = @_;
1212              
1213 0 0         my $dcc = $self->{dcc}->{$id}
1214             or return;
1215              
1216 0           weaken $dcc;
1217 0           weaken $self;
1218              
1219             $dcc->{timeout} = AnyEvent->timer (after => $timeout || 5 * 60, cb => sub {
1220 0 0   0     $self->dcc_disconnect ($id, "CONNECT TIMEOUT") if $self;
1221 0   0       });
1222              
1223             $dcc->{connect} = tcp_connect $dcc->{ip}, $dcc->{port}, sub {
1224 0     0     my ($fh) = @_;
1225 0 0 0       return unless $dcc && $self;
1226              
1227 0           delete $dcc->{timeout};
1228 0           delete $dcc->{connect};
1229              
1230 0 0         unless ($fh) {
1231 0           $self->dcc_disconnect ($id, "CONNECT ERROR: $!");
1232 0           return;
1233             }
1234              
1235             $dcc->{handle} = AnyEvent::Handle->new (
1236             fh => $fh,
1237             on_eof => sub {
1238 0           delete $dcc->{handle};
1239 0           $self->dcc_disconnect ($id, "EOF");
1240             },
1241             on_error => sub {
1242 0           delete $dcc->{handle};
1243 0           $self->dcc_disconnect ($id, "ERROR: $!");
1244             }
1245 0           );
1246              
1247 0           $self->event (dcc_connected => $id, $dcc->{type}, $dcc->{handle});
1248 0           };
1249              
1250 0           $id
1251             }
1252              
1253             sub dcc_handle {
1254 0     0 0   my ($self, $id) = @_;
1255              
1256 0 0         if (my $dcc = $self->{dcc}->{$id}) {
1257 0           return $dcc->{handle}
1258             }
1259 0           return;
1260             }
1261              
1262             sub send_dcc_chat {
1263 0     0 0   my ($self, $id, $msg) = @_;
1264              
1265 0 0         if (my $dcc = $self->{dcc}->{$id}) {
1266 0 0         if ($dcc->{handle}) {
1267 0           $dcc->{handle}->push_write ("$msg\015\012");
1268             }
1269             }
1270             }
1271              
1272             ################################################################################
1273             # Private utility functions
1274             ################################################################################
1275              
1276             sub _was_me {
1277 0     0     my ($self, $msg) = @_;
1278 0           $self->lower_case (prefix_nick ($msg)) eq $self->lower_case ($self->nick ())
1279             }
1280              
1281             sub update_ident {
1282 0     0 0   my ($self, $ident) = @_;
1283 0           my ($n, $u, $h) = split_prefix ($ident);
1284 0           my $old = $self->{idents}->{$self->lower_case ($n)};
1285 0           $self->{idents}->{$self->lower_case ($n)} = $ident;
1286 0 0         if ($old ne $ident) {
1287 0           $self->event (ident_change => $n, $ident);
1288             }
1289             #d# warn "IDENTS:\n".(join "\n", map { "\t$_\t=>\t$self->{idents}->{$_}" } keys %{$self->{idents}})."\n";
1290             }
1291              
1292             ################################################################################
1293             # Channel utility functions
1294             ################################################################################
1295              
1296             sub channel_remove {
1297 0     0 1   my ($self, $msg, $chan, $nicks) = @_;
1298              
1299 0           for my $nick (@$nicks) {
1300 0 0         if ($self->lower_case ($nick) eq $self->lower_case ($self->nick ())) {
1301 0           delete $self->{chan_queue}->{$self->lower_case ($chan)};
1302 0           delete $self->{channel_list}->{$self->lower_case ($chan)};
1303 0           last;
1304             } else {
1305 0           delete $self->{channel_list}->{$self->lower_case ($chan)}->{$nick};
1306             }
1307             }
1308             }
1309              
1310             sub channel_add {
1311 0     0 1   my ($self, $msg, $chan, $nicks, $modes) = @_;
1312              
1313 0           my @mods = @$modes;
1314              
1315 0           for my $nick (@$nicks) {
1316 0           my $mode = shift @mods;
1317              
1318 0 0         if ($self->is_my_nick ($nick)) {
1319 0           for (@{$self->{chan_queue}->{$self->lower_case ($chan)}}) {
  0            
1320 0           $self->send_msg (@$_);
1321             }
1322              
1323 0           $self->clear_chan_queue ($chan);
1324             }
1325              
1326 0   0       my $ch = $self->{channel_list}->{$self->lower_case ($chan)} ||= { };
1327              
1328 0 0         if (defined $mode) {
1329 0           $ch->{$nick} = $mode;
1330 0           $self->event (channel_nickmode_update => $chan, $nick);
1331             } else {
1332 0 0         $ch->{$nick} = { } unless defined $ch->{$nick};
1333             }
1334             }
1335             }
1336              
1337             sub channel_mode_change {
1338 0     0 0   my ($self, $chan, $op, $mode, $nick) = @_;
1339              
1340 0           my $nickmode = $self->nick_modes ($chan, $nick);
1341 0 0         defined $nickmode or return;
1342              
1343 0 0         $op eq '+'
1344             ? $nickmode->{$mode} = 1
1345             : delete $nickmode->{$mode};
1346             }
1347              
1348             sub _filter_new_nicks_from_channel {
1349 0     0     my ($self, $chan, @nicks) = @_;
1350 0           grep { not exists $self->{channel_list}->{$self->lower_case ($chan)}->{$_} } @nicks;
  0            
1351             }
1352              
1353             ################################################################################
1354             # Callbacks
1355             ################################################################################
1356              
1357             sub anymsg_cb {
1358 0     0 0   my ($self, $msg) = @_;
1359              
1360 0           my $cmd = lc $msg->{command};
1361              
1362 0 0 0       if ($cmd =~ /^\d\d\d$/ && not ($cmd >= 400 && $cmd <= 599)) {
    0 0        
      0        
      0        
1363 0           $self->event (statmsg => $msg);
1364             } elsif (($cmd >= 400 && $cmd <= 599) || $cmd eq 'error') {
1365 0           $self->event (error => $msg->{command},
1366 0 0         (@{$msg->{params}} ? $msg->{params}->[-1] : ''),
1367             $msg);
1368             }
1369             }
1370              
1371             sub privmsg_cb {
1372 0     0 0   my ($self, $msg) = @_;
1373              
1374 0           my ($trail, $ctcp) = decode_ctcp ($msg->{params}->[-1]);
1375              
1376 0           for (@$ctcp) {
1377 0           $self->event (ctcp => prefix_nick ($msg), $msg->{params}->[0], $_->[0], $_->[1], $msg->{command});
1378 0           $self->event ("ctcp_".lc ($_->[0]), prefix_nick ($msg), $msg->{params}->[0], $_->[1], $msg->{command});
1379             }
1380              
1381 0           $msg->{params}->[-1] = $trail;
1382              
1383 0 0         if ($msg->{params}->[-1] ne '') {
1384 0           my $targ = $msg->{params}->[0];
1385 0 0         if ($self->is_channel_name ($targ)) {
1386 0           $self->event (publicmsg => $targ, $msg);
1387              
1388             } else {
1389 0           $self->event (privatemsg => $targ, $msg);
1390             }
1391             }
1392             }
1393              
1394             sub welcome_cb {
1395 0     0 0   my ($self, $msg) = @_;
1396              
1397 0 0         if ($self->{registered}) {
1398 0           return;
1399             }
1400              
1401 0           $self->{registered} = 1;
1402 0           $self->event ('registered');
1403             }
1404              
1405             sub registered_cb {
1406 0     0 0   my ($self, $msg) = @_;
1407              
1408 0 0         $self->send_srv (WHOIS => $self->nick)
1409             if $self->{send_initial_whois};
1410              
1411 0           for (@{$self->{con_queue}}) {
  0            
1412 0           $self->send_msg (@$_);
1413             }
1414 0           $self->clear_srv_queue ();
1415             }
1416              
1417             sub isupport_cb {
1418 0     0 0   my ($self, $msg) = @_;
1419              
1420 0           foreach (@{$msg->{params}}) {
  0            
1421 0 0         if (/([A-Z]+)(?:=(.+))?/) {
1422 0 0         $self->{isupport}->{$1} = defined $2 ? $2 : 1;
1423             }
1424             }
1425              
1426 0 0         if (defined (my $casemap = $self->{isupport}->{CASEMAPPING})) {
1427 0 0         if (defined (my $func = $LOWER_CASEMAP{$casemap})) {
1428 0           $self->{casemap_func} = $func;
1429             } else {
1430 0           $self->{casemap_func} = $LOWER_CASEMAP{rfc1459};
1431             }
1432             }
1433              
1434 0 0         if (defined (my $nick_prefixes = $self->{isupport}->{PREFIX})) {
1435 0 0         if ($nick_prefixes =~ /^\(([^)]+)\)(.+)$/) {
1436 0           my ($modes, $prefixes) = ($1, $2);
1437 0           $self->{prefix_chars} = $prefixes;
1438 0           my @prefixes = split //, $prefixes;
1439 0           $self->{prefix2mode} = { };
1440 0           for (split //, $modes) {
1441 0           $self->{prefix2mode}->{shift @prefixes} = $_;
1442             }
1443             }
1444             }
1445              
1446 0 0 0       if ($self->{isupport}->{NAMESX}
1447             && !$self->{protoctl}->{NAMESX}) {
1448 0           $self->send_srv (PROTOCTL => 'NAMESX');
1449 0           $self->{protoctl}->{NAMESX} = 1;
1450             }
1451              
1452 0 0 0       if ($self->{isupport}->{UHNAMES}
1453             && !$self->{protoctl}->{UHNAMES}) {
1454 0           $self->send_srv (PROTOCTL => 'UHNAMES');
1455 0           $self->{protoctl}->{UHNAMES} = 1;
1456             }
1457              
1458 0 0         if (defined (my $chan_prefixes = $self->{isupport}->{CHANTYPES})) {
1459 0           $self->{channel_chars} = $chan_prefixes;
1460             }
1461             }
1462              
1463             sub ping_cb {
1464 0     0 0   my ($self, $msg) = @_;
1465 0           $self->send_msg ("PONG", $msg->{params}->[0]);
1466             }
1467              
1468             sub pong_cb {
1469 0     0 0   my ($self, $msg) = @_;
1470 0           $self->{last_pong_recv} = time;
1471             }
1472              
1473             sub nick_cb {
1474 0     0 0   my ($self, $msg) = @_;
1475 0           my $nick = prefix_nick ($msg);
1476 0           my $newnick = $msg->{params}->[0];
1477 0           my $wasme = $self->_was_me ($msg);
1478              
1479 0 0         if ($wasme) { $self->{nick} = $newnick }
  0            
1480              
1481 0           my @chans;
1482              
1483 0           for my $channame (keys %{$self->{channel_list}}) {
  0            
1484 0           my $chan = $self->{channel_list}->{$channame};
1485 0 0         if (exists $chan->{$nick}) {
1486 0           $chan->{$newnick} = delete $chan->{$nick};
1487              
1488 0           push @chans, $channame;
1489             }
1490             }
1491              
1492 0           $self->event (nick_change => $nick, $newnick, $wasme);
1493              
1494 0           for (@chans) {
1495 0           $self->event (channel_change => $msg, $_, $nick, $newnick, $wasme);
1496             }
1497             }
1498              
1499             sub namereply_cb {
1500 0     0 0   my ($self, $msg) = @_;
1501 0           my @nicks = split / /, $msg->{params}->[-1];
1502 0           push @{$self->{_tmp_namereply}}, @nicks;
  0            
1503             }
1504              
1505             sub endofnames_cb {
1506 0     0 0   my ($self, $msg) = @_;
1507 0           my $chan = $msg->{params}->[1];
1508 0           my @names_result = @{delete $self->{_tmp_namereply}};
  0            
1509 0           my @modes = map { ($self->split_nick_mode ($_))[0] } @names_result;
  0            
1510 0           my @nicks = map { ($self->split_nick_mode ($_))[1] } @names_result;
  0            
1511 0           my @idents = grep { defined } map { ($self->split_nick_mode ($_))[2] } @names_result;
  0            
  0            
1512 0           my @new_nicks = $self->_filter_new_nicks_from_channel ($chan, @nicks);
1513              
1514 0           $self->channel_add ($msg, $chan, \@nicks, \@modes);
1515 0           $self->update_ident ($_) for @idents;
1516 0 0         $self->event (channel_add => $msg, $chan, @new_nicks) if @new_nicks;
1517             }
1518              
1519             sub whoreply_cb {
1520 0     0 0   my ($self, $msg) = @_;
1521 0           my (undef, $channel, $user, $host, $server, $nick) = @{$msg->{params}};
  0            
1522 0           $self->update_ident (join_prefix ($nick, $user, $host));
1523             }
1524              
1525             sub whoisuser_cb {
1526 0     0 0   my ($self, $msg) = @_;
1527 0           my (undef, $nick, $user, $host) = @{$msg->{params}};
  0            
1528 0           $self->update_ident (join_prefix ($nick, $user, $host));
1529             }
1530              
1531             sub join_cb {
1532 0     0 0   my ($self, $msg) = @_;
1533 0           my $chan = $msg->{params}->[0];
1534 0           my $nick = prefix_nick ($msg);
1535              
1536 0           my @new_nicks = $self->_filter_new_nicks_from_channel ($chan, $nick);
1537              
1538 0           $self->channel_add ($msg, $chan, [$nick], [undef]);
1539 0 0         $self->event (channel_add => $msg, $chan, @new_nicks) if @new_nicks;
1540 0           $self->event (join => $nick, $chan, $self->_was_me ($msg));
1541              
1542 0 0 0       if ($self->_was_me ($msg) && !$self->isupport ('UHNAMES')) {
1543 0           $self->send_srv (WHO => $chan);
1544             }
1545             }
1546              
1547             sub part_cb {
1548 0     0 0   my ($self, $msg) = @_;
1549 0           my $chan = $msg->{params}->[0];
1550 0           my $nick = prefix_nick ($msg);
1551              
1552 0           $self->event (part => $nick, $chan, $self->_was_me ($msg), $msg->{params}->[1]);
1553 0           $self->channel_remove ($msg, $chan, [$nick]);
1554 0           $self->event (channel_remove => $msg, $chan, $nick);
1555             }
1556              
1557             sub kick_cb {
1558 0     0 0   my ($self, $msg) = @_;
1559 0           my $chan = $msg->{params}->[0];
1560 0           my $kicked_nick = $msg->{params}->[1];
1561 0           my $kicker_nick = prefix_nick($msg);
1562              
1563 0           $self->event (kick => $kicked_nick, $chan, $self->_was_me ($msg), $msg->{params}->[2], $kicker_nick);
1564 0           $self->channel_remove ($msg, $chan, [$kicked_nick]);
1565 0           $self->event (channel_remove => $msg, $chan, $kicked_nick);
1566             }
1567              
1568             sub quit_cb {
1569 0     0 0   my ($self, $msg) = @_;
1570 0           my $nick = prefix_nick ($msg);
1571              
1572 0           $self->event (quit => $nick, $msg->{params}->[0]);
1573              
1574 0           for (keys %{$self->{channel_list}}) {
  0            
1575 0 0         if ($self->{channel_list}->{$_}->{$nick}) {
1576 0           $self->channel_remove ($msg, $_, [$nick]);
1577 0           $self->event (channel_remove => $msg, $_, $nick);
1578             }
1579             }
1580             }
1581              
1582             sub mode_cb {
1583 0     0 0   my ($self, $msg) = @_;
1584 0           my $changer = prefix_nick ($msg);
1585 0           my ($target, $mode, $dest) = (@{$msg->{params}});
  0            
1586              
1587 0 0         if ($self->is_channel_name ($target)) {
1588 0 0 0       if ($mode =~ /^([+-])(\S+)$/ && defined $dest) {
1589 0           my ($op, $mode) = ($1, $2);
1590              
1591 0 0         if (defined $self->map_mode_to_prefix ($mode)) {
1592 0           $self->channel_mode_change ($target, $op, $mode, $dest);
1593 0           $self->event (channel_nickmode_update => $target, $dest);
1594             }
1595             }
1596             }
1597             }
1598              
1599             sub away_change_cb {
1600 0     0 0   my ($self, $msg) = @_;
1601              
1602 0 0         if ($msg->{command} eq '305') { # no longer away
1603 0           delete $self->{away_status};
1604             } else { # away
1605 0           $self->{away_status} = 1;
1606             }
1607              
1608 0           $self->event (away_status_change => $self->{away_status});
1609             }
1610              
1611             sub debug_cb {
1612 0     0 0   my ($self, $msg) = @_;
1613 0           $self->event (debug_recv => $msg);
1614             }
1615              
1616             sub change_nick_login_cb {
1617 0     0 0   my ($self, $msg) = @_;
1618              
1619 0 0         if ($self->registered) {
1620 0           delete $self->{change_nick_cb_guard};
1621              
1622             } else {
1623 0           my $newnick = $self->{nick_change}->($self->nick);
1624              
1625 0 0         if ($self->lower_case ($newnick) eq $self->lower_case ($self->{nick})) {
1626 0           $self->disconnect ("couldn't change nick to non-conflicting one");
1627 0           return 0;
1628             }
1629              
1630 0           $self->{nick} = $newnick;
1631 0           $self->send_msg ("NICK", $newnick);
1632             }
1633             }
1634              
1635             sub disconnect_cb {
1636 0     0 0   my ($self) = @_;
1637              
1638 0           for (keys %{$self->{channel_list}}) {
  0            
1639 0           $self->channel_remove (undef, $_, [$self->nick]);
1640 0           $self->event (channel_remove => undef, $_, $self->nick)
1641             }
1642              
1643 0           $self->cleanup;
1644             }
1645              
1646             sub rpl_topic_cb {
1647 0     0 0   my ($self, $msg) = @_;
1648 0           my $chan = $msg->{params}->[1];
1649 0           my $topic = $msg->{params}->[-1];
1650              
1651 0           $self->event (channel_topic => $chan, $topic);
1652             }
1653              
1654             sub topic_change_cb {
1655 0     0 0   my ($self, $msg) = @_;
1656 0           my $who = prefix_nick ($msg);
1657 0           my $chan = $msg->{params}->[0];
1658 0           my $topic = $msg->{params}->[-1];
1659              
1660 0           $self->event (channel_topic => $chan, $topic, $who);
1661             }
1662              
1663             sub update_ident_cb {
1664 0     0 0   my ($self, $msg) = @_;
1665              
1666 0 0         if (is_nick_prefix ($msg->{prefix})) {
1667 0           $self->update_ident ($msg->{prefix});
1668             }
1669             }
1670              
1671             sub update_ident_nick_change_cb {
1672 0     0 0   my ($self, $old, $new) = @_;
1673              
1674 0           my $oldid = $self->nick_ident ($old);
1675 0 0         return unless defined $oldid;
1676              
1677 0           my ($n, $u, $h) = split_prefix ($oldid);
1678              
1679 0           $self->update_ident (join_prefix ($new, $u, $h));
1680             }
1681              
1682             sub ctcp_auto_reply_cb {
1683 0     0 0   my ($self, $src, $targ, $tag, $msg, $type) = @_;
1684              
1685 0 0         return if $type ne 'PRIVMSG';
1686              
1687 0 0         my $ctcprepl = $self->{ctcp_auto_replies}->{$tag}
1688             or return;
1689              
1690 0 0         if (ref ($ctcprepl->[0]) eq 'CODE') {
1691 0           $ctcprepl = [$ctcprepl->[0]->($self, $src, $targ, $tag, $msg, $type)]
1692             }
1693              
1694 0           $self->send_msg (NOTICE => $src, encode_ctcp (@$ctcprepl));
1695             }
1696              
1697             =back
1698              
1699             =head1 EXAMPLES
1700              
1701             See samples/anyeventirccl and other samples in samples/ for some examples on how to use AnyEvent::IRC::Client.
1702              
1703             =head1 AUTHOR
1704              
1705             Robin Redeker, C<< <elmex@ta-sa.org> >>
1706              
1707             =head1 SEE ALSO
1708              
1709             L<AnyEvent::IRC::Connection>
1710              
1711             RFC 1459 - Internet Relay Chat: Client Protocol
1712              
1713             =head1 COPYRIGHT & LICENSE
1714              
1715             Copyright 2006-2009 Robin Redeker, all rights reserved.
1716              
1717             This program is free software; you can redistribute it and/or modify it
1718             under the same terms as Perl itself.
1719              
1720             =cut
1721              
1722             1;