File Coverage

blib/lib/POE/Component/IRC/Service/Hybrid.pm
Criterion Covered Total %
statement 27 651 4.1
branch 0 268 0.0
condition 0 154 0.0
subroutine 9 74 12.1
pod 13 42 30.9
total 49 1189 4.1


line stmt bran cond sub pod time code
1             # Author: Chris "BinGOs" Williams
2             # Derived from code by Dennis Taylor
3             #
4             # This module may be used, modified, and distributed under the same
5             # terms as Perl itself. Please see the license that came with your Perl
6             # distribution for details.
7             #
8              
9             package POE::Component::IRC::Service::Hybrid;
10              
11 1     1   6 use strict;
  1         2  
  1         31  
12 1         7 use POE qw( Wheel::SocketFactory Wheel::ReadWrite Driver::SysRW
13 1     1   4 Filter::Line Filter::Stream );
  1         3  
14 1     1   930 use POE::Filter::IRC::Hybrid;
  1         3  
  1         28  
15 1     1   400 use POE::Filter::CTCP::Hybrid;
  1         3  
  1         26  
16 1     1   6 use Carp;
  1         2  
  1         47  
17 1     1   6 use Socket;
  1         2  
  1         415  
18 1     1   6 use Sys::Hostname;
  1         2  
  1         39  
19 1     1   5 use vars qw($VERSION);
  1         2  
  1         44  
20              
21             $VERSION = '0.998';
22              
23 1     1   5 use constant PCI_REFCOUNT_TAG => "P::C::I registered";
  1         2  
  1         6433  
24              
25             my %irc_commands =
26             ('quit' => \&oneoptarg_client,
27             'nick' => \&onlyonearg_client,
28             'invite' => \&onlytwoargs_client,
29             'kill' => \&onlytwoargs,
30             'gline' => \&spacesep,
31             'kline' => \&spacesep,
32             'jupe' => \&spacesep,
33             'privmsg' => \&privandnotice,
34             'notice' => \&privandnotice,
35             'join' => \&sjoin,
36             'stats' => \&spacesep_client,
37             'links' => \&spacesep_client,
38             'mode' => \&spacesep_client,
39             'part' => \&commasep_client,
40             'ctcp' => \&ctcp,
41             'ctcpreply' => \&ctcp,
42             );
43              
44             # Create a new IRC Service
45              
46             sub new {
47 0     0 1   my ($package,$alias,$hash) = splice @_, 0, 3;
48 0           my ($package_events);
49              
50 0 0 0       unless ($alias and $hash) {
51 0           croak "Not enough parameters to POE::Component::IRC::Service::Hybrid->new()";
52             }
53              
54 0 0         unless (ref $hash eq 'HASH') {
55 0           croak "Second argument to POE::Component::IRC::Service::P10::new() must be a hash reference";
56             }
57            
58 0           warn "This module has now been deprecated by POE::Component::Server::IRC\n";
59              
60 0 0 0       $hash->{EventMode} = 1 unless ( defined ( $hash->{EventMode} ) and $hash->{EventMode} == 0 );
61              
62 0 0 0       $hash->{Reconnect} = 0 unless ( defined ( $hash->{Reconnect} ) and $hash->{Reconnect} == 1 );
63              
64 0 0 0       $hash->{Debug} = 0 unless ( defined ( $hash->{Debug} ) and $hash->{Debug} == 1 );
65              
66              
67 0 0         if ( $hash->{EventMode} == 1 ) {
68 0           $package_events = [qw( _start
69             _stop
70             _parseline
71             _sock_up
72             _sock_down
73             _sock_failed
74             autoping
75             addnick
76             connect
77             topic
78             irc_hyb_stats
79             irc_hyb_version
80             irc_hyb_server_link
81             irc_hyb_server
82             irc_hyb_squit
83             irc_hyb_eob
84             irc_hyb_ping
85             irc_hyb_quit
86             irc_hyb_kill
87             irc_hyb_nick
88             irc_hyb_whois
89             irc_hyb_sjoin
90             irc_hyb_part
91             irc_hyb_kick
92             irc_hyb_mode
93             kick
94             join
95             register
96             sl_server
97             sl_client
98             shutdown
99             squit
100             unregister)];
101             } else {
102 0           $package_events = [qw( _start
103             _stop
104             _parseline
105             _sock_up
106             _sock_down
107             _sock_failed
108             autoping
109             addnick
110             connect
111             topic
112             irc_hyb_stats
113             irc_hyb_version
114             irc_hyb_server_link
115             irc_hyb_server
116             irc_hyb_squit
117             irc_hyb_eob
118             irc_hyb_ping
119             irc_hyb_quit
120             irc_hyb_kill
121             irc_hyb_nick
122             irc_hyb_whois
123             irc_hyb_mode
124             kick
125             join
126             register
127             sl_server
128             sl_client
129             shutdown
130             squit
131             unregister)];
132             }
133              
134             # Create our object
135 0           my ($self) = { };
136 0           bless ($self);
137              
138             # Parse the passed hash reference
139 0 0 0       unless ($hash->{'ServerName'} and $hash->{'RemoteServer'} and $hash->{'Password'} and $hash->{'ServerPort'}) {
      0        
      0        
140 0           croak "You must specify ServerName, RemoteServer, Password and ServerPort in your hash reference.";
141             }
142              
143 0 0         $hash->{ServerDesc} = "*** POE::Component::IRC::Service ***" unless defined ($hash->{ServerDesc});
144 0 0         $hash->{Version} = "POE-Component-IRC-Service-P10-$VERSION" unless defined ($hash->{Version});
145 0 0         $hash->{'PingFreq'} = 90 unless ( defined ( $hash->{'PingFreq'} ) );
146              
147 0           my @event_map = map {($_, $irc_commands{$_})} keys %irc_commands;
  0            
148              
149             POE::Session->create( inline_states => { @event_map },
150             package_states => [
151             $package => $package_events, ],
152             args => [ $alias, @_ ],
153             heap => { State => $self,
154             servername => $hash->{'ServerName'},
155             serverdesc => $hash->{'ServerDesc'},
156             remoteserver => $hash->{'RemoteServer'},
157             serverport => $hash->{'ServerPort'},
158             password => $hash->{'Password'},
159             localaddr => $hash->{'LocalAddr'},
160             pingfreq => $hash->{'PingFreq'},
161             eventmode => $hash->{'EventMode'},
162             reconnect => $hash->{'Reconnect'},
163             debug => $hash->{'Debug'},
164 0           version => $hash->{'Version'}, },
165             );
166 0           return $self;
167             }
168              
169             # Register and unregister to receive events
170              
171             sub register {
172 0     0 1   my ($kernel, $heap, $session, $sender, @events) =
173             @_[KERNEL, HEAP, SESSION, SENDER, ARG0 .. $#_];
174              
175 0 0         die "Not enough arguments" unless @events;
176              
177             # FIXME: What "special" event names go here? (ie, "errors")
178             # basic, dcc (implies ctcp), ctcp, oper ...what other categories?
179 0           foreach (@events) {
180 0 0         $_ = "irc_hyb_" . $_ unless /^_/;
181 0           $heap->{events}->{$_}->{$sender} = $sender;
182 0           $heap->{sessions}->{$sender}->{'ref'} = $sender;
183 0 0 0       unless ($heap->{sessions}->{$sender}->{refcnt}++ or $session == $sender) {
184 0           $kernel->refcount_increment($sender->ID(), PCI_REFCOUNT_TAG);
185             }
186             }
187             }
188              
189             sub unregister {
190 0     0 1   my ($kernel, $heap, $session, $sender, @events) =
191             @_[KERNEL, HEAP, SESSION, SENDER, ARG0 .. $#_];
192              
193 0 0         die "Not enough arguments" unless @events;
194              
195 0           foreach (@events) {
196 0           delete $heap->{events}->{$_}->{$sender};
197 0 0         if (--$heap->{sessions}->{$sender}->{refcnt} <= 0) {
198 0           delete $heap->{sessions}->{$sender};
199 0 0         unless ($session == $sender) {
200 0           $kernel->refcount_decrement($sender->ID(), PCI_REFCOUNT_TAG);
201             }
202             }
203             }
204             }
205              
206             # Session starts or stops
207              
208             sub _start {
209 0     0     my ($kernel, $session, $heap, $alias) = @_[KERNEL, SESSION, HEAP, ARG0];
210 0           my @options = @_[ARG1 .. $#_];
211              
212 0 0         $session->option( @options ) if @options;
213 0           $kernel->alias_set($alias);
214 0           $kernel->yield( 'register', qw(stats version server_link server squit eob quit kill nick whois sjoin part kick mode) );
215 0           $heap->{irc_filter} = POE::Filter::IRC::Hybrid->new();
216 0           $heap->{ctcp_filter} = POE::Filter::CTCP::Hybrid->new();
217 0 0         $heap->{irc_filter}->debug(1) if ( $heap->{debug} );
218 0           $heap->{connected} = 0;
219 0           $heap->{serverlink} = "";
220 0           $heap->{starttime} = time();
221             }
222              
223             sub _stop {
224 0     0     my ($kernel, $heap, $quitmsg) = @_[KERNEL, HEAP, ARG0];
225              
226 0 0         if ($heap->{connected}) {
227 0           $kernel->call( $_[SESSION], 'shutdown', $quitmsg );
228             }
229             }
230              
231             # Connect to IRC Network
232              
233             sub connect {
234 0     0 1   my ($kernel, $heap, $session, $args) = @_[KERNEL, HEAP, SESSION, ARG0];
235              
236 0 0         if ($heap->{'sock'}) {
237 0           $kernel->call ($session, 'squit');
238             }
239              
240             $heap->{socketfactory} = POE::Wheel::SocketFactory->new(
241             SocketDomain => AF_INET,
242             SocketType => SOCK_STREAM,
243             SocketProtocol => 'tcp',
244             RemoteAddress => $heap->{'remoteserver'},
245             RemotePort => $heap->{'serverport'},
246             SuccessEvent => '_sock_up',
247             FailureEvent => '_sock_failed',
248 0 0         ( $heap->{localaddr} ? (BindAddress => $heap->{localaddr}) : () ),
249             );
250             }
251              
252             sub autoping {
253 0     0 0   my ($kernel,$heap) = @_[KERNEL,HEAP];
254              
255 0 0         if ( $heap->{'socket'} ) {
256 0           $kernel->yield( 'sl_client', "PING :$heap->{serverlink}" );
257 0           $kernel->delay( 'autoping' => $heap->{pingfreq} );
258             }
259             }
260              
261             sub squit {
262 0     0 1   my ($kernel, $heap) = @_[KERNEL,HEAP];
263              
264             # Don't give a f**k about any parameters passed
265              
266 0 0         if ( $heap->{'socket'} ) {
267 0           delete ( $heap->{'socket'} );
268 0           $kernel->yield( 'sl_client', "SQUIT $heap->{serverlink} :$heap->{servername}" );
269             }
270             }
271              
272             # Internal function called when a socket is closed.
273             sub _sock_down {
274 0     0     my ($kernel, $heap) = @_[KERNEL, HEAP];
275              
276             # Destroy the RW wheel for the socket.
277 0           delete $heap->{'socket'};
278 0           $heap->{connected} = 0;
279              
280             # post a 'irc_disconnected' to each session that cares
281 0           foreach (keys %{$heap->{sessions}}) {
  0            
282             $kernel->post( $heap->{sessions}->{$_}->{'ref'},
283 0           'irc_hyb_disconnected', $heap->{server} );
284             }
285             }
286              
287             sub _sock_up {
288 0     0     my ($kernel,$heap,$session,$socket) = @_[KERNEL,HEAP,SESSION,ARG0];
289 0           $heap->{connecttime} = time();
290 0           $heap->{State}->_burst_create();
291              
292 0           delete $heap->{socketfactory};
293              
294 0           $heap->{localaddr} = (unpack_sockaddr_in( getsockname $socket))[1];
295              
296 0           $heap->{'socket'} = new POE::Wheel::ReadWrite
297             (
298             Handle => $socket,
299             Driver => POE::Driver::SysRW->new(),
300             Filter => POE::Filter::Line->new(),
301             InputEvent => '_parseline',
302             ErrorEvent => '_sock_down',
303             );
304              
305 0 0         if ($heap->{'socket'}) {
306 0           $heap->{connected} = 1;
307             } else {
308 0           _send_event ( $kernel, $heap, 'irc_hyb_socketerr', "Couldn't create ReadWrite wheel for IRC socket" );
309             }
310              
311 0           foreach (keys %{$heap->{sessions}}) {
  0            
312 0           $kernel->post( $heap->{sessions}->{$_}->{'ref'}, 'irc_hyb_connected', $heap->{remoteserver} );
313             }
314              
315 0           $heap->{socket}->put("PASS $heap->{password} :TS\n");
316 0           $heap->{socket}->put("CAPAB :EOB\n");
317 0           $heap->{socket}->put("SERVER $heap->{servername} 1 :$heap->{serverdesc}\n");
318 0           $heap->{socket}->put("SVINFO 3 3 1 :$heap->{connecttime}\n");
319             }
320              
321             sub _sock_failed {
322 0     0     my ($kernel, $heap, $op, $errno, $errstr) = @_[KERNEL, HEAP, ARG0..ARG2];
323              
324 0           _send_event( $kernel, $heap, 'irc_hyb_socketerr', "$op error $errno: $errstr" );
325             }
326              
327             # Parse each line from received at the socket
328              
329             # Parse a message from the IRC server and generate the appropriate
330             # event(s) for listening sessions.
331             sub _parseline {
332 0     0     my ($kernel, $session, $heap, $line) = @_[KERNEL, SESSION, HEAP, ARG0];
333 0           my (@events, @cooked);
334              
335             # Feed the proper Filter object the raw IRC text and get the
336             # "cooked" events back for sending, then deliver each event. We
337             # handle CTCPs separately from normal IRC messages here, to avoid
338             # silly module dependencies later.
339              
340 0           @cooked = ($line =~ tr/\001// ? @{$heap->{ctcp_filter}->get( [$line] )}
341 0 0         : @{$heap->{irc_filter}->get( [$line] )} );
  0            
342              
343 0           foreach my $ev (@cooked) {
344 0           $ev->{name} = 'irc_hyb_' . $ev->{name};
345 0           _send_event( $kernel, $heap, $ev->{name}, @{$ev->{args}} );
  0            
346             }
347             }
348              
349              
350             # Sends an event to all interested sessions. This is a separate sub
351             # because I do it so much, but it's not an actual POE event because it
352             # doesn't need to be one and I don't need the overhead.
353             sub _send_event {
354 0     0     my ($kernel, $heap, $event, @args) = @_;
355 0           my %sessions;
356              
357 0           foreach (values %{$heap->{events}->{'irc_hyb_all'}},
  0            
358 0           values %{$heap->{events}->{$event}}) {
359 0           $sessions{$_} = $_;
360             }
361 0           foreach (values %sessions) {
362 0           $kernel->post( $_, $event, @args );
363             }
364             }
365              
366             sub addnick {
367 0     0 1   my ($kernel, $heap, $session, $args) = @_[KERNEL, HEAP, SESSION, ARG0];
368 0           my $connecttime = time();
369              
370 0 0         if ($args) {
371 0           my %arg;
372 0 0         if (ref $args eq 'ARRAY') {
    0          
373 0           %arg = @$args;
374             } elsif (ref $args eq 'HASH') {
375 0           %arg = %$args;
376             } else {
377 0           die "First argument to addnick() should be a hash or array reference";
378             }
379              
380             # Gentlemen, lets get down to business
381             # Mandatory fields we must must must have these, damnit
382 0 0         my $nickname = $arg{'NickName'} if exists $arg{'NickName'};
383 0 0         my $username = $arg{'UserName'} if exists $arg{'UserName'};
384 0 0         my $hostname = $arg{'HostName'} if exists $arg{'HostName'};
385 0 0         my $umode = $arg{'Umode'} if exists $arg{'Umode'};
386 0 0         my $description = $arg{'Description'} if exists $arg{'Description'};
387              
388 0 0         unless (defined $nickname) {
389 0           die "You must specify at least a NickName to addnick";
390             }
391              
392             # Default everything else
393              
394 0           my $cmd = "NICK $nickname 1 $connecttime ";
395 0 0         $umode = "+o" unless (defined $umode);
396 0 0 0       $umode = "+" . $umode unless ($umode =~ /^\+/ or not defined($umode));
397 0 0         $cmd .= "$umode " if defined($umode);
398 0 0         $cmd .= "+ " if not defined($umode);
399 0 0         $cmd .= lc $nickname . " " unless (defined $username);
400 0 0         $cmd .= "$username " if (defined $username);
401 0 0         $cmd .= "$heap->{servername} " unless (defined $hostname);
402 0 0         $cmd .= "$hostname " if (defined $hostname);
403 0           $cmd .= "$heap->{servername} ";
404 0 0         $cmd .= ":$heap->{serverdesc}" unless (defined $description);
405 0 0         $cmd .= ":$description" if defined($description);
406              
407 0           $kernel->yield ( 'sl_client', $cmd ); # Kludge tbh :)
408              
409             } else {
410 0           die "First argument to addnick() should be a hash or array reference";
411             }
412              
413             }
414              
415             # Generate an automatic pong in response to IRC Server's ping
416              
417             sub irc_hyb_ping {
418 0     0 1   my ($heap, $arg) = @_[HEAP, ARG0];
419              
420 0           $heap->{socket}->put("PONG :$heap->{servername}\n");
421             }
422              
423             sub irc_hyb_server_link {
424 0     0 1   my ($kernel,$heap,$server) = @_[KERNEL,HEAP,ARG0];
425              
426 0           $heap->{Bursting} = 1;
427 0           $heap->{State}->{serverlink} = $server;
428 0           $heap->{serverlink} = $server;
429 0           $heap->{State}->_server_add($server,1,$heap->{servername});
430             }
431              
432             sub irc_hyb_eob {
433 0     0 0   my ($kernel,$heap,$who) = @_[KERNEL,HEAP,ARG0];
434              
435             SWITCH: {
436 0 0         if ( $who eq $heap->{serverlink} ) {
  0            
437 0           foreach ( $heap->{State}->_burst_info() ) {
438 0           $kernel->yield( 'sl_server', $_ );
439             }
440 0           $kernel->yield( 'sl_server', "EOB" );
441 0           $heap->{State}->_burst_destroy();
442 0           last SWITCH;
443             }
444 0 0         if ( $who eq $heap->{servername} ) {
445 0           $heap->{Bursting} = 0;
446 0           last SWITCH;
447             }
448             }
449             }
450              
451             sub irc_hyb_server {
452 0     0 0   my ($kernel,$heap,$link,$server,$hops) = @_[KERNEL,HEAP,ARG0,ARG1,ARG2];
453              
454 0           $heap->{State}->_server_add($server,$hops,$link);
455             }
456              
457             sub irc_hyb_squit {
458 0     0 1   my ($heap,$squit) = @_[HEAP,ARG0];
459              
460 0           $heap->{State}->_server_del($squit);
461             }
462              
463             sub irc_hyb_version {
464 0     0 0   my ($kernel, $heap, $who) = @_[KERNEL,HEAP,ARG0];
465              
466 0           $kernel->yield( 'sl_server', "351 $who $heap->{version}. $heap->{servername} :" );
467             }
468              
469             sub irc_hyb_sjoin {
470 0     0 1   my ($kernel,$heap,$who,$what) = @_[KERNEL,HEAP,ARG0,ARG1];
471              
472 0           $heap->{State}->_channel_burst( $what );
473             }
474              
475             sub irc_p10_quit {
476 0     0 0   my ($heap, $who) = @_[HEAP,ARG0];
477              
478 0           $heap->{State}->_nick_del($who);
479             }
480              
481              
482             # Our event handlers for events sent to us
483              
484             # The handler for commands which have N arguments, separated by commas.
485             sub commasep {
486 0     0 0   my ($kernel, $state) = @_[KERNEL, STATE];
487 0           my $args = join ',', @_[ARG0 .. $#_];
488              
489 0           $state = uc( $state );
490 0 0         $state .= " $args" if defined $args;
491 0           $kernel->yield( 'sl_server', $state );
492             }
493              
494             # The handler for commands which have N arguments, separated by commas. Client hacked.
495             sub commasep_client {
496 0     0 0   my ($kernel, $state, $numeric) = @_[KERNEL, STATE, ARG0];
497 0           my $args = join ',', @_[ARG1 .. $#_];
498              
499 0           $state = uc( $state );
500 0 0         $state .= " $args" if defined $args;
501 0           $kernel->yield( 'sl_client', ":$numeric $state" );
502             }
503              
504             # Send a CTCP query or reply, with the same syntax as a PRIVMSG event.
505             sub ctcp {
506 0     0 1   my ($kernel, $state, $heap, $numeric, $to) = @_[KERNEL, STATE, HEAP, ARG0, ARG1];
507 0           my $message = join ' ', @_[ARG2 .. $#_];
508              
509 0 0 0       unless (defined $numeric and defined $to and defined $message) {
      0        
510 0           die "The POE::Component::IRC event \"$state\" requires three arguments";
511             }
512              
513             # CTCP-quote the message text.
514 0           ($message) = @{$heap->{ctcp_filter}->put([ $message ])};
  0            
515              
516             # Should we send this as a CTCP request or reply?
517 0 0         $state = $state eq 'ctcpreply' ? 'notice' : 'privmsg';
518              
519 0           $kernel->yield( $state, $numeric, $to, $message );
520             }
521              
522             # Tell the IRC server to forcibly remove a user from a channel.
523             sub kick {
524 0     0 0   my ($kernel, $numeric, $chan, $nick) = @_[KERNEL, ARG0, ARG1, ARG2];
525 0           my $message = join '', @_[ARG3 .. $#_];
526              
527 0 0 0       unless (defined $numeric and defined $chan and defined $nick) {
      0        
528 0           die "The POE::Component::IRC event \"kick\" requires at least three arguments";
529             }
530              
531 0 0         $nick .= " :$message" if defined $message;
532 0           $kernel->yield('sl_client', ":$numeric KICK $chan $nick" );
533             }
534              
535              
536             # The handler for all IRC commands that take no arguments.
537             sub noargs {
538 0     0 0   my ($kernel, $state, $arg) = @_[KERNEL, STATE, ARG0];
539              
540 0 0         if (defined $arg) {
541 0           die "The POE::Component::IRC event \"$state\" takes no arguments";
542             }
543 0           $kernel->yield( 'sl_server', uc( $state ) );
544             }
545              
546             # The handler for all IRC commands that take no arguments. Client hacked.
547             sub noargs_client {
548 0     0 0   my ($kernel, $state, $numeric, $arg) = @_[KERNEL, STATE, ARG0, ARG1];
549              
550 0 0         unless (defined $numeric) {
551 0           die "The POE::Component::IRC event \"$state\" requires at least one argument";
552             }
553              
554 0 0         if (defined $arg) {
555 0           die "The POE::Component::IRC event \"$state\" takes no arguments";
556             }
557 0           $kernel->yield( 'sl_client', ":$numeric " . uc( $state ) );
558             }
559              
560             # The handler for commands that take one required and two optional arguments.
561             sub oneandtwoopt {
562 0     0 0   my ($kernel, $state) = @_[KERNEL, STATE];
563 0           my $arg = join '', @_[ARG0 .. $#_];
564              
565 0           $state = uc( $state );
566 0 0         if (defined $arg) {
567 0 0         $arg = ':' . $arg if $arg =~ /\s/;
568 0           $state .= " $arg";
569             }
570 0           $kernel->yield( 'sl_server', $state );
571             }
572              
573             # The handler for commands that take one required and two optional arguments. Client hacked.
574             sub oneandtwoopt_client {
575 0     0 0   my ($kernel, $state, $numeric) = @_[KERNEL, STATE, ARG0];
576 0           my $arg = join '', @_[ARG1 .. $#_];
577              
578 0 0         unless (defined $numeric) {
579 0           die "The POE::Component::IRC event \"$state\" requires at least one argument";
580             }
581              
582 0           $state = uc( $state );
583 0 0         if (defined $arg) {
584 0 0         $arg = ':' . $arg if $arg =~ /\s/;
585 0           $state .= " $arg";
586             }
587 0           $kernel->yield( 'sl_client', ":$numeric $state" );
588             }
589              
590             # The handler for commands that take at least one optional argument.
591             sub oneoptarg {
592 0     0 0   my ($kernel, $state) = @_[KERNEL, STATE];
593 0 0         my $arg = join '', @_[ARG0 .. $#_] if defined $_[ARG0];
594              
595 0           $state = uc( $state );
596 0 0         if (defined $arg) {
597 0 0         $arg = ':' . $arg if $arg =~ /\s/;
598 0           $state .= " $arg";
599             }
600 0           $kernel->yield( 'sl_server', $state );
601             }
602              
603             # The handler for commands that take at least one optional argument. Client hacked.
604             sub oneoptarg_client {
605 0     0 0   my ($kernel, $state, $numeric) = @_[KERNEL, STATE, ARG0];
606 0 0         my $arg = join '', @_[ARG1 .. $#_] if defined $_[ARG1];
607              
608 0 0         unless (defined $numeric) {
609 0           die "The POE::Component::IRC event \"$state\" requires at least one argument";
610             }
611              
612 0           $state = uc( $state );
613 0 0         if (defined $arg) {
614 0 0         $arg = ':' . $arg if $arg =~ /\s/;
615 0           $state .= " $arg";
616             }
617 0           $kernel->yield( 'sl_client', ":$numeric $state" );
618             }
619              
620             # The handler for commands which take one required and one optional argument.
621             sub oneortwo {
622 0     0 0   my ($kernel, $state, $one) = @_[KERNEL, STATE, ARG0];
623 0           my $two = join '', @_[ARG1 .. $#_];
624              
625 0 0         unless (defined $one) {
626 0           die "The POE::Component::IRC event \"$state\" requires at least one argument";
627             }
628              
629 0           $state = uc( $state ) . " $one";
630 0 0         $state .= " $two" if defined $two;
631 0           $kernel->yield( 'sl_server', $state );
632             }
633              
634             # The handler for commands which take one required and one optional argument. Client hacked.
635             sub oneortwo_client {
636 0     0 0   my ($kernel, $state, $numeric, $one) = @_[KERNEL, STATE, ARG0, ARG1];
637 0           my $two = join '', @_[ARG2 .. $#_];
638              
639 0 0 0       unless (defined $numeric and defined $one) {
640 0           die "The POE::Component::IRC event \"$state\" requires at least two argument";
641             }
642 0           $state = uc( $state ) . " $one";
643 0 0         $state .= " $two" if defined $two;
644 0           $kernel->yield( 'sl_client', ":$numeric $state" );
645             }
646              
647             # Handler for commands that take exactly one argument.
648             sub onlyonearg {
649 0     0 0   my ($kernel, $state) = @_[KERNEL, STATE];
650 0           my $arg = join '', @_[ARG0 .. $#_];
651              
652 0 0         unless (defined $arg) {
653 0           die "The POE::Component::IRC event \"$state\" requires one argument";
654             }
655              
656 0           $state = uc( $state );
657 0 0         $arg = ':' . $arg if $arg =~ /\s/;
658 0           $state .= " $arg";
659 0           $kernel->yield( 'sl_server', $state );
660             }
661              
662             # Handler for commands that take exactly one argument. Client hacked.
663             sub onlyonearg_client {
664 0     0 0   my ($kernel, $state, $numeric) = @_[KERNEL, STATE, ARG0];
665 0           my $arg = join '', @_[ARG1 .. $#_];
666              
667 0 0 0       unless (defined $numeric and defined $arg) {
668 0           die "The POE::Component::IRC::Service::P10 event \"$state\" requires two argument";
669             }
670              
671 0           $state = uc( $state );
672 0 0         $arg = ':' . $arg if $arg =~ /\s/;
673 0           $state .= " $arg";
674 0           $kernel->yield( 'sl_client', ":$numeric $state" );
675             }
676              
677             # Handler for commands that take exactly two arguments.
678             sub onlytwoargs {
679 0     0 0   my ($heap, $kernel, $state, $one) = @_[HEAP, KERNEL, STATE, ARG0];
680 0           my ($two) = join '', @_[ARG1 .. $#_];
681              
682 0 0 0       unless (defined $one and defined $two) {
683 0           die "The POE::Component::IRC::Service::P10 event \"$state\" requires two arguments";
684             }
685              
686 0           $state = uc( $state );
687 0 0         $two = ':' . $two if $two =~ /\s/;
688 0           $kernel->yield( 'sl_server', "$state $two" );
689             }
690              
691             # Handler for commands that take exactly two arguments. Client hacked.
692             sub onlytwoargs_client {
693 0     0 0   my ($heap, $kernel, $state, $numeric, $one) = @_[HEAP, KERNEL, STATE, ARG0, ARG1];
694 0           my ($two) = join '', @_[ARG2 .. $#_];
695              
696 0 0 0       unless (defined $numeric and defined $one and defined $two) {
      0        
697 0           die "The POE::Component::IRC::Service::P10 event \"$state\" requires three arguments";
698             }
699              
700 0           $state = uc( $state );
701 0 0         $two = ':' . $two if $two =~ /\s/;
702 0           $kernel->yield( 'sl_client', ":$numeric $state $two" );
703             }
704              
705             # Handler for privmsg or notice events.
706             sub privandnotice {
707 0     0 0   my ($kernel, $state, $numeric, $to) = @_[KERNEL, STATE, ARG0, ARG1];
708 0           my $message = join ' ', @_[ARG2 .. $#_];
709              
710 0 0 0       unless (defined $numeric and defined $to and defined $message) {
      0        
711 0           die "The POE::Component::IRC event \"$state\" requires three arguments";
712             }
713              
714 0 0         if (ref $to eq 'ARRAY') {
715 0           $to = join ',', @$to;
716             }
717              
718 0           $state = uc( $state );
719 0           $state .= " $to :$message";
720 0           $kernel->yield( 'sl_client', ":$numeric $state" );
721             }
722              
723             # Tell the IRC session to go away.
724             sub shutdown {
725 0     0 0   my ($kernel, $heap) = @_[KERNEL, HEAP];
726              
727 0           foreach ($kernel->alias_list( $_[SESSION] )) {
728 0           $kernel->alias_remove( $_ );
729             }
730              
731 0           foreach (qw(socket sock socketfactory dcc wheelmap)) {
732 0           delete $heap->{$_};
733             }
734             }
735              
736             # The handler for commands which have N arguments, separated by spaces.
737             sub spacesep {
738 0     0 0   my ($kernel, $state) = @_[KERNEL, STATE];
739 0           my $args = join ' ', @_[ARG0 .. $#_];
740              
741 0           $state = uc( $state );
742 0 0         $state .= " $args" if defined $args;
743 0           $kernel->yield( 'sl_server', $state );
744             }
745              
746             # The handler for commands which have N arguments, separated by spaces. Client hacked.
747             sub spacesep_client {
748 0     0 0   my ($kernel, $state, $numeric) = @_[KERNEL, STATE, ARG0];
749 0           my $args = join ' ', @_[ARG1 .. $#_];
750              
751 0           $state = uc( $state );
752 0 0         $state .= " $args" if defined $args;
753 0           $kernel->yield( 'sl_server', "$numeric $state" );
754             }
755              
756             # Dish out server initiated commands
757              
758             sub sl_server {
759 0     0 1   my ($kernel, $heap, $cmd) = @_[KERNEL, HEAP, ARG0];
760              
761 0           $heap->{socket}->put(":$heap->{servername} $cmd\n");
762 0           $kernel->yield('_parseline',":$heap->{servername} $cmd");
763             }
764              
765             # Dish out client (whichever is specified) initiated commands
766              
767             sub sl_client {
768 0     0 1   my ($kernel, $heap, $cmd) = @_[KERNEL, HEAP, ARG0];
769              
770 0           $heap->{socket}->put("$cmd\n");
771 0           $kernel->yield('_parseline',$cmd);
772             }
773              
774             # Set or query the current topic on a channel.
775             sub topic {
776 0     0 0   my ($kernel,$heap, $numeric, $chan) = @_[KERNEL,HEAP, ARG0, ARG1];
777 0           my $topic = join '', @_[ARG2 .. $#_];
778              
779 0 0         $chan .= " :$topic" if length $topic;
780 0           $kernel->yield('sl_client',":$numeric TOPIC $chan");
781             }
782              
783             sub sjoin {
784 0     0 0   my ($kernel,$state,$heap,$nick,$channel) = @_[KERNEL,STATE,HEAP,ARG0,ARG1];
785 0           my ($ts) = time();
786              
787 0 0 0       unless ( defined($nick) and defined($channel) ) {
788 0           die "The POE::Component::IRC event \"$state\" requires at least two argument";
789             }
790             # Under TSora joins are actually implemented as server initiated events *sigh*
791 0           $kernel->yield('sl_server',"SJOIN $ts $channel + :$nick");
792             }
793              
794              
795             # Our own little function to return a proper uppercase nickname or channel name IRC stylee
796             # See the RFC for the details
797              
798             sub u_irc {
799 0   0 0 0   my ($value) = shift || return undef;
800              
801 0           $value =~ tr/a-z{}|/A-Z[]\\/;
802 0           return $value;
803             }
804              
805              
806             # Return a correctly formatted string for STATS u requests
807              
808             sub timestring {
809 0   0 0 0   my ($timeval) = shift || return 0;
810 0           my $uptime = time() - $timeval;
811            
812 0           my $days = int $uptime / 86400;
813 0           my $remain = $uptime % 86400;
814 0           my $hours = int $remain / 3600;
815 0           $remain %= 3600;
816 0           my $mins = int $remain / 60;
817 0           $remain %= 60;
818 0           return sprintf("Server Up %d days, %2.2d:%2.2d:%2.2d",$days,$hours,$mins,$remain);
819             }
820              
821             sub retOpflags {
822 0   0 0 0   my ($opflags) = shift || return undef;
823 0           my (@opflags) = ();
824 0           my ($action) = "";
825              
826 0           for (my $i = 0; $i < length($opflags); $i++) {
827 0           my $char = substr($opflags,$i,1);
828 0 0 0       if ($char eq "+" or $char eq "-") {
829 0           $action = $char;
830             } else {
831 0           push (@opflags,"$action$char");
832             }
833             }
834 0           return @opflags;
835             }
836              
837             # Object Methods
838             # Private methods begin with _
839              
840             sub _server_add {
841 0     0     my ($self) = shift;
842            
843 0           my ($server) = { Name => $_[0],
844             Hops => $_[1],
845             Link => $_[2]
846             };
847              
848 0           $self->{servers_name}->{ $server->{Name} } = $server;
849 0           return 1;
850             }
851              
852             sub _server_del {
853 0     0     my ($self) = shift;
854 0   0       my ($server) = shift || return 0;
855              
856 0           $self->{servers_name}->{$server}->{ToDelete} = 1;
857 0           foreach ( keys %{ $self->{servers_name} } ) {
  0            
858 0 0 0       if ( $server eq $self->{servers_name}->{$_}->{Link} and not defined ( $self->{servers_name}->{$server}->{ToDelete} ) ) {
859 0           $self->_server_del($self->{servers_name}->{$_}->{Link});
860             }
861             }
862 0           foreach ( keys %{ $self->{byserver}->{$server} } ) {
  0            
863 0           $self->_nick_del($_);
864             }
865 0           delete ( $self->{servers_name}->{$server} );
866 0           return 1;
867             }
868              
869             sub _nick_add {
870 0     0     my ($self) = shift;
871 0   0       my ($nickname) = $_[0] || return 0;
872 0   0       my ($server) = $_[1] || return 0;
873 0   0       my ($username) = $_[2] || return 0;
874 0   0       my ($hostname) = $_[3] || return 0;
875 0   0       my ($timestamp) = $_[4] || time();
876 0   0       my ($umode) = $_[5] || undef;
877 0   0       my ($ircname) = $_[6] || undef;
878              
879             # Does the nickname already exist in our state, ie. one of our clients
880             # If so kludge the timestamp on ours so it is older and they will get KILLed mwuahahahaha :o)
881 0 0         if ( defined ( $self->{bynickname}->{ u_irc ($nickname) } ) ) {
882 0           my ($kludge) = $timestamp - 30;
883 0           $self->{bynickname}->{ u_irc ( $nickname ) }->{TimeStamp} = $kludge;
884 0 0         if ( defined ( $self->{burst_nicks}->{ u_irc( $nickname ) } ) ) {
885 0           $self->{burst_nicks}->{ u_irc( $nickname ) }->{TimeStamp} = $kludge;
886             }
887             }
888              
889 0 0         if ( not defined ( $self->{bynickname}->{ u_irc( $nickname ) } ) ) {
890 0           my ($record) = { NickName => $nickname,
891             UserName => $username,
892             HostName => $hostname,
893             IRCName => $ircname,
894             TimeStamp => $timestamp,
895             Server => $server,
896             UMode => $umode, };
897 0           $self->{bynickname}->{ u_irc ( $record->{NickName} ) } = $record;
898 0           $self->{byserver}->{ $server }->{ u_irc ( $record->{NickName} ) } = $record;
899             }
900            
901 0           return 1;
902             }
903              
904             sub _nick_del {
905 0     0     my ($self) = shift;
906 0   0       my ($nickname) = u_irc ( $_[0] ) || return 0;
907              
908 0           foreach ( keys %{ $self->{bynickname}->{$nickname}->{Channels} } ) {
  0            
909 0           delete ( $self->{channels}->{$_}->{Members}->{$nickname} );
910 0 0         if ( scalar ( keys % { $self->{channels}->{$_}->{Members} } ) == 0 ) {
  0            
911 0           delete ( $self->{channels}->{$_} );
912             }
913             }
914 0           my ($server) = $self->{bynickname}->{$nickname}->{Server};
915 0           delete ( $self->{bynickname}->{$nickname} );
916 0           delete ( $self->{byserver}->{$server}->{$nickname} );
917 0           return 1;
918             }
919              
920             sub _nick_change {
921 0     0     my ($self) = shift;
922 0   0       my ($nickname) = u_irc ( $_[0] ) || return 0;
923 0   0       my ($newnick) = $_[1] || return 0;
924              
925 0           my ($record) = $self->{bynickname}->{$nickname};
926 0           $record->{NickName} = $newnick;
927 0           $record->{TimeStamp} = time();
928 0           delete $self->{bynickname}->{$nickname};
929 0           $self->{bynickname}->{ u_irc( $record->{NickName} ) } = $record;
930 0           return 1;
931             }
932              
933             sub _nick_umode {
934 0     0     my ($self) = shift;
935 0   0       my ($nickname) = u_irc ( $_[0] ) || return 0;
936 0   0       my ($umode) = $_[1] || return 0;
937              
938 0           my ($currentumode) = $self->{bynickname}->{$nickname}->{UMode};
939 0           foreach (retOpflags($umode)) {
940             SWITCH: {
941 0 0         if (/^\+(.+)/) {
  0            
942 0 0         if ( not defined ($currentumode) ) {
943 0           $currentumode = $1;
944             } else {
945 0           $currentumode .= $1;
946 0           $currentumode = join("",sort(split(//,$currentumode)));
947             }
948 0           last SWITCH;
949             }
950 0 0         if (/^-(.+)/) {
951 0 0         if ( defined ($currentumode) ) {
952 0           $currentumode =~ s/$1//g;
953             }
954 0           last SWITCH;
955             }
956             }
957             }
958 0 0 0       if ( defined ($currentumode) and $currentumode ) {
959 0           $self->{bynickname}->{$nickname}->{UMode} = $currentumode;
960             } else {
961 0           delete ( $self->{bynickname}->{$nickname}->{UMode} );
962             }
963 0           return 1;
964             }
965              
966             sub _channel_join {
967 0     0     my ($self) = shift;
968 0   0       my ($channel) = $_[0] || return 0;
969 0   0       my ($nickname) = u_irc ( $_[1] ) || return 0;
970 0           my ($timestamp) = $_[2];
971 0           my ($usermode) = 0;
972 0           my ($channelname) = $channel;
973 0           $channel = u_irc ( $channel );
974            
975 0 0         if (not exists $self->{channels}->{$channel}) {
976 0           $self->{channels}->{$channel}->{Channel} = $channelname;
977 0           $self->{channels}->{$channel}->{TimeStamp} = $timestamp;
978 0           $usermode = 2;
979             }
980 0           $self->{channels}->{$channel}->{Members}->{$nickname} = $usermode;
981 0           $self->{bynickname}->{$nickname}->{Channels}->{$channel} = $usermode;
982 0           return 1;
983             }
984              
985             sub _channel_part {
986 0     0     my ($self) = shift;
987 0   0       my ($channel) = u_irc ( $_[0] ) || return 0;
988 0   0       my ($nickname) = u_irc ( $_[1] ) || return 0;
989              
990 0           delete ( $self->{channels}->{$channel}->{Members}->{$nickname} );
991 0 0         if ( scalar ( keys % { $self->{channels}->{$_}->{Members} } ) == 0 ) {
  0            
992 0           delete ( $self->{channels}->{$_} );
993             }
994 0           delete ( $self->{bynickname}->{$nickname}->{Channels}->{$channel} );
995 0           return 1;
996             }
997              
998             sub _channel_topic {
999 0     0     my ($self) = shift;
1000 0   0       my ($channel) = u_irc( $_[0] ) || return 0;
1001 0   0       my ($topic) = $_[1] || return 0;
1002 0   0       my ($set_by) = $_[2] || return 0;
1003 0   0       my ($timestamp) = $_[3] || return 0;
1004              
1005 0           $self->{channels}->{$channel}->{Topic} = $topic;
1006 0           $self->{channels}->{$channel}->{Set_By} = $set_by;
1007 0           $self->{channels}->{$channel}->{TopicTS} = $timestamp;
1008 0           return 1;
1009             }
1010              
1011             sub _channel_untopic {
1012 0     0     my ($self) = shift;
1013 0   0       my ($channel) = u_irc( $_[0] ) || return 0;
1014              
1015 0           delete ( $self->{channels}->{$channel}->{Topic} );
1016 0           delete ( $self->{channels}->{$channel}->{Set_By} );
1017 0           delete ( $self->{channels}->{$channel}->{TopicTS} );
1018 0           return 1;
1019             }
1020              
1021             sub _channel_mode {
1022 0     0     my ($self) = shift;
1023 0   0       my ($channel) = u_irc( $_[0] ) || return 0;
1024 0   0       my ($string) = $_[1] || return 0;
1025 0   0       my ($who) = $_[2] || return 0; # This is either a server or client name only used for bans tbh
1026              
1027 0           my ($modes,@args) = split(/ /,$string);
1028 0           my (@modes) = retOpflags($modes);
1029 0           my ($currentmode) = $self->{channels}->{$channel}->{Mode};
1030 0           foreach (@modes) {
1031 0           my $argument;
1032 0 0         $argument = shift(@args) if (/\+[bkloveIh]/);
1033 0 0         $argument = shift(@args) if (/-[boveIh]/);
1034             SWITCH: {
1035 0 0         if (/[eI]/) {
  0            
1036 0           last SWITCH;
1037             }
1038 0 0         if (/b/) {
1039 0           $self->_channel_ban($channel,$_,$argument,$who);
1040 0           last SWITCH;
1041             }
1042 0 0         if (/l/) {
1043 0 0         if (/^\+(.+)/) {
1044 0           $self->{channels}->{$channel}->{ChanLimit} = $argument;
1045 0           $currentmode .= $1;
1046             } else {
1047 0           delete ( $self->{channels}->{$channel}->{ChanLimit} );
1048 0           $currentmode =~ s/$1//g;
1049             }
1050 0           last SWITCH;
1051             }
1052 0 0         if (/k/) {
1053 0 0         if (/^\+(.+)/) {
1054 0           $self->{channels}->{$channel}->{ChanKey} = $argument;
1055 0           $currentmode .= $1;
1056             } else {
1057 0           delete ( $self->{channels}->{$channel}->{ChanKey} );
1058 0           $currentmode =~ s/$1//g;
1059             }
1060 0           last SWITCH;
1061             }
1062 0 0         if (/[ov]/) {
1063 0           my ($value) = 0;
1064 0 0         if (/\+o/) { $value = 2; }
  0            
1065 0 0         if (/-o/) { $value = -2; }
  0            
1066 0 0         if (/\+v/) { $value = 1; }
  0            
1067 0 0         if (/-v/) { $value = -1; }
  0            
1068 0           $self->{channels}->{$channel}->{Members}->{$argument} += $value;
1069 0           $self->{bynickname}->{ u_irc ( $argument ) }->{Channels}->{$channel} += $value;
1070 0           last SWITCH;
1071             }
1072 0 0         if (/[h]/) {
1073 0 0         if (/\+h/) {
1074 0           $self->{channels}->{$channel}->{Members}->{$argument} = -1;
1075 0           $self->{bynickname}->{ u_irc ( $argument ) }->{Channels}->{$channel} = -1;
1076             } else {
1077 0           $self->{channels}->{$channel}->{Members}->{$argument} = 0;
1078 0           $self->{bynickname}->{ u_irc ( $argument ) }->{Channels}->{$channel} = 0;
1079             }
1080 0           last SWITCH;
1081             }
1082 0 0         if (/^\+(.+)/) {
1083 0           $currentmode .= $1;
1084 0           last SWITCH;
1085             }
1086 0 0         if (/^-(.+)/) {
1087 0           $currentmode =~ s/$1//g;
1088 0           last SWITCH;
1089             }
1090             }
1091             }
1092 0           $self->{channels}->{$channel}->{Mode} = join("",sort(split(//,$currentmode)));
1093 0           return 1;
1094             }
1095              
1096             sub _channel_ban {
1097 0     0     my ($self) = shift;
1098 0   0       my ($channel) = u_irc( $_[0] ) || return 0;
1099 0   0       my ($operation) = $_[1] || return 0;
1100 0   0       my ($banmask) = $_[2] || return 0;
1101 0   0       my ($who) = $_[3] || return 0;
1102            
1103 0 0         if ($operation eq "+b") {
1104 0           $self->{channels}->{$channel}->{Bans}->{$banmask}->{Time} = time();
1105 0           $self->{channels}->{$channel}->{Bans}->{$banmask}->{Who} = $who;
1106             } else {
1107 0           delete ( $self->{channels}->{$channel}->{Bans}->{$banmask} );
1108             }
1109 0           return 1;
1110             }
1111              
1112             sub _channel_burst {
1113 0     0     my ($self) = shift;
1114 0   0       my ($args) = shift || return 0;
1115              
1116 0           my ($first,$second) = split(/ :/,$args);
1117 0           my (@args) = split(/ /,$first); my (@nicknames) = split(/ /,$second);
  0            
1118 0           my ($timestamp,$channelname) = @args[0..1];
1119 0           my ($channel) = u_irc ( $channelname );
1120 0 0 0       if ( exists $self->{channels}->{$channel} and $timestamp < $self->{channels}->{$channel}->{TimeStamp} ) {
1121 0           $self->{channels}->{$channel}->{TimeStamp} = $timestamp;
1122 0           $self->{burst_channels}->{$channel}->{TimeStamp} = $timestamp;
1123             } else {
1124 0           $self->{channels}->{$channel}->{Channel} = $channelname;
1125 0           $self->{channels}->{$channel}->{TimeStamp} = $timestamp;
1126             }
1127 0 0         if ( $args[2] =~ /^\+(.+)$/ ) {
1128 0           $self->{channels}->{$channel}->{Mode} = $1;
1129 0           my ($l) = index ( $1, "l" );
1130 0           my ($k) = index ( $1, "k" );
1131             SWITCH: {
1132 0 0 0       if ( $l > $k and $k != -1 ) {
  0            
1133 0           $self->{channels}->{$channel}->{ChanLimit} = $args[4];
1134 0           $self->{channels}->{$channel}->{ChanKey} = $args[3];
1135 0           last SWITCH;
1136             }
1137 0 0 0       if ( $l > $k and $k == -1 ) {
1138 0           $self->{channels}->{$channel}->{ChanLimit} = $args[3];
1139 0           last SWITCH;
1140             }
1141 0 0 0       if ( $k > $l and $l != -1 ) {
1142 0           $self->{channels}->{$channel}->{ChanLimit} = $args[3];
1143 0           $self->{channels}->{$channel}->{ChanKey} = $args[4];
1144 0           last SWITCH;
1145             }
1146 0 0 0       if ( $k > $l and $l == -1 ) {
1147 0           $self->{channels}->{$channel}->{ChanKey} = $args[3];
1148 0           last SWITCH;
1149             }
1150             }
1151             }
1152 0           foreach ( @nicknames ) {
1153 0           my ($value) = 0; my ($nickname);
  0            
1154 0 0         if ( /^(\@|\+|%)+(.*)/ ) {
1155 0 0         if ( $1 =~ /\@/ ) {
1156 0           $value += 2;
1157             }
1158 0 0         if ( $1 =~ /\+/ ) {
1159 0           $value += 1;
1160             }
1161 0 0         if ( $1 =~ /%/ ) {
1162 0           $value = -1;
1163             }
1164 0           $nickname = $2;
1165             } else {
1166 0           $nickname = $_;
1167             }
1168 0           $self->{channels}->{$channel}->{Members}->{ u_irc ( $nickname ) } = $value;
1169 0           $self->{bynickname}->{ u_irc ( $nickname ) }->{Channels}->{$channel} = $value;
1170             }
1171             }
1172              
1173             sub _burst_create {
1174 0     0     my ($self) = shift;
1175              
1176 0           foreach ( keys %{ $self->{bynickname} } ) {
  0            
1177 0           $self->{burst_nicks}->{$_}->{NickName} = $self->{bynickname}->{$_}->{NickName};
1178 0           $self->{burst_nicks}->{$_}->{UserName} = $self->{bynickname}->{$_}->{UserName};
1179 0           $self->{burst_nicks}->{$_}->{HostName} = $self->{bynickname}->{$_}->{HostName};
1180 0           $self->{burst_nicks}->{$_}->{IRCName} = $self->{bynickname}->{$_}->{IRCName};
1181 0           $self->{burst_nicks}->{$_}->{TimeStamp} = $self->{bynickname}->{$_}->{TimeStamp};
1182 0           $self->{burst_nicks}->{$_}->{Server} = $self->{bynickname}->{$_}->{Server};
1183 0           $self->{burst_nicks}->{$_}->{UMode} = $self->{bynickname}->{$_}->{UMode};
1184             }
1185 0           foreach ( keys %{ $self->{channels} } ) {
  0            
1186 0           $self->{burst_channels}->{$_}->{Channel} = $self->{channels}->{$_}->{Channel};
1187 0           $self->{burst_channels}->{$_}->{TimeStamp} = $self->{channels}->{$_}->{TimeStamp};
1188 0           $self->{burst_channels}->{$_}->{Mode} = $self->{channels}->{$_}->{Mode};
1189 0 0         $self->{burst_channels}->{$_}->{ChanKey} = $self->{channels}->{$_}->{ChanKey} if ( defined ( $self->{channels}->{$_}->{ChanKey} ) );
1190 0 0         $self->{burst_channels}->{$_}->{ChanLimit} = $self->{channels}->{$_}->{ChanLimit} if ( defined ( $self->{channels}->{$_}->{ChanLimit} ) );
1191 0           foreach my $ban ( keys %{ $self->{channels}->{$_}->{Bans} } ) {
  0            
1192 0           push( @{ $self->{burst_channels}->{$_}->{Bans} }, $ban );
  0            
1193             }
1194 0           foreach my $user ( keys %{ $self->{channels}->{$_}->{Members} } ) {
  0            
1195 0           $self->{burst_channels}->{$_}->{Members}->{$user} = $self->{channels}->{$_}->{Members}->{$user};
1196             }
1197             }
1198 0           return 1;
1199             }
1200              
1201             sub _burst_info {
1202 0     0     my ($self) = shift;
1203 0           my (@burst);
1204 0           my (@modes) = ( '', '+', '@', '@+' );
1205              
1206             # Nicknames first
1207 0           foreach ( keys %{ $self->{burst_nicks} } ) {
  0            
1208 0           my ($burstline) = "NICK " . $self->{burst_nicks}->{$_}->{NickName} . " ";
1209 0           $burstline .= "1 " . $self->{burst_nicks}->{$_}->{TimeStamp} . " ";
1210 0           $burstline .= $self->{burst_nicks}->{$_}->{UserName} . " " . $self->{burst_nicks}->{$_}->{HostName} . " " . $self->{burst_nicks}->{$_}->{Server} . " :";
1211 0 0         $burstline .= $self->{burst_nicks}->{$_}->{IRCName} if ( defined ( $self->{burst_nicks}->{$_}->{IRCName} ) );
1212 0           push (@burst, $burstline);
1213             }
1214 0           foreach ( keys %{ $self->{burst_channels} } ) {
  0            
1215 0           my ($burstline) = "SJOIN " . $self->{burst_channels}->{$_}->{TimeStamp} . " " . $self->{burst_channels}->{$_}->{Channel} . " +";
1216 0 0         $burstline .= $self->{burst_channels}->{$_}->{Mode} if ( defined ( $self->{burst_channels}->{$_}->{Mode} ) );
1217 0 0         $burstline .= " " . $self->{burst_channels}->{$_}->{ChanKey} if ( defined ( $self->{burst_channels}->{$_}->{ChanKey} ) );
1218 0 0         $burstline .= " " . $self->{burst_channels}->{$_}->{ChanLimit} if ( defined ( $self->{burst_channels}->{$_}->{ChanLimit} ) );
1219 0           $burstline .= " :"; my (@users);
  0            
1220 0           foreach my $i ( keys %{ $self->{burst_channels}->{$_}->{Members} } ) {
  0            
1221 0 0         if ( $self->{burst_channels}->{$_}->{Members}->{$i} == -1 ) {
1222 0           push ( @users, "%" . $self->{burst_nicks}->{$i}->{NickName} );
1223             } else {
1224 0           push ( @users, $modes[ $self->{burst_channels}->{$_}->{Members}->{$i} ] . $self->{burst_nicks}->{$i}->{NickName} );
1225             }
1226             }
1227 0           $burstline .= join(" ", @users);
1228 0           push (@burst, $burstline);
1229 0           my ($bans) = join(" ", @{ $self->{burst_channels}->{$_}->{Bans} });
  0            
1230 0 0         if ( defined ($bans) ) {
1231 0           $burstline = "MODE " . $self->{burst_channels}->{$_}->{Channel} . " +";
1232 0           for (my $i = 0; $i <= $#{ $self->{burst_channels}->{$_}->{Bans} }; $i++) {
  0            
1233 0           $burstline .= "b";
1234             }
1235 0           $burstline .= " $bans";
1236 0           push (@burst, $burstline);
1237             }
1238             }
1239 0           return @burst;
1240             }
1241              
1242             sub _burst_destroy {
1243 0     0     my ($self) = shift;
1244              
1245 0           delete ( $self->{burst_nicks} );
1246 0           delete ( $self->{burst_channels} );
1247             }
1248              
1249             # Public Methods
1250              
1251             1;
1252             __END__