ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/Net-IRC3/lib/Net/IRC3/Client/Connection.pm
Revision: 1.12
Committed: Fri Jan 5 10:46:31 2007 UTC (19 years, 9 months ago) by elmex
Branch: MAIN
Changes since 1.11: +59 -20 lines
Log Message:
- fixed bugs in nick handling and added support for the NICK
  change command in Net::IRC3::Client::Connection
- Net::IRC3::Client::Connection->channel_list now returns channel and nick
  information in the servers cAsE.

File Contents

# User Rev Content
1 elmex 1.1 package Net::IRC3::Client::Connection;
2 elmex 1.4 use base "Net::IRC3::Connection";
3     use Net::IRC3::Util qw/prefix_nick/;
4 elmex 1.12 use strict;
5 elmex 1.1
6 elmex 1.4 our $DEBUG;
7 elmex 1.1
8     =head1 NAME
9    
10     Net::IRC3::Client::Connection - A highlevel IRC connection
11    
12     =head1 SYNOPSIS
13    
14 elmex 1.5 use AnyEvent;
15     use Net::IRC3::Client::Connection;
16 elmex 1.1
17 elmex 1.5 my $c = AnyEvent->condvar;
18 elmex 1.1
19 elmex 1.5 my $timer;
20     my $con = new Net::IRC3::Client::Connection;
21 elmex 1.1
22 elmex 1.5 $con->reg_cb (registered => sub { print "I'm in!\n"; 0 });
23     $con->reg_cb (disconnect => sub { print "I'm out!\n"; 0 });
24     $con->reg_cb (
25     sent => sub {
26     if ($_[2] eq 'PRIVMSG') {
27     print "Sent message!\n";
28     $timer = AnyEvent->timer (after => 1, cb => sub { $c->broadcast });
29     }
30     1
31     }
32     );
33    
34     $con->send_srv (PRIVMSG => "Hello there i'm the cool Net::IRC3 test script!", 'elmex');
35    
36     $con->connect ("localhost", 6667);
37     $con->register (qw/testbot testbot testbot/);
38 elmex 1.1
39 elmex 1.5 $c->wait;
40     undef $timer;
41    
42     $con->disconnect;
43 elmex 1.1
44     =head1 DESCRIPTION
45    
46 elmex 1.5 L<Net::IRC3::Client::Connection> is a highlevel client connection,
47     that manages all the stuff that noone wants to implement again and again
48     when handling with IRC. For example it PONGs the server or keeps track
49     of the users on a channel.
50 elmex 1.1
51 elmex 1.2 =head1 EVENTS
52    
53     The following events are emitted by L<Net::IRC3::Client::Connection>.
54     Use C<reg_cb> as described in L<Net::IRC3::Connection> to register to such an
55     event.
56 elmex 1.1
57     =over 4
58    
59 elmex 1.3 =item B<registered>
60    
61     Emitted when the connection got successfully registered.
62    
63 elmex 1.2 =item B<channel_add $channel @nicks>
64    
65     Emitted when C<@nicks> are added to the channel C<$channel>,
66     this happens for example when someone JOINs a channel or when you
67     get a RPL_NAMREPLY (see RFC2812).
68    
69     =item B<channel_remove $channel @nicks>
70    
71     Emitted when C<@nicks> are removed from the channel C<$channel>,
72     happens for example when they PART, QUIT or get KICKed.
73    
74     =item B<join $nick $channel $is_myself>
75    
76     Emitted when C<$nick> enters the channel C<$channel> by JOINing.
77     C<$is_myself> is true if youself are the one who JOINs.
78    
79     =item B<part $nick $channel $is_myself $msg>
80    
81     Emitted when C<$nick> PARTs the channel C<$channel>.
82     C<$is_myself> is true if youself are the one who PARTs.
83     C<$msg> is the PART message.
84 elmex 1.1
85 elmex 1.12 =item B<nick_change $old_nick, $new_nick, $is_myself>
86    
87     Emitted when C<$old_nick> is renamed to C<$new_nick>.
88     C<$is_myself> is true when youself was the one who changed the nick.
89    
90 elmex 1.3 =item B<quit $nick $msg>
91    
92     Emitted when the nickname C<$nick> QUITs with the message C<$msg>.
93    
94     =item B<publicmsg $channel $ircmsg>
95    
96     Emitted for NOTICE and PRIVMSG where the target C<$channel> is a channel.
97     C<$ircmsg> is the original IRC message hash like it is returned by C<parse_irc_msg>.
98    
99     =item B<privatemsg $nick $ircmsg>
100    
101     Emitted for NOTICE and PRIVMSG where the target C<$nick> (most of the time you) is a nick.
102     C<$ircmsg> is the original IRC message hash like it is returned by C<parse_irc_msg>.
103    
104 elmex 1.2 =back
105    
106     =head1 METHODS
107    
108     =over 4
109 elmex 1.1
110     =cut
111    
112 elmex 1.2 sub new {
113     my $this = shift;
114     my $class = ref($this) || $this;
115     my $self = $class->SUPER::new (@_);
116 elmex 1.1 $self->reg_cb (irc_001 => \&welcome_cb);
117     $self->reg_cb (irc_join => \&join_cb);
118 elmex 1.12 $self->reg_cb (irc_nick => \&nick_cb);
119 elmex 1.1 $self->reg_cb (irc_part => \&part_cb);
120 elmex 1.2 $self->reg_cb (irc_kick => \&kick_cb);
121     $self->reg_cb (irc_quit => \&quit_cb);
122 elmex 1.1 $self->reg_cb (irc_353 => \&namereply_cb);
123     $self->reg_cb (irc_366 => \&endofnames_cb);
124     $self->reg_cb (irc_ping => \&ping_cb);
125    
126     $self->reg_cb (irc_privmsg => \&privmsg_cb);
127     $self->reg_cb (irc_notice => \&privmsg_cb);
128    
129     $self->reg_cb ('irc_*' => \&debug_cb)
130     if $DEBUG;
131     $self->reg_cb ('irc_*' => \&anymsg_cb);
132    
133 elmex 1.2 $self->reg_cb (channel_remove => \&channel_remove_event);
134     $self->reg_cb (channel_add => \&channel_add_event);
135    
136     return $self;
137     }
138    
139     =item B<register ($nick, $user, $real)>
140    
141     Sends the IRC registration commands NICK and USER.
142    
143     =cut
144    
145     sub register {
146     my ($self, $nick, $user, $real) = @_;
147    
148 elmex 1.1 $self->send_msg (undef, "NICK", undef, $nick);
149     $self->send_msg (undef, "USER", $real || $nick, $user || $nick, "*", "0");
150    
151     $self->{nick} = $nick;
152     $self->{user} = $user;
153     $self->{real} = $real;
154     }
155    
156     =item B<nick ()>
157    
158     Returns the current nickname, under which this connection
159     is registered at the IRC server. It might be different from the
160     one that was passed to C<register> as a nick-collision might happened
161     on login.
162    
163     =cut
164    
165     sub nick { $_[0]->{nick} }
166    
167     =item B<channel_list ()>
168    
169 elmex 1.2 This returns a hash reference. The keys are the currently joined channels. The values
170     are hash references which contain the joined nicks as key.
171 elmex 1.1
172     =cut
173    
174     sub channel_list {
175     my ($self) = @_;
176 elmex 1.12 return $self->{channel_list} || {};
177 elmex 1.1 }
178    
179 elmex 1.5 =item B<send_srv ($command, $trailing, @params)>
180 elmex 1.1
181 elmex 1.5 This function sends an IRC message that is constructed by C<mk_msg (undef, $command, $trailing, @params)> (see L<Net::IRC3::Util>).
182 elmex 1.1 If the connection isn't yet registered (for example if the connection is slow) and hasn't got a
183     welcome (IRC command 001) from the server yet, the IRC message is queued until it gets a welcome.
184    
185     =cut
186    
187     sub send_srv {
188     my ($self, @msg) = @_;
189    
190     if ($self->{connected}) {
191     $self->send_msg (undef, @msg);
192    
193     } else {
194     push @{$self->{con_queue}}, \@msg;
195     }
196     }
197    
198     =item B<clear_srv_queue>
199    
200     Clears the server send queue.
201    
202     =cut
203    
204     sub clear_srv_queue {
205     my ($self) = @_;
206     $self->{con_queue} = [];
207     }
208    
209    
210 elmex 1.5 =item B<send_chan ($channel, $command, $trailing, @params))>
211    
212     This function sends a message (constructed by C<mk_msg (undef, $command, $trailing, @params)>
213     to the server, like C<send_srv> only that it will queue the messages if it hasn't joined the
214     channel C<$channel> yet. The queued messages will be send once the connection successfully
215     JOINed the C<$channel>.
216 elmex 1.1
217 elmex 1.12 C<$channel> will be lowercased so that any case that comes from the server matches.
218     (Yes, IRC handles upper and lower case as equal :-(
219    
220     Be careful with this, there are chances you might not join the channel you
221     wanted to join. You may wanted to join #bla and the server redirects that
222     and sends you that you joined #blubb. You may use C<clear_chan_queue> to
223     remove the queue after some timeout after joining, so that you don't end up
224     with a memory leak.
225    
226 elmex 1.1 =cut
227    
228     sub send_chan {
229     my ($self, $chan, @msg) = @_;
230    
231 elmex 1.2 if ($self->{channels}->{lc $chan}) {
232 elmex 1.1 $self->send_msg (undef, @msg);
233    
234     } else {
235     push @{$self->{chan_queue}->{lc $chan}}, \@msg;
236     }
237     }
238    
239     =item B<clear_chan_queue ($channel)>
240    
241     Clears the channel queue of the channel C<$channel>.
242    
243     =cut
244    
245     sub clear_chan_queue {
246     my ($self, $chan) = @_;
247     $self->{chan_queue}->{lc $chan} = [];
248     }
249    
250     ################################################################################
251 elmex 1.2 # Private utility functions
252     ################################################################################
253    
254     sub _was_me {
255     my ($self, $msg) = @_;
256 elmex 1.4 lc prefix_nick ($msg) eq lc $self->nick ()
257 elmex 1.2 }
258    
259     ################################################################################
260 elmex 1.1 # Callbacks
261     ################################################################################
262    
263 elmex 1.2 sub channel_remove_event {
264     my ($self, $chan, @nicks) = @_;
265    
266     for my $nick (@nicks) {
267 elmex 1.12 if (lc ($nick) eq lc ($self->nick ())) {
268     delete $self->{chan_queue}->{lc $chan};
269     delete $self->{channels}->{lc $chan};
270     delete $self->{channel_list}->{$chan};
271 elmex 1.2 last;
272     } else {
273 elmex 1.12 delete $self->{channels}->{lc $chan}->{lc $nick};
274     delete $self->{channel_list}->{$chan}->{$nick};
275 elmex 1.2 }
276     }
277    
278     1;
279     }
280    
281     sub channel_add_event {
282     my ($self, $chan, @nicks) = @_;
283    
284     for my $nick (@nicks) {
285 elmex 1.12 if (lc ($nick) eq lc ($self->nick ())) {
286     for (@{$self->{chan_queue}->{lc $chan}}) {
287 elmex 1.2 $self->send_msg (undef, @$_);
288     }
289 elmex 1.11 $self->clear_chan_queue ($chan);
290 elmex 1.2 }
291    
292 elmex 1.12 $self->{channels}->{lc $chan}->{lc $nick} = 1;
293     $self->{channel_list}->{$chan}->{$nick} = 1;
294 elmex 1.2 }
295    
296     1;
297     }
298    
299 elmex 1.1 sub anymsg_cb {
300     my ($self, $msg) = @_;
301    
302     my $cmd = lc $msg->{command};
303    
304     if ( $cmd ne "privmsg"
305     and $cmd ne "notice"
306     and $cmd ne "part"
307     and $cmd ne "join"
308     )
309     {
310     $self->event (statmsg => $msg);
311     }
312    
313     1;
314     }
315    
316     sub privmsg_cb {
317     my ($self, $msg) = @_;
318    
319 elmex 1.3 my $targ = $msg->{params}->[0];
320     if ($targ =~ m/^(?:[#+&]|![A-Z0-9]{5})/) {
321     $self->event (publicmsg => $targ, $msg);
322 elmex 1.1
323     } else {
324 elmex 1.3 $self->event (privatemsg => $targ, $msg);
325 elmex 1.1 }
326    
327     1;
328     }
329    
330     sub welcome_cb {
331     my ($self, $msg) = @_;
332    
333     $self->{connected} = 1;
334    
335     for (@{$self->{con_queue}}) {
336     $self->send_msg (undef, @$_);
337     }
338 elmex 1.11 $self->clear_srv_queue ();
339 elmex 1.1
340 elmex 1.12 $self->event ('registered');
341    
342 elmex 1.1 1;
343     }
344    
345     sub ping_cb {
346     my ($self, $msg) = @_;
347 elmex 1.8 $self->send_msg (undef, "PONG", $msg->{params}->[0]);
348 elmex 1.2
349     1;
350 elmex 1.1 }
351    
352 elmex 1.12 sub nick_cb {
353     my ($self, $msg) = @_;
354     my $nick = prefix_nick ($msg);
355     my $newnick = $msg->{params}->[0];
356     my $wasme = $self->_was_me ($msg);
357    
358     warn "NICK $nick => $newnick\n";
359    
360     if ($wasme) { $self->{nick} = $newnick }
361    
362     for my $chan (values %{$self->{channel_list}}) {
363     if (exists $chan->{$nick}) {
364     delete $chan->{$nick};
365     $chan->{$newnick} = 1;
366     }
367     }
368    
369     for my $chan (values %{$self->{channels}}) {
370     if (exists $chan->{lc $nick}) {
371     delete $chan->{lc $nick};
372     $chan->{lc $newnick} = 1;
373     }
374     }
375    
376     $self->event (nick_change => $nick, $newnick, $wasme);
377     }
378    
379 elmex 1.1 sub namereply_cb {
380     my ($self, $msg) = @_;
381 elmex 1.2 my @nicks = split / /, $msg->{trailing};
382     push @{$self->{_tmp_namereply}}, @nicks;
383 elmex 1.10
384     1;
385 elmex 1.1 }
386    
387     sub endofnames_cb {
388     my ($self, $msg) = @_;
389 elmex 1.12 my $chan = $msg->{params}->[1];
390 elmex 1.4 $self->event (channel_add => $chan, map { s/^[@\+]//; $_ } @{delete $self->{_tmp_namereply}});
391 elmex 1.10
392     1;
393 elmex 1.1 }
394    
395     sub join_cb {
396     my ($self, $msg) = @_;
397 elmex 1.2 my $chan = $msg->{params}->[0];
398 elmex 1.4 my $nick = prefix_nick ($msg);
399 elmex 1.1
400 elmex 1.12 $self->event (channel_add => $chan, $nick);
401 elmex 1.2 $self->event (join => $nick, $chan, $self->_was_me ($msg));
402 elmex 1.1
403 elmex 1.2 1;
404     }
405    
406     sub part_cb {
407     my ($self, $msg) = @_;
408     my $chan = $msg->{params}->[0];
409 elmex 1.4 my $nick = prefix_nick ($msg);
410 elmex 1.1
411 elmex 1.2 $self->event (part => $nick, $chan, $self->_was_me ($msg), $msg->{params}->[1]);
412     $self->event (channel_remove => $chan, $nick);
413 elmex 1.1
414 elmex 1.2 1;
415     }
416 elmex 1.1
417 elmex 1.2 sub kick_cb {
418     my ($self, $msg) = @_;
419     my $chan = $msg->{params}->[0];
420     my $kicked_nick = $msg->{params}->[1];
421 elmex 1.1
422 elmex 1.2 $self->event (channel_remove => $chan, $kicked_nick);
423 elmex 1.1
424     1;
425     }
426    
427 elmex 1.2 sub quit_cb {
428 elmex 1.1 my ($self, $msg) = @_;
429 elmex 1.4 my $nick = prefix_nick ($msg);
430 elmex 1.1
431 elmex 1.2 $self->event (quit => $nick, $msg->{params}->[1]);
432 elmex 1.1
433 elmex 1.12 for (keys %{$self->{channel_list}}) {
434 elmex 1.2 $self->event (channel_remove => $_, $nick);
435 elmex 1.1 }
436 elmex 1.10
437     1;
438 elmex 1.1 }
439    
440     sub debug_cb {
441     my ($self, $msg) = @_;
442     print "$self->{h}:$self->{p} > ";
443     my $par = delete $msg->{params};
444     print (join " ", map { $_ => $msg->{$_} } sort keys %$msg);
445     print " params:";
446     print (join ",", @$par);
447     print "\n";
448 elmex 1.10
449     1;
450 elmex 1.1 }
451    
452     =back
453    
454     =head1 EXAMPLES
455    
456     See samples/netirc3cl and other samples in samples/ for some examples on how to use Net::IRC3::Client::Connection.
457    
458     =head1 AUTHOR
459    
460     Robin Redeker, C<< <elmex@ta-sa.org> >>
461    
462     =head1 SEE ALSO
463    
464 elmex 1.7 L<Net::IRC3::Connection>
465 elmex 1.1
466     RFC 2812 - Internet Relay Chat: Client Protocol
467    
468     =head1 COPYRIGHT & LICENSE
469    
470 elmex 1.6 Copyright 2006 Robin Redeker, all rights reserved.
471 elmex 1.1
472     This program is free software; you can redistribute it and/or modify it
473     under the same terms as Perl itself.
474    
475     =cut
476    
477     1;