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