]> git.donarmstrong.com Git - infobot.git/blob - src/CommandStubs.pl
added ddesc for desc search
[infobot.git] / src / CommandStubs.pl
1 #
2 # User Command Extension Stubs
3 #
4
5 if (&IsParam("useStrict")) { use strict; }
6
7 use vars qw(@W3Search_engines $W3Search_regex);
8 @W3Search_engines = qw(AltaVista Dejanews Excite Gopher HotBot Infoseek
9                         Lycos Magellan PLweb SFgate Simple Verity Google);
10 $W3Search_regex = join '|', @W3Search_engines;
11 $babel::lang_regex = "";        # lame fix.
12
13 ### PROPOSED COMMAND HOOK IMPLEMENTATION.
14 # addCmdHook('TEXT_HOOK', $code_ref,
15 #       (Forker         => 1,
16 #       Identifier      => 'config_label',
17 #       Help            => 'help_label',
18 #       Cmdstats        => 'text_label',)
19 #}
20 ### EXAMPLE
21 # addCmdHook('d?find', (
22 #       CODEREF => \&debianFind(),
23 #       Forker => 1,
24 #       Identifier => "debian",
25 #       Help => "dfind",
26 #       Cmdstats => "Debian Search",) );
27 ### NOTES:
28 #   * viable solution?
29 ###
30
31 sub addCmdHook {
32     my ($ident, %hash) = @_;
33
34     &DEBUG("aCH: added $ident to command hooks.");
35     $cmdhooks{$ident} = \%hash;
36 }
37
38 # RUN IF ADDRESSED.
39 sub parseCmdHook {
40     foreach (keys %cmdhooks) {
41         &DEBUG("cmdhooks{$_} => ...");
42         my %hash = \%{ $cmdhooks{$_} };
43         foreach (keys %hash) {
44             &DEBUG("   '$_' => '$hash{$_}'.");
45         }
46     }
47
48     &DEBUG("pCH: ended.");
49 }
50
51 sub Modules {
52     if (!defined $message) {
53         &WARN("Modules: message is undefined. should never happen.");
54         return;
55     }
56
57     # babel bot: Jonathan Feinberg++
58     if (&IsParam("babelfish") and $message =~ m{
59                 ^\s*
60                 (?:babel(?:fish)?|x|xlate|translate)
61                 \s+
62                 (to|from)               # direction of translation (through)
63                 \s+
64                 ($babel::lang_regex)\w* # which language?
65                 \s*
66                 (.+)                    # The phrase to be translated
67         }xoi) {
68
69         &Forker("babelfish", sub { &babel::babelfish(lc $1, lc $2, $3); } );
70
71         $cmdstats{'BabelFish'}++;
72         return $noreply;
73     }
74
75     # cookie (random). xk++
76     if ($message =~ /^(cookie|random)(\s+(.*))?$/i) {
77         return $noreply unless (&hasParam("cookie"));
78
79         my $arg = $3;
80
81         # lets find that secret cookie.
82         my $target      = $talkchannel;
83         $target         = $who          if ($msgType ne 'public');
84
85         my $cookiemsg   = &getRandom(keys %{$lang{'cookie'}});
86         my ($key,$value);
87         ### WILL CHEW TONS OF MEM.
88         ### TODO: convert this to a Forker function!
89         if ($arg) {
90             my @list = &searchTable("factoids", "factoid_key", "factoid_value", $arg);
91             $key  = &getRandom(@list);
92             $val  = &getFactInfo("factoids", $key, "factoid_value");
93         } else {
94             ($key,$value) = &randKey("factoids","factoid_key,factoid_value");
95         }
96
97         $cookiemsg      =~ s/##KEY/\002$key\002/;
98         $cookiemsg      =~ s/##VALUE/$value/;
99         $cookiemsg      =~ s/##WHO/$who/;
100         $cookiemsg      =~ s/\$who/$who/;       # cheap fix.
101         $cookiemsg      =~ s/(\S+)?\s*<\S+>/$1 /;
102         $cookiemsg      =~ s/\s+/ /g;
103
104         if ($cookiemsg =~ s/^ACTION //i) {
105             &action($target, $cookiemsg);
106         } else {
107             &msg($target, $cookiemsg);
108         }
109
110         $cmdstats{'Random Cookie'}++;
111         return $noreply;
112     }
113
114     if ($message =~ /^d?bugs$/i) {
115         return $noreply unless (&hasParam("debianExtra"));
116
117         &Forker("debianExtra", sub { &debianBugs(); } );
118
119         $cmdstats{'Debian Bugs'}++;
120         return $noreply;
121     }
122
123     # Debian Author Search.
124     if ($message =~ /^dauthor(\s+(.*))?$/i) {
125         return $noreply unless (&hasParam("debian"));
126
127         my $query = $2;
128         if (!defined $query) {
129             &help("dauthor");
130             return $noreply;
131         }
132
133         &Forker("debian", sub { &Debian::searchAuthor($query); } );
134
135         $cmdstats{'Debian Author Search'}++;
136         return $noreply;
137     }
138
139     # Debian Author Search.
140     if ($message =~ /^(d|search)desc(\s+(.*))?$/i) {
141         return $noreply unless (&hasParam("debian"));
142
143         my $query = $2;
144         if (!defined $query) {
145             &help("ddesc");
146             return $noreply;
147         }
148
149         &Forker("debian", sub { &Debian::searchDesc($query); } );
150
151         $cmdstats{'Debian Desc Search'}++;
152         return $noreply;
153     }
154
155     # Debian Incoming Search.
156     if ($message =~ /^dincoming$/i) {
157         return $noreply unless (&hasParam("debian"));
158
159         &Forker("debian", sub { &Debian::generateIncoming(); } );
160
161         $cmdstats{'Debian Incoming Search'}++;
162         return $noreply;
163     }
164
165     # Debian Distro(Package) Stats
166     if ($message =~ /^dstats(\s+(.*))?$/i) {
167         return $noreply unless (&hasParam("debian"));
168         my $dist = $2 || $Debian::defaultdist;
169
170         &Forker("debian", sub { &Debian::infoStats($dist); } );
171
172         $cmdstats{'Debian Statistics'}++;
173         return $noreply;
174     }
175
176     # Debian Contents search.
177     if ($message =~ /^d?contents(\s+(.*))?$/i) {
178         return $noreply unless (&hasParam("debian"));
179
180         my $query = $2;
181         if (!defined $query) {
182             &help("contents");
183             return $noreply;
184         }
185
186         &Forker("debian", sub { &Debian::searchContents($query); } );
187
188         $cmdstats{'Debian Contents Search'}++;
189         return $noreply;
190     }
191
192     # Debian Package info.
193     if ($message =~ /^d?find(\s+(.*))?$/i and &IsParam("debian")) {
194         my $string = $2;
195
196         if (!defined $string) {
197             &help("find");
198             return $noreply;
199         }
200
201         &Forker("debian", sub { &Debian::DebianFind($string); } );
202         return $noreply;
203     }
204
205     if (&IsParam("debian")) {
206         my $debiancmd    = 'conflicts?|depends?|desc|file|info|provides?';
207         $debiancmd      .= '|recommends?|suggests?|maint|maintainer';
208         if ($message =~ /^($debiancmd)(\s+(.*))?$/i) {
209             my $package = lc $3;
210
211             if (defined $package) {
212                 &Forker("debian", sub { &Debian::infoPackages($1, $package); } );
213             } else {
214                 &help($1);
215             }
216
217             return $noreply;
218         }
219     }
220
221     # Dict. xk++
222     if ($message =~ /^dict(\s+(.*))?$/i) {
223         return $noreply unless (&hasParam("dict"));
224
225         my $query = $2;
226         $query =~ s/^[\s\t]+//;
227         $query =~ s/[\s\t]+$//;
228         $query =~ s/[\s\t]+/ /;
229
230         if (!defined $query) {
231             &help("dict");
232             return $noreply;
233         }
234
235         if (length $query > 30) {
236             &msg($who,"dictionary word is too long.");
237             return $noreply;
238         }
239
240         &Forker("dict", sub { &Dict::Dict($query); } );
241
242         $cmdstats{'Dict'}++;
243         return $noreply;
244     }
245
246     # Freshmeat. xk++
247     if ($message =~ /^(fm|freshmeat)(\s+(.*))?$/i) {
248         return $noreply unless (&hasParam("freshmeat"));
249
250         my $query = $3;
251
252         if (!defined $query) {
253             &help("freshmeat");
254             &msg($who, "I have \002".&countKeys("freshmeat")."\002 entries.");
255             return $noreply;
256         }
257
258         &loadMyModule($myModules{'freshmeat'});
259         &Freshmeat::Freshmeat($query);
260
261         $cmdstats{'Freshmeat'}++;
262         return $noreply;
263     }
264
265     # google searching. Simon++
266     if (&IsParam("wwwsearch") and $message =~ /^(?:search\s+)?($W3Search_regex)\s+for\s+['"]?(.*?)['"]?\s*\?*$/i) {
267         return $noreply unless (&hasParam("wwwsearch"));
268
269         &Forker("wwwsearch", sub { &W3Search::W3Search($1,$2,$param{'wwwsearch'}); } );
270
271         $cmdstats{'WWWSearch'}++;
272         return $noreply;
273     }
274
275     # insult server. patch thanks to michael@limit.org
276     if ($message =~ /^insult(\s+(\S+))?$/) {
277         return $noreply unless (&hasParam("insult"));
278
279         my $person      = $2;
280         if (!defined $person) {
281             &help("insult");
282             return $noreply;
283         }
284
285         &Forker("insult", sub { &Insult::Insult($person); } );
286
287         return $noreply;
288     }
289
290     # Kernel. xk++
291     if ($message =~ /^kernel$/i) {
292         return $noreply unless (&hasParam("kernel"));
293
294         &Forker("kernel", sub { &Kernel::Kernel(); } );
295
296         $cmdstats{'Kernel'}++;
297         return $noreply;
298     }
299
300     # LART. originally by larne/cerb.
301     if ($message =~ /^lart(\s+(.*))?$/i) {
302         return $noreply unless (&hasParam("lart"));
303         my ($target) = &fixString($2);
304
305         if (!defined $target) {
306             &help("lart");
307             return $noreply;
308         }
309         my $extra = 0;
310
311         my $chan = $talkchannel;
312         if ($msgType eq 'private') {
313             if ($target =~ /^($mask{chan})\s+(.*)$/) {
314                 $chan   = $1;
315                 $target = $2;
316                 $extra  = 1;
317             } else {
318                 &msg($who, "error: invalid format or missing arguments.");
319                 &help("lart");
320                 return $noreply;
321             }
322         }
323
324         my $line = &getRandomLineFromFile($bot_misc_dir. "/blootbot.lart");
325         if (defined $line) {
326             if ($target =~ /^(me|you|itself|\Q$ident\E)$/i) {
327                 $line =~ s/WHO/$who/g;
328             } else {
329                 $line =~ s/WHO/$target/g;
330             }
331             $line .= ", courtesy of $who" if ($extra);
332
333             &action($chan, $line);
334         } else {
335             &status("lart: error reading file?");
336         }
337
338         return $noreply;
339     }
340
341     # Search factoid extensions by 'author'. xk++
342     if ($message =~ /^listauth(\s+(\S+))?$/i) {
343         return $noreply unless (&hasParam("search"));
344
345         my $query = $2;
346
347         if (!defined $query) {
348             &help("listauth");
349             return $noreply;
350         }
351
352         &loadMyModule($myModules{'factoids'});
353         &performStrictReply( &CmdListAuth($query) );
354         return $noreply;
355     }
356
357     # list{keys|values}. xk++. Idea taken from #linuxwarez@EFNET
358     if ($message =~ /^list(\S+)( (.*))?$/i) {
359         return $noreply unless (&hasParam("search"));
360
361         my $thiscmd     = lc($1);
362         my $args        = $3;
363
364         $thiscmd =~ s/^vals$/values/;
365         return $noreply if ($thiscmd ne "keys" && $thiscmd ne "values");
366
367         # Usage:
368         if (!defined $args) {
369             &help("list". $thiscmd);
370             return $noreply;
371         }
372
373         if (length $args == 1) {
374             &msg($who,"search string is too short.");
375             return $noreply;
376         }
377
378         ### chews up to 4megs => use forker :)
379         &Forker("search", sub { &Search::Search($thiscmd, $args); } );
380 #       &loadMyModule($myModules{'search'});
381 #       &Search::Search($thiscmd, $args);
382
383         $cmdstats{'Factoid Search'}++;
384         return $noreply;
385     }
386
387     # Nickometer. Adam Spiers++
388     if ($message =~ /^(?:lame|nick)ometer(?: for)? (\S+)/i) {
389         return $noreply unless (&hasParam("nickometer"));
390
391         my $term = (lc $1 eq 'me') ? $who : $1;
392         $term =~ s/\?+\s*//;
393
394         &loadMyModule($myModules{'nickometer'});
395         my $percentage = &nickometer($term);
396
397         if ($percentage =~ /NaN/) {
398             $percentage = "off the scale";
399         } else {
400             $percentage = sprintf("%0.4f", $percentage);
401             $percentage =~ s/\.?0+$//;
402             $percentage .= '%';
403         }
404
405         if ($msgType eq 'public') {
406             &say("'$term' is $percentage lame, $who");
407         } else {
408             &msg($who, "the 'lame nick-o-meter' reading for $term is $percentage, $who");
409         }
410
411         return $noreply;
412     }
413
414     # Quotes. mu++
415     if ($message =~ /^quote(\s+(\S+))?$/i) {
416         return $noreply unless (&hasParam("quote"));
417
418         my $query = $2;
419
420         if ($query eq "") {
421             &help("quote");
422             return $noreply;
423         }
424
425         &Forker("quote", sub { &Quote::Quote($query); } );
426
427         $cmdstats{'Quote'}++;
428         return $noreply;
429     }
430
431     # rootWarn. xk++
432     if ($message =~ /^rootWarn$/i) {
433         return $noreply unless (&hasParam("rootWarn"));
434
435         &loadMyModule($myModules{'rootwarn'});
436         &performStrictReply( &CmdrootWarn() );
437         return $noreply;
438     }
439
440     # seen.
441     if ($message =~ /^seen(\s+(\S+))?$/) {
442         return $noreply unless (&hasParam("seen"));
443
444         my $person = $2;
445         if (!defined $person) {
446             &help("seen");
447
448             my $i = &countKeys("seen");
449             &msg($who,"there ". &fixPlural("is",$i) ." \002$i\002 ".
450                 "seen ". &fixPlural("entry",$i) ." that I know of.");
451
452             return $noreply;
453         }
454
455         my @seen;
456         $person =~ s/\?*$//;
457
458         &seenFlush();   # very evil hack. oh well, better safe than sorry.
459
460         ### TODO: Support &dbGetRowInfo(); like in &FactInfo();
461         my $select = "nick,time,channel,host,message";
462         if ($person eq "random") {
463             @seen = &randKey("seen", $select);
464         } else {
465             @seen = &dbGet("seen", "nick", $person, $select);
466         }
467
468         if (scalar @seen < 2) {
469             foreach (@seen) {
470                 &DEBUG("seen: _ => '$_'.");
471             }
472             &performReply("i haven't seen '$person'");
473             return $noreply;
474         }
475
476         # valid seen.
477         my $reply;
478         ### TODO: multi channel support. may require &IsNick() to return
479         ###     all channels or something.
480         my @chans = &GetNickInChans($seen[0]);
481         if (scalar @chans) {
482             $reply = "$seen[0] is currently on";
483
484             foreach (@chans) {
485                 $reply .= " ".$_;
486                 next unless (exists $userstats{lc $seen[0]}{'Join'});
487                 $reply .= " (".&Time2String(time() - $userstats{lc $seen[0]}{'Join'}).")";
488             }
489
490             if (&IsParam("seenStats")) {
491                 my $i;
492                 $i = $userstats{lc $seen[0]}{'Count'};
493                 $reply .= ".  Has said a total of \002$i\002 messages" if (defined $i);
494                 $i = $userstats{lc $seen[0]}{'Time'};
495                 $reply .= ".  Is idling for ".&Time2String(time() - $i) if (defined $i);
496             }
497         } else {
498             my $howlong = &Time2String(time() - $seen[1]);
499             $reply = "$seen[0] <$seen[3]> was last seen on IRC ".
500                         "in channel $seen[2], $howlong ago, ".
501                         "saying\002:\002 '$seen[4]'.";
502         }
503
504         &performStrictReply($reply);
505         return $noreply;
506     }
507
508     # slashdot headlines: from Chris Tessone.
509     if ($message =~ /^slashdot$/i) {
510         return $noreply unless (&hasParam("slashdot"));
511
512         &Forker("slashdot", sub { &Slashdot::Slashdot() });
513
514         $cmdstats{'Slashdot'}++;
515         return $noreply;
516     }
517
518     # Topic management. xk++
519     # may want to add a flag(??) for topic in the near future. -xk
520     if ($message =~ /^topic(\s+(.*))?$/i) {
521         return $noreply unless (&hasParam("topic"));
522
523         my $chan        = $talkchannel;
524         my @args        = split(/ /, $2);
525
526         if (!scalar @args) {
527             &msg($who,"Try 'help topic'");
528             return $noreply;
529         }
530
531         $chan           = lc(shift @args) if ($msgType eq 'private');
532         my $thiscmd     = shift @args;
533
534         # topic over public:
535         if ($msgType eq 'public' && $thiscmd =~ /^#/) {
536             &msg($who, "error: channel argument is not required.");
537             &msg($who, "\002Usage\002: topic <CMD>");
538             return $noreply;
539         }
540
541         # topic over private:
542         if ($msgType eq 'private' && $chan !~ /^#/) {
543             &msg($who, "error: channel argument is required.");
544             &msg($who, "\002Usage\002: topic #channel <CMD>");
545             return $noreply;
546         }
547
548         if (&validChan($chan) == 0) {
549             &msg($who,"error: invalid channel \002$chan\002");
550             return $noreply;
551         }
552
553         # for semi-outsiders.
554         if (!&IsNickInChan($who,$chan)) {
555             &msg($who, "Failed. You ($who) are not in $chan, hey?");
556             return $noreply;
557         }
558
559         # now lets do it.
560         &loadMyModule($myModules{'topic'});
561         &Topic($chan, $thiscmd, join(' ', @args));
562         $cmdstats{'Topic'}++;
563         return $noreply;
564     }
565
566     # Countdown.
567     if ($message =~ /^countdown(\s+(\S+))?$/i) {
568         return $noreply unless (&hasParam("countdown"));
569
570         my $query = $2;
571
572         &loadMyModule($myModules{'countdown'});
573         &Countdown($query);
574
575         $cmdstats{'Countdown'}++;
576
577         return $noreply;
578     }
579
580     # User Information Services. requested by Flugh.
581     if ($message =~ /^u(ser)?info(\s+(.*))?$/i) {
582         return $noreply unless (&hasParam("userinfo"));
583         &loadMyModule($myModules{'userinfo'});
584
585         my $arg = $3;
586         if (!defined $arg or $arg eq "") {
587             &help("userinfo");
588             return $noreply;
589         }
590
591         if ($arg =~ /^set(\s+(.*))?$/i) {
592             $arg = $2;
593             if (!defined $arg) {
594                 &help("userinfo set");
595                 return $noreply;
596             }
597
598             &UserInfoSet(split /\s+/, $arg, 2);
599         } elsif ($arg =~ /^unset(\s+(.*))?$/i) {
600             $arg = $2;
601             if (!defined $arg) {
602                 &help("userinfo unset");
603                 return $noreply;
604             }
605
606             &UserInfoSet($arg, "");
607         } else {
608             &UserInfoGet($arg);
609         }
610
611         $cmdstats{'UIS'}++;
612         return $noreply;
613     }
614
615     # Uptime. xk++
616     if ($message =~ /^uptime$/i) {
617         return $noreply unless (&hasParam("uptime"));
618
619         my $count = 1;
620         &msg($who, "- Uptime for $ident -");
621         &msg($who, "Now: ". &Time2String(&uptimeNow()) ." running $bot_version");
622         foreach (&uptimeGetInfo()) {
623             /^(\d+)\.\d+ (.*)/;
624             my $time = &Time2String($1);
625             my $info = $2;
626
627             &msg($who, "$count: $time $2");
628             $count++;
629         }
630
631         $cmdstats{'Uptime'}++;
632         return $noreply;
633     }
634
635     # wingate.
636     if ($message =~ /^wingate$/i) {
637         return $noreply unless (&hasParam("wingate"));
638
639         my $reply = "Wingate statistics: scanned \002"
640                         .scalar(keys %wingate)."\002 hosts";
641         my $queue = scalar(keys %wingateToDo);
642         if ($queue) {
643             $reply .= ".  I have \002$queue\002 hosts in the queue";
644             $reply .= ".  Started the scan ".&Time2String(time() - $wingaterun)." ago";
645         }
646
647         &performStrictReply("$reply.");
648
649         return $noreply;
650     }
651
652     # convert.
653     if ($message =~ /^convert(\s+(.*))?$/i) {
654         return $noreply unless (&hasParam("units"));
655
656         my $str = $2;
657         if (!defined $str) {
658             &help("convert");
659             return $noreply;
660         }
661
662         my ($from,$to);
663         ($from,$to) = ($1,$2) if ($str =~ /^(.*) to (.*)$/);
664         ($from,$to) = ($2,$1) if ($str =~ /^(.*) from (.*)$/);
665         if (!defined $from or !defined $to or $to eq "" or $from eq "") {
666             &msg($who, "Invalid format!");
667             &help("convert");
668             return $noreply;
669         }
670
671         &Forker("units", sub { &Units::convertUnits($from, $to); } );
672
673         return $noreply;
674     }
675
676     # do nothing and let the other routines have a go
677     return '';
678 }
679
680 1;