]> git.donarmstrong.com Git - infobot.git/blob - src/UserExtra.pl
conninfo
[infobot.git] / src / UserExtra.pl
1 #
2 # UserExtra.pl: User Commands, Public.
3 #       Author: dms
4 #
5
6 use strict;
7 use vars qw($message $arg $qWord $verb $lobotomized $who $result $chan
8   $conn $msgType $query $talkchannel $ident $memusage);
9 use vars qw(%channels %chanstats %cmdstats %count %forked %ircstats %param
10   %cache %mask %userstats);
11
12 ### hooks get added in CommandHooks.pl.
13
14 ###
15 ### Start of commands for hooks.
16 ###
17
18 sub chaninfo {
19     my $chan = lc shift(@_);
20     my $mode;
21
22     if ( $chan eq '' ) {    # all channels.
23         my $i = keys %channels;
24         my $reply = "I'm on \002$i\002 " . &fixPlural( 'channel', $i );
25         my $tucount = 0;    # total user count.
26         my $uucount = 0;    # unique user count.
27         my %chans;
28         my @array;
29
30         ### line 1.
31         foreach ( keys %channels ) {
32             if ( /^\s*$/ or / / ) {
33                 &status('chanstats: fe channels: chan == NULL.');
34
35                 #&ircCheck();
36                 next;
37             }
38             next if (/^_default$/);
39
40             $chans{$_} = scalar( keys %{ $channels{$_}{''} } );
41         }
42         foreach $chan ( sort { $chans{$b} <=> $chans{$a} } keys %chans ) {
43             push( @array, "$chan/" . $chans{$chan} );
44         }
45         &performStrictReply( $reply . ': ' . join( ', ', @array ) );
46
47         ### total user count.
48         foreach $chan ( keys %channels ) {
49             $tucount += scalar( keys %{ $channels{$chan}{''} } );
50         }
51
52         ### unique user count.
53         my %nicks = ();
54         foreach $chan ( keys %channels ) {
55             my $nick;
56             foreach $nick ( keys %{ $channels{$chan}{''} } ) {
57                 $nicks{$nick}++;
58             }
59         }
60         $uucount = scalar( keys %nicks );
61
62         my $chans = scalar( keys %channels );
63         &performStrictReply( "i've cached \002$tucount\002 "
64               . &fixPlural( 'user', $tucount )
65               . ", \002$uucount\002 unique "
66               . &fixPlural( 'user', $uucount )
67               . ", distributed over \002$chans\002 "
68               . &fixPlural( 'channel', $chans )
69               . '.' );
70         &ircCheck();
71
72         return;
73     }
74
75     # channel specific.
76
77     if ( &validChan($chan) == 0 ) {
78         &msg( $who, "error: invalid channel \002$chan\002" );
79         return;
80     }
81
82     # Step 1:
83     my @array;
84     foreach ( sort keys %{ $chanstats{$chan} } ) {
85         my $int = $chanstats{$chan}{$_};
86         next unless ($int);
87
88         push( @array, "\002$int\002 " . &fixPlural( $_, $int ) );
89     }
90     my $reply =
91         "On \002$chan\002, there "
92       . &fixPlural( 'has', scalar(@array) )
93       . ' been '
94       . &IJoin(@array);
95
96     # Step 1b: check channel inconstencies.
97     $chanstats{$chan}{'Join'}    ||= 0;
98     $chanstats{$chan}{'SignOff'} ||= 0;
99     $chanstats{$chan}{'Part'}    ||= 0;
100
101     my $delta_stats = $chanstats{$chan}{'Join'} - $chanstats{$chan}{'SignOff'} -
102       $chanstats{$chan}{'Part'};
103
104     if ($delta_stats) {
105         my $total = scalar( keys %{ $channels{$chan}{''} } );
106         &status(
107             "chaninfo: join ~= signoff + part (drift of $delta_stats < $total)."
108         );
109
110         if ( $delta_stats > $total ) {
111             &ERROR('chaninfo: delta_stats exceeds total users.');
112         }
113     }
114
115     # Step 2:
116     undef @array;
117     my $type;
118     foreach ( 'v', 'o', '' ) {
119         my $int = scalar( keys %{ $channels{$chan}{$_} } );
120         next unless ($int);
121
122         $type = 'Voice' if ( $_ eq 'v' );
123         $type = 'Opped' if ( $_ eq 'o' );
124         $type = 'Total' if ( $_ eq '' );
125
126         push( @array, "\002$int\002 $type" );
127     }
128     $reply .= '.  At the moment, ' . &IJoin(@array);
129
130     # Step 3:
131     my %new;
132     foreach ( keys %userstats ) {
133         next unless ( exists $userstats{$_}{'Count'} );
134         if ( $userstats{$_}{'Count'} =~ /^\D+$/ ) {
135             &WARN("userstats{$_}{Count} is non-digit.");
136             next;
137         }
138
139         $new{$_} = $userstats{$_}{'Count'};
140     }
141
142     # TODO: show top 3 with percentages?
143     my ($count) = ( sort { $new{$b} <=> $new{$a} } keys %new )[0];
144     if ($count) {
145         $reply .=
146 ".  \002$count\002 has said the most with a total of \002$new{$count}\002 messages";
147     }
148     &performStrictReply("$reply.");
149 }
150
151 # Command statistics.
152 sub cmdstats {
153     my @array;
154
155     if ( !scalar( keys %cmdstats ) ) {
156         &performReply('no-one has run any commands yet');
157         return;
158     }
159
160     my %countstats;
161     foreach ( keys %cmdstats ) {
162         $countstats{ $cmdstats{$_} }{$_} = 1;
163     }
164
165     foreach ( sort { $b <=> $a } keys %countstats ) {
166         my $int = $_;
167         next unless ($int);
168
169         foreach ( keys %{ $countstats{$int} } ) {
170             push( @array, "\002$int\002 of $_" );
171         }
172     }
173     &performStrictReply( 'command usage include ' . &IJoin(@array) . '.' );
174 }
175
176 # Command statistics.
177 sub conninfo {
178     &performStrictReply( 'connection info ' . &IJoin(sort keys %::conns) );
179 }
180
181 # Factoid extension info. xk++
182 sub factinfo {
183     my $faqtoid = lc shift(@_);
184     my $query   = '';
185
186     if ( $faqtoid =~ /^\-(\S+)(\s+(.*))$/ ) {
187         &msg( $who,
188             'error: individual factoid info queries not supported as yet.' );
189         &msg( $who,
190             "it's possible that the factoid mistakenly begins with '-'." );
191         return;
192
193         $query   = lc $1;
194         $faqtoid = lc $3;
195     }
196
197     &CmdFactInfo( $faqtoid, $query );
198 }
199
200 sub factstats {
201     my $type = shift(@_);
202
203     &Forker(
204         'Factoids',
205         sub {
206             &performStrictReply( &CmdFactStats($type) );
207         }
208     );
209 }
210
211 sub karma {
212     my $target = lc( shift || $who );
213     my $karma =
214       &sqlSelect( 'stats', 'counter', { nick => $target, type => 'karma' } )
215       || 0;
216
217     if ( $karma != 0 ) {
218         &performStrictReply("$target has karma of $karma");
219     }
220     else {
221         &performStrictReply("$target has neutral karma");
222     }
223 }
224
225 sub tell {
226     my $args = shift;
227     my ( $target, $tell_obj ) = ( '', '' );
228     my $dont_tell_me = 0;
229     my $reply;
230
231     ### is this fixed elsewhere?
232     $args =~ s/\s+/ /g;         # fix up spaces.
233     $args =~ s/^\s+|\s+$//g;    # again.
234
235     # this one catches most of them
236     if ( $args =~ /^(\S+) (-?)about (.*)$/i ) {
237         $target       = $1;
238         $tell_obj     = $3;
239         $dont_tell_me = ($2) ? 1 : 0;
240
241         $tell_obj = $who if ( $tell_obj =~ /^(me|myself)$/i );
242         $query = $tell_obj;
243     }
244     elsif ( $args =~ /^(\S+) where (\S+) can (\S+) (.*)$/i ) {
245
246         # i'm sure this could all be nicely collapsed
247         $target   = $1;
248         $tell_obj = $4;
249         $query    = $tell_obj;
250
251     }
252     elsif ( $args =~ /^(\S+) (what|where) (.*?) (is|are)[.?!]*$/i ) {
253         $target   = $1;
254         $qWord    = $2;
255         $tell_obj = $3;
256         $verb     = $4;
257         $query    = "$qWord $verb $tell_obj";
258
259     }
260     elsif ( $args =~ /^(.*?) to (\S+)$/i ) {
261         $target   = $3;
262         $tell_obj = $2;
263         $query    = $tell_obj;
264     }
265
266     # check target type. Deny channel targets.
267     if ( $target !~ /^$mask{nick}$/ or $target =~ /^$mask{chan}$/ ) {
268         &msg( $who, "No, $who, I won't. (target invalid?)" );
269         return;
270     }
271
272     $target = $talkchannel if ( $target =~ /^us$/i );
273     $target = $who         if ( $target =~ /^(me|myself)$/i );
274
275     &status("tell: target = $target, query = $query");
276
277     # 'intrusive'.
278     #    if ($target !~ /^$mask{chan}$/ and !&IsNickInAnyChan($target)) {
279     #   &msg($who, "No, $target is not in any of my chans.");
280     #   return;
281     #    }
282
283     # self.
284     if ( $target =~ /^\Q$ident\E$/i ) {
285         &msg( $who, "Isn't that a bit silly?" );
286         return;
287     }
288
289     my $oldwho   = $who;
290     my $oldmtype = $msgType;
291     $who = $target;
292     my $result = &doQuestion($tell_obj);
293
294     # ^ returns '0' if nothing was found.
295     $who = $oldwho;
296
297     # no such factoid.
298     if ( !defined $result || $result =~ /^0?$/ ) {
299         $who     = $target;
300         $msgType = 'private';
301
302         # support command redirection.
303         # recursive cmdHooks aswell :)
304         my $done = 0;
305         $done++ if &parseCmdHook($tell_obj);
306         $message = $tell_obj;
307         $done++ unless ( &Modules() );
308
309         &VERB( 'tell: setting old values of who and msgType.', 2 );
310         $who     = $oldwho;
311         $msgType = $oldmtype;
312
313         if ($done) {
314             &msg( $who, "told $target about CMD '$tell_obj'" );
315         }
316         else {
317             &msg( $who, "i dunno what is '$tell_obj'." );
318         }
319
320         return;
321     }
322
323     # success.
324     &status("tell: <$who> telling $target about $tell_obj.");
325     if ( $who ne $target ) {
326         if ($dont_tell_me) {
327             &msg( $who, "told $target about $tell_obj." );
328         }
329         else {
330             &msg( $who, "told $target about $tell_obj ($result)" );
331         }
332
333         $reply = "$who wants you to know: $result";
334     }
335     else {
336         $reply = "telling yourself: $result";
337     }
338
339     &msg( $target, $reply );
340 }
341
342 sub countryStats {
343     if ( exists $cache{countryStats} ) {
344         &msg( $who, 'countrystats is already running!' );
345         return;
346     }
347
348     if ( $chan eq '' ) {
349         $chan = $_[0];
350     }
351
352     if ( $chan eq '' ) {
353         &help('countrystats');
354         return;
355     }
356
357     $conn->who($chan);
358     $cache{countryStats}{chan}  = $chan;
359     $cache{countryStats}{mtype} = $msgType;
360     $cache{countryStats}{who}   = $who;
361     $cache{on_who_Hack}         = 1;
362 }
363
364 sub do_countrystats {
365     $chan    = $cache{countryStats}{chan};
366     $msgType = $cache{countryStats}{mtype};
367     $who     = $cache{countryStats}{who};
368
369     my $total = 0;
370     my %cstats;
371     foreach ( keys %{ $cache{nuhInfo} } ) {
372         my $h = $cache{nuhInfo}{$_}{Host};
373
374         if ( $h =~ /^.*\.(\D+)$/ ) {    # host
375             $cstats{$1}++;
376         }
377         else {                          # ip
378             $cstats{unresolve}++;
379         }
380         $total++;
381     }
382     my %count;
383     foreach ( keys %cstats ) {
384         $count{ $cstats{$_} }{$_} = 1;
385     }
386
387     my @list;
388     foreach ( sort { $b <=> $a } keys %count ) {
389         my $str = join( ', ', sort keys %{ $count{$_} } );
390
391         #       push(@list, "$str ($_)");
392         my $perc = sprintf( '%.01f', 100 * $_ / $total );
393         $perc =~ s/\.0+$//;
394         push( @list, "$str ($_, $perc %)" );
395     }
396
397     # TODO: move this into a scheduler
398     $msgType = 'private';
399     &performStrictReply( &formListReply( 0, 'Country Stats ', @list ) );
400
401     delete $cache{countryStats};
402     delete $cache{on_who_Hack};
403 }
404
405 ###
406 ### amalgamated commands.
407 ###
408
409 sub userCommands {
410
411     # conversion: ascii.
412     if ( $message =~ /^(asci*|chr) (\d+)$/ ) {
413         &DEBUG('ascii/chr called ...');
414         return unless ( &IsChanConfOrWarn('allowConv') );
415
416         &DEBUG('ascii/chr called');
417
418         $arg    = $2;
419         $result = chr($arg);
420         $result = 'NULL' if ( $arg == 0 );
421
422         &performReply( sprintf( "ascii %s is '%s'", $arg, $result ) );
423
424         return;
425     }
426
427     # conversion: ord.
428     if ( $message =~ /^ord(\s+(.*))$/ ) {
429         return unless ( &IsChanConfOrWarn('allowConv') );
430
431         $arg = $2;
432
433         if ( !defined $arg or length $arg != 1 ) {
434             &help('ord');
435             return;
436         }
437
438         if ( ord($arg) < 32 ) {
439             $arg = chr( ord($arg) + 64 );
440             if ( $arg eq chr(64) ) {
441                 $arg = 'NULL';
442             }
443             else {
444                 $arg = '^' . $arg;
445             }
446         }
447
448         &performReply( sprintf( "'%s' is ascii %s", $arg, ord $arg ) );
449         return;
450     }
451
452     # hex.
453     if ( $message =~ /^hex(\s+(.*))?$/i ) {
454         return unless ( &IsChanConfOrWarn('allowConv') );
455         my $arg = $2;
456
457         if ( !defined $arg ) {
458             &help('hex');
459             return;
460         }
461
462         if ( length $arg > 80 ) {
463             &msg( $who, 'Too long.' );
464             return;
465         }
466
467         my $retval;
468         foreach ( split //, $arg ) {
469             $retval .= sprintf( ' %X', ord($_) );
470         }
471
472         &performStrictReply("$arg is$retval");
473
474         return;
475     }
476
477     # crypt.
478     if ( $message =~ /^crypt\s+(\S*)?\s*(.*)?$/i ) {
479         &status("crypt: $1:$2:$3");
480         if ( "$2" ne '' ) {
481             &performStrictReply( crypt( $2, $1 ) );
482         }
483         else {
484             &performStrictReply( &mkcrypt($1) );
485         }
486         return;
487     }
488
489     # cycle.
490     if ( $message =~ /^(cycle)(\s+(\S+))?$/i ) {
491         return unless ( &hasFlag('o') );
492         my $chan = lc $3;
493
494         if ( $chan eq '' ) {
495             if ( $msgType =~ /public/ ) {
496                 $chan = $talkchannel;
497                 &DEBUG("cycle: setting chan to '$chan'.");
498             }
499             else {
500                 &help('cycle');
501                 return;
502             }
503         }
504
505         if ( &validChan($chan) == 0 ) {
506             &msg( $who, "error: invalid channel \002$chan\002" );
507             return;
508         }
509
510         &msg( $chan, "I'm coming back. (courtesy of $who)" );
511         &part($chan);
512 ###     &ScheduleThis(5, 'getNickInUse') if (@_);
513         &status("Schedule rejoin in 5secs to $chan by $who.");
514         $conn->schedule( 5, sub { &joinchan($chan); } );
515
516         return;
517     }
518
519     # reload.
520     if ( $message =~ /^reload$/i ) {
521         return unless ( &hasFlag('n') );
522
523         &status("USER reload $who");
524         &performStrictReply('reloading...');
525         my $modules = &reloadAllModules();
526         &performStrictReply("reloaded:$modules");
527         return;
528     }
529
530     # redir.
531     if ( $message =~ /^redir(\s+(.*))?/i ) {
532         return unless ( &hasFlag('o') );
533         my $factoid = $2;
534
535         if ( !defined $factoid ) {
536             &help('redir');
537             return;
538         }
539
540         my $val = &getFactInfo( $factoid, 'factoid_value' );
541         if ( !defined $val or $val eq '' ) {
542             &msg( $who, "error: '$factoid' does not exist." );
543             return;
544         }
545         &DEBUG("val => '$val'.");
546         my @list =
547           &searchTable( 'factoids', 'factoid_key', 'factoid_value', "^$val\$" );
548
549         if ( scalar @list == 1 ) {
550             &msg( $who, "hrm... '$factoid' is unique." );
551             return;
552         }
553         if ( scalar @list > 5 ) {
554             &msg( $who, 'A bit too many factoids to be redirected, hey?' );
555             return;
556         }
557
558         my @redir;
559         &status( "Redirect '$factoid' (" . ($#list) . ')...' );
560         for (@list) {
561             my $x = $_;
562             next if (/^\Q$factoid\E$/i);
563
564             &status("  Redirecting '$_'.");
565             my $was = &getFactoid($_);
566             if ( $was =~ /<REPLY> see/i ) {
567                 &status('warn: not redirecting a redirection.');
568                 next;
569             }
570
571             &DEBUG("  was '$was'.");
572             push( @redir, $x );
573             &setFactInfo( $x, 'factoid_value', "<REPLY> see $factoid" );
574         }
575         &status('Done.');
576
577         &msg( $who,
578             &formListReply( 0, "'$factoid' is redirected to by '", @redir ) );
579
580         return;
581     }
582
583     # rot13 it.
584     if ( $message =~ /^rot([0-9]*)(\s+(.*))?/i ) {
585         my $reply = $3;
586
587         if ( !defined $reply ) {
588             &help('rot13');
589             return;
590         }
591         my $num   = $1 % 26;
592         my $upper = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
593         my $lower = 'abcdefghijklmnopqrstuvwxyz';
594         my $to =
595             substr( $upper, $num )
596           . substr( $upper, 0, $num )
597           . substr( $lower, $num )
598           . substr( $lower, 0, $num );
599         eval "\$reply =~ tr/$upper$lower/$to/;";
600
601         #$reply =~ y/A-Za-z/N-ZA-Mn-za-m/;
602         &performStrictReply($reply);
603
604         return;
605     }
606
607     # cpustats.
608     if ( $message =~ /^cpustats$/i ) {
609         if ( $^O !~ /linux/ ) {
610             &ERROR('cpustats: your OS is not supported yet.');
611             return;
612         }
613
614         ### poor method to get info out of file, please fix.
615         open( STAT, "/proc/$$/stat" );
616         my $line = <STAT>;
617         chop $line;
618         my @data = split( / /, $line );
619         close STAT;
620
621         # utime(13) + stime(14).
622         my $cpu_usage = sprintf( '%.01f', ( $data[13] + $data[14] ) / 100 );
623
624         # cutime(15) + cstime (16).
625         my $cpu_usage2 = sprintf( '%.01f', ( $data[15] + $data[16] ) / 100 );
626         my $time       = time() - $^T;
627         my $raw_perc   = $cpu_usage * 100 / $time;
628         my $raw_perc2  = $cpu_usage2 * 100 / $time;
629         my $perc;
630         my $perc2;
631         my $total;
632         my $ratio;
633
634         if ( $raw_perc > 1 ) {
635             $perc  = sprintf( '%.01f', $raw_perc );
636             $perc2 = sprintf( '%.01f', $raw_perc2 );
637             $total = sprintf( '%.01f', $raw_perc + $raw_perc2 );
638         }
639         elsif ( $raw_perc > 0.1 ) {
640             $perc  = sprintf( '%.02f', $raw_perc );
641             $perc2 = sprintf( '%.02f', $raw_perc2 );
642             $total = sprintf( '%.02f', $raw_perc + $raw_perc2 );
643         }
644         else {    # <=0.1
645             $perc  = sprintf( '%.03f', $raw_perc );
646             $perc2 = sprintf( '%.03f', $raw_perc2 );
647             $total = sprintf( '%.03f', $raw_perc + $raw_perc2 );
648         }
649         $ratio = sprintf( '%.01f', 100 * $perc / ( $perc + $perc2 ) );
650
651         &performStrictReply( "Total CPU usage: \002$cpu_usage\002 s ... "
652               . "Total used: \002$total\002 % "
653               . "(parent/child ratio: $ratio %)" );
654
655         return;
656     }
657
658     # ircstats.
659     if ( $message =~ /^ircstats?$/i ) {
660         $ircstats{'TotalTime'} ||= 0;
661         $ircstats{'OffTime'}   ||= 0;
662
663         my $count       = $ircstats{'ConnectCount'};
664         my $format_time = &Time2String( time() - $ircstats{'ConnectTime'} );
665         my $total_time =
666           time() - $ircstats{'ConnectTime'} + $ircstats{'TotalTime'};
667         my $reply;
668
669         my $connectivity =
670           100 * ( $total_time - $ircstats{'OffTime'} ) / $total_time;
671         my $p = sprintf( '%.03f', $connectivity );
672         $p =~ s/(\.\d*)0+$/$1/;
673         if ( $p =~ s/\.0$// ) {
674
675             # this should not happen... but why...
676         }
677         else {
678             $p =~ s/\.$//;
679         }
680
681         if ( $total_time != ( time() - $ircstats{'ConnectTime'} ) ) {
682             my $tt_format = &Time2String($total_time);
683             &DEBUG("tt_format => $tt_format");
684         }
685
686         ### RECONNECT COUNT.
687         if ( $count == 1 ) {    # good.
688             $reply =
689                 "I'm connected to $ircstats{'Server'} and have been so"
690               . " for $format_time";
691         }
692         else {
693             $reply =
694                 "Currently I'm hooked up to $ircstats{'Server'} but only"
695               . " for $format_time.  "
696               . "I had to reconnect \002$count\002 times."
697               . "   Connectivity: $p %";
698         }
699
700         ### REASON.
701         my $reason = $ircstats{'DisconnectReason'};
702         if ( defined $reason ) {
703             $reply .= ".  I was last disconnected for '$reason'.";
704         }
705
706         &performStrictReply($reply);
707
708         return;
709     }
710
711     # status.
712     if ( $message =~ /^statu?s$/i ) {
713         my $startString = scalar( gmtime $^T );
714         my $upString    = &Time2String( time() - $^T );
715         my ( $puser, $psystem, $cuser, $csystem ) = times;
716         my $factoids = &countKeys('factoids');
717         my $forks    = 0;
718         foreach ( keys %forked ) {
719             $forks += scalar keys %{ $forked{$_} };
720         }
721         $forks /= 2;
722         $count{'Commands'} = 0;
723         foreach ( keys %cmdstats ) {
724             $count{'Commands'} += $cmdstats{$_};
725         }
726
727         &performStrictReply( "Since $startString, there have been"
728               . " \002$count{'Update'}\002 "
729               . &fixPlural( 'modification', $count{'Update'} )
730               . ", \002$count{'Question'}\002 "
731               . &fixPlural( 'question', $count{'Question'} )
732               . ", \002$count{'Dunno'}\002 "
733               . &fixPlural( 'dunno', $count{'Dunno'} )
734               . ", \002$count{'Moron'}\002 "
735               . &fixPlural( 'moron', $count{'Moron'} )
736               . " and \002$count{'Commands'}\002 "
737               . &fixPlural( 'command', $count{'Commands'} )
738               . ".  I have been awake for $upString this session, and "
739               . "currently reference \002$factoids\002 factoids.  "
740               . "I'm using about \002$memusage\002 "
741               . "kB of memory. With \002$forks\002 active "
742               . &fixPlural( 'fork', $forks )
743               . ". Process time user/system $puser/$psystem child $cuser/$csystem"
744         );
745
746         return;
747     }
748
749     # wantNick. xk++
750     # FIXME does not try to get nick 'back', just switches nicks
751     if ( $message =~ /^wantNick\s(.*)?$/i ) {
752         return unless ( &hasFlag('o') );
753         my $wantnick = lc $1;
754         my $mynick   = $conn->nick();
755
756         if ( $mynick eq $wantnick ) {
757             &msg( $who,
758 "I hope you're right. I'll try anyway (mynick=$mynick, wantnick=$wantnick)."
759             );
760         }
761
762         # fallback check, I guess.  needed?
763         if ( !&IsNickInAnyChan($wantnick) ) {
764             my $str = "attempting to change nick from $mynick to $wantnick";
765             &status($str);
766             &msg( $who, $str );
767             &nick($wantnick);
768             return;
769         }
770
771         # idea from dondelecarlo :)
772         # TODO: use cache{nickserv}
773         if ( $param{'nickServ_pass'} ) {
774             my $str = "someone is using nick $wantnick; GHOSTing";
775             &status($str);
776             &msg( $who, $str );
777             &msg( 'NickServ', "GHOST $wantnick $param{'nickServ_pass'}" );
778
779             $conn->schedule(
780                 5,
781                 sub {
782                     &status(
783 "going to change nick from $mynick to $wantnick after GHOST."
784                     );
785                     &nick($wantnick);
786                 }
787             );
788
789             return;
790         }
791
792         return;
793     }
794
795     return 'CONTINUE';
796 }
797
798 1;
799
800 # vim:ts=4:sw=4:expandtab:tw=80