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