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