File Coverage

blib/lib/Net/IRC3/Connection.pm
Criterion Covered Total %
statement 21 136 15.4
branch 0 36 0.0
condition 0 9 0.0
subroutine 7 25 28.0
pod 10 10 100.0
total 38 216 17.5


line stmt bran cond sub pod time code
1             package Net::IRC3::Connection;
2 1     1   945 use strict;
  1         2  
  1         33  
3 1     1   4 no warnings;
  1         2  
  1         28  
4 1     1   4 use AnyEvent;
  1         2  
  1         14  
5 1     1   855 use POSIX;
  1         6867  
  1         8  
6 1     1   4070 use IO::Socket::INET;
  1         22  
  1         12  
7 1     1   970 use IO::Handle;
  1         2  
  1         51  
8 1     1   6 use Net::IRC3::Util qw/mk_msg parse_irc_msg/;
  1         1  
  1         1731  
9              
10             =head1 NAME
11              
12             Net::IRC3::Connection - An IRC connection abstraction
13              
14             =head1 SYNOPSIS
15              
16             #...
17             $con->send_msg (undef, "PRIVMSG", "Hello there!", "yournick");
18             #...
19              
20             =head1 DESCRIPTION
21              
22             B This module is B, please use L for new programs,
23             and possibly port existing L applications to L. Though the
24             API of L has incompatible changes, it's still fairly similar.
25              
26              
27             The connection class. Here the actual interesting stuff can be done,
28             such as sending and receiving IRC messages.
29              
30             Please note that CTCP support is available through the functions
31             C and C provided by L.
32              
33             =head2 METHODS
34              
35             =over 4
36              
37             =item B
38              
39             This constructor does take no arguments.
40              
41             =cut
42              
43             sub new
44             {
45 0     0 1   my $this = shift;
46 0   0       my $class = ref($this) || $this;
47              
48 0           my $self = {
49             cbs => {},
50             heap => {},
51             outbuf => ''
52             };
53              
54 0           bless $self, $class;
55              
56 0           return $self;
57             }
58              
59             =item B
60              
61             Tries to open a socket to the host C<$host> and the port C<$port>.
62             If an error occured it will die (use eval to catch the exception).
63              
64             =cut
65              
66             sub connect {
67 0     0 1   my ($self, $host, $port) = @_;
68              
69 0 0         $self->{socket}
70             and return;
71              
72 0 0         my $sock = IO::Socket::INET->new (
73             PeerAddr => $host,
74             PeerPort => $port,
75             Proto => 'tcp',
76             Blocking => 0
77             ) or die "couldn't connect to irc server '$host:$port': $!\n";;
78              
79 0           $self->{socket} = $sock;
80 0           $self->{host} = $host;
81 0           $self->{port} = $port;
82              
83             $self->{cw} =
84             AnyEvent->io (poll => 'w', fh => $self->{socket}, cb => sub {
85 0     0     my ($w) = @_;
86             # FIXME: handle EAGAIN ?
87 0           delete $self->{cw};
88              
89 0 0         if ($! = $sock->sockopt (SO_ERROR)) {
90 0           $self->event ('connect_error' => $!);
91 0           $self->_clear_me;
92             } else {
93 0           $self->use_socket ($host, $port, $self->{socket});
94             }
95 0           0
96 0           });
97 0           1
98             }
99              
100             =item B
101              
102             This method can be used instead of C to handle IRC messages
103             that are received and sent over the C<$socket>.
104              
105             In this case C<$host> and C<$port> are just documentation for the error messages.
106              
107             =cut
108              
109             sub use_socket {
110 0     0 1   my ($self, $host, $port, $socket) = @_;
111              
112 0           $self->{host} = $host;
113 0           $self->{port} = $port;
114 0           $self->{socket} = $socket;
115 0           $socket->blocking (0);
116              
117 0           $self->{connected} = 1;
118 0           $self->event ('connect');
119 0           $self->_start_reader;
120 0           $self->_start_writer;
121             }
122              
123             sub _start_reader {
124 0     0     my ($self) = @_;
125 0           my ($host, $port) = ($self->{host}, $self->{port});
126              
127 0 0         return if $self->{rw};
128 0 0         return unless $self->{socket};
129              
130             $self->{rw} =
131             AnyEvent->io (poll => 'r', fh => $self->{socket}, cb => sub {
132 0     0     my $data;
133 0           my $l = $self->{socket}->sysread ($data, 1024);
134              
135             # FIXME: handle EAGAIN
136 0 0         if (defined $l) {
137 0 0         if ($l == 0) {
138 0           $self->disconnect ("EOF from IRC server '$host:$port'");
139             return
140 0           } else {
141 0           $self->_feed_irc_data ($data);
142             }
143              
144             } else {
145 0 0         if ($! == EAGAIN()) {
146 0           return;
147              
148             } else {
149 0           $self->disconnect ("Error while reading from IRC server '$host:$port': $!");
150 0           return;
151             }
152             }
153 0           });
154             }
155              
156              
157             sub _start_writer {
158 0     0     my ($self) = @_;
159              
160 0 0 0       return unless $self->{socket} && $self->{connected} && length ($self->{outbuf}) > 0;
      0        
161              
162 0           my ($host, $port) = ($self->{host}, $self->{port});
163              
164 0 0         unless (defined $self->{ww}) {
165             $self->{ww} =
166             AnyEvent->io (poll => 'w', fh => $self->{socket}, cb => sub {
167 0     0     my $l = syswrite $self->{socket}, $self->{outbuf};
168              
169 0 0         if (defined $l) {
170 0           substr $self->{outbuf}, 0, $l, "";
171 0 0         if (length ($self->{outbuf}) == 0) { delete $self->{ww} }
  0            
172              
173             } else {
174 0 0         if ($! == EAGAIN()) {
175              
176 0           return;
177             } else {
178 0           $self->disconnect ("Error while writing to IRC server '$self->{host}:$self->{port}': $!");
179 0           return;
180             }
181             }
182 0           });
183             }
184             }
185              
186             =item B
187              
188             Unregisters the connection in the main Net::IRC3 object, closes
189             the sockets and send a 'disconnect' event with C<$reason> as argument.
190              
191             =cut
192              
193             sub disconnect {
194 0     0 1   my ($self, $reason) = @_;
195              
196 0           $self->event (disconnect => $reason);
197 0           $self->_clear_me;
198              
199             }
200              
201             =item B
202              
203             Returns true when this connection is connected.
204             Otherwise false.
205              
206             =cut
207              
208             sub is_connected {
209 0     0 1   my ($self) = @_;
210 0 0         $self->{socket} && $self->{connected}
211             }
212              
213             sub _clear_me {
214 0     0     my ($self) = @_;
215              
216 0           delete $self->{connected};
217              
218 0           delete $self->{rw};
219 0           delete $self->{ww};
220 0           delete $self->{cw};
221              
222 0           delete $self->{socket};
223              
224 0           delete $self->{cbs};
225 0           delete $self->{events};
226             }
227              
228             =item B
229              
230             Returns a hash reference that is local to this connection object
231             that lets you store any information you want.
232              
233             =cut
234              
235             sub heap {
236 0     0 1   my ($self) = @_;
237 0           return $self->{heap};
238             }
239              
240             =item B
241              
242             This method sends C<$ircline> straight to the server without any
243             further processing done.
244              
245             =cut
246              
247             sub send_raw {
248 0     0 1   my ($self, $ircline) = @_;
249 0           $self->_send_raw ("$ircline\015\012");
250             }
251              
252             sub _send_raw {
253 0     0     my ($self, $data) = @_;
254              
255 0           $self->{outbuf} .= $data;
256 0           $self->_start_writer;
257             }
258              
259             =item B
260              
261             This function sends a message to the server. C<@ircmsg> is the argumentlist
262             for C.
263              
264             =cut
265              
266             sub send_msg {
267 0     0 1   my ($self, @msg) = @_;
268              
269 0           $self->event (sent => @msg);
270 0           $self->_send_raw (mk_msg (@msg));
271             }
272              
273             =item B or B
274              
275             This registers a callback in the connection class.
276             These callbacks will be called by internal events and
277             by IRC protocol commands. You can also specify multiple callback registrations.
278              
279             The first argument to the callbacks is always the connection object
280             itself.
281              
282             If a callback returns a false value, it will be unregistered.
283              
284             NOTE: I
285              
286             If C<$cmd> starts with 'irc_' the callback C<$cb> will be registered
287             for a IRC protocol command. The command is the suffix of C<$cmd> then.
288             The second argument to the callback is the message hash reference
289             that has the layout that is returned by C.
290              
291             With the special C<$cmd> 'irc_*' the callback will be called on I
292             IRC command that is received.
293              
294             EXAMPLE:
295              
296             $con->reg_cb (irc_privmsg => \&privmsg_handler);
297             # privmsg_handler will be called if an IRC message
298             # with the command 'PRIVMSG' arrives.
299              
300             If C<$cmd> is not prefixed with a 'irc_' it will be called when an event
301             with the name C<$cmd> is emitted. The arguments to the callback depend
302             on the event that is emitted (but remember: the first argument will always be the
303             connection object)
304              
305             Following events are emitted by this module and shouldn't be emitted
306             from a module user call to C.
307              
308             =over 4
309              
310             =item B
311              
312             This event is generated when the socket was successfully connected.
313              
314             =item B
315              
316             This event is generated when the socket couldn't be connected successfully.
317              
318             =item B
319              
320             This event will be generated if the connection is somehow terminated.
321             It will also be emitted when C is called.
322             The second argument to the callback is C<$reason>, a string that contains
323             a clue about why the connection terminated.
324              
325             If you want to reestablish a connection, call C again.
326              
327             =item B
328              
329             Emitted when a message (C<@ircmsg>) was sent to the server.
330             C<@ircmsg> are the arguments to C.
331              
332             =item B<'*' $msg>
333              
334             =item B
335              
336             Emitted when a message (C<$msg>) was read from the server.
337             C<$msg> is the hash reference returned by C;
338              
339             =back
340              
341             =cut
342              
343             sub reg_cb {
344 0     0 1   my ($self, %regs) = @_;
345              
346 0           for my $cmd (keys %regs) {
347 0           my $cb = $regs{$cmd};
348              
349 0 0         if ($cmd =~ m/^irc_(\S+)/i) {
350 0           push @{$self->{cbs}->{lc $1}}, $cb;
  0            
351              
352             } else {
353 0           push @{$self->{events}->{$cmd}}, $cb;
  0            
354             }
355             }
356              
357 0           1;
358             }
359              
360             =item B
361              
362             This function emits an event with the name C<$event> and the arguments C<@args>.
363             The registerd callback that has been registered with C will be called
364             with the first argument being the connection object and the rest of the arguments
365             being C<@args>.
366              
367             EXAMPLE
368              
369             $con->reg_cb (test_event => sub { print "Yay, i love $_[1]!!\n");
370             $con->event (test_event => "IRC");
371              
372             # will print "Yay, i love IRC!!\n"
373              
374             =cut
375              
376             sub event {
377 0     0 1   my ($self, $ev, @arg) = @_;
378              
379 0           my $nxt = [];
380              
381 0           for (@{$self->{events}->{$ev}}) {
  0            
382 0 0         $_->($self, @arg) and push @$nxt, $_;
383             }
384              
385 0           $self->{events}->{$ev} = $nxt;
386             }
387              
388             # internal function, called by the read callbacks above.
389             sub _feed_irc_data {
390 0     0     my ($self, $data) = @_;
391              
392 0           $self->{buffer} .= $data;
393              
394 0           my @msg;
395 0           while ($self->{buffer} =~ s/^([^\015\012]*)\015?\012//) {
396 0           push @msg, $1;
397             }
398              
399 0           for (@msg) {
400 0           my $m = parse_irc_msg ($_);
401              
402 0           $self->event (read => $m);
403              
404 0           my $nxt = [];
405              
406 0           for (@{$self->{cbs}->{lc $m->{command}}}) {
  0            
407 0 0         $_->($self, $m) and push @$nxt, $_;
408             }
409              
410 0           $self->{cbs}->{lc $m->{command}} = $nxt;
411              
412 0           $nxt = [];
413              
414 0           for (@{$self->{cbs}->{'*'}}) {
  0            
415 0 0         $_->($self, $m) and push @$nxt, $_;
416             }
417              
418 0           $self->{cbs}->{'*'} = $nxt;
419             }
420             }
421              
422              
423             =back
424              
425             =head1 AUTHOR
426              
427             Robin Redeker, C<< >>
428              
429             =head1 SEE ALSO
430              
431             L
432              
433             L
434              
435             =head1 COPYRIGHT & LICENSE
436              
437             Copyright 2006 Robin Redeker, all rights reserved.
438              
439             This program is free software; you can redistribute it and/or modify it
440             under the same terms as Perl itself.
441              
442             =cut
443              
444             1;