]> git.donarmstrong.com Git - infobot.git/blob - src/Process.pl
Initial revision
[infobot.git] / src / Process.pl
1 # infobot :: Kevin Lenzo 1997-1999
2 #
3 # process the incoming message
4 #
5
6 if (&IsParam("useStrict")) { use strict; }
7
8 sub process {
9     $learnok    = 0;    # Able to learn?
10     $talkok     = 0;    # Able to yap?
11     $force_public_reply = 0;
12
13     return 'X'                  if $who eq $ident;      # self-message.
14     return 'addressedother set' if ($addressedother);
15
16     $talkok     = ($param{'addressing'} =~ /^OPTIONAL$/i or $addressed);
17     $learnok    = ($param{'learn'}      =~ /^HUNGRY$/i   or $addressed);
18
19     &shmFlush();                # hack.
20
21     # check if we have our head intact.
22     if ($lobotomized) {
23         if ($addressed and IsFlag("o") eq "o") {
24             &msg($who, "give me an unlobotomy.");
25         }
26         return 'LOBOTOMY';
27     }
28
29     # talkMethod.
30     if ($param{'talkMethod'} =~ /^PRIVATE$/i) {
31         if ($msgType =~ /public/ and $addressed) {
32             &msg($who, "sorry. i'm in 'PRIVATE' talkMethod mode ".
33                   "while you sent a message to me ${msgType}ly.");
34
35             return 'TALKMETHOD';
36         }
37     }
38
39     # ignore.
40     if ($ignore) {
41         return 'IGNORE';
42     }
43
44     # join, must be done before outsider checking.
45     if ($message =~ /^join(\s+(.*))?\s*$/i) {
46         return 'join: not addr' unless ($addressed);
47
48         $2 =~ /^($mask{chan})(,(\S+))?/;
49         my($thischan, $key) = (lc $1, $3);
50         my $chankey     = $thischan;
51         $chankey        .= " $key"      if (defined $key);
52
53         if ($thischan eq "") {
54             &help("join");
55             return;
56         }
57
58         # Thanks to Eden Li (tile) for the channel key patch
59         my @chans = split(/[\s\t]+/, $param{'join_channels'});
60         if (!grep /^$thischan$/i, @chans) {
61             if (&IsFlag("o") ne "o") {
62                 &msg($who, "I am not allowed to join $thischan.");
63                 return;
64             }
65         }
66
67         if (&validChan($thischan)) {
68             &msg($who,"I'm already on $thischan...");
69             return;
70         }
71         $joinverb{$thischan} = $who;    # used for on_join self.
72
73         &joinchan($chankey);
74         &status("JOIN $chankey <$who>");
75         &msg($who, "joining $chankey");
76
77         return;
78     }
79
80     # allowOutsiders.
81     if (&IsParam("disallowOutsiders") and $msgType =~ /private/i) {
82         my $found = 0;
83
84         foreach (keys %channels) {
85             next unless (&IsNickInChan($who,$_));
86
87             $found++;
88             last;
89         }
90
91         if (!$found and scalar(keys %channels)) {
92             &status("OUTSIDER <$who> $message");
93             return 'OUTSIDER';
94         }
95     }
96
97     # User Processing, for all users.
98     return 'NOREPLY from userC' if &userCommands() eq 'NOREPLY';
99
100     ###
101     # once useless messages have been parsed out, we match them.
102     ###
103
104     # addressed.
105     if ($message =~ /^\Q$ident\E\s*\?*$/i) {
106         &status("feedback addressing from $who");
107
108         &performReply("yes?");
109
110         return;
111     }
112
113     # confused? is this for infobot communications?
114     foreach (keys %{$lang{'confused'}}) {
115         my $y = $_;
116
117         next unless ($message =~ /^\Q$y\E\s*/);
118         return 'CONFUSO';
119     }
120
121     # hello. [took me a while to fix this. -xk]
122     if ($orig{message} =~ /^(\Q$ident\E\S?[:, ]\S?)?\s*(h(ello|i( there)?|owdy|ey|ola))( \Q$ident\E)?\s*$/i) {
123         return '' unless ($talkok);
124
125         # 'mynick: hi' or 'hi mynick' or 'hi'.
126         &status("somebody said hello");
127
128         # 50% chance of replying to a random greeting when not addressed
129         if (!defined $5 and $addressed == 0 and rand() < 0.5) {
130             &status("not returning unaddressed greeting");
131             return;
132         }
133
134         # customized random message.
135         my $tmp = (rand() < 0.5) ? ", $who" : "";
136         &performStrictReply(&getRandom(keys %{$lang{'hello'}}) . $tmp);
137         return;
138     }
139
140     # greetings.
141     if ($message =~ /how (the hell )?are (ya|you)( doin\'?g?)?\?*$/) {
142         my $reply = &getRandom(keys %{$lang{'howareyou'}});
143         
144         &performReply($reply);
145         
146         return;
147     }
148
149     # praise.
150     if ($message =~ /you (rock|rewl|rule|are so+ coo+l)/ ||
151         $message =~ /(good (bo(t|y)|g([ui]|r+)rl))|(bot( |\-)?snack)/i)
152     {
153         return 'praise: no addr' unless ($addressed);
154
155         &status("random praise detected");
156
157         my $tmp = (rand() < 0.5) ? "thanks $who " : "";
158         &performStrictReply($tmp.":)");
159
160         return;
161     }
162
163     # thanks.
164     if ($message =~ /^than(ks?|x)( you)?( \S+)?/i) {
165         &DEBUG("thanks: talkok => '$talkok', addressed => '$addressed'.");
166         return 'thank: no addr' unless ($message =~ /$ident/ or $talkok);
167
168         &performReply( &getRandom(keys %{$lang{'welcome'}}) );
169         return;
170     }
171
172
173     ###
174     ### bot commands...
175     ###
176
177     # override msgType.
178     if ($msgType =~ /public/ and $message =~ s/^\+//) {
179         &status("found '+' flag; setting msgType to public.");
180         $force_public_reply++;
181         $msgType = 'public';
182     }
183
184
185     # karma. set...
186     if ($message =~ /^(\S+)(--|\+\+)\s*$/ and $addressed) {
187         return '' unless (&hasParam("karma"));
188
189         my($term,$inc) = (lc $1,$2);
190
191         if ($msgType !~ /public/i) {
192             &msg($who, "karma must be done in public!");
193             return;
194         }
195
196         if (lc($term) eq lc($who)) {
197             &msg($who, "please don't karma yourself");
198             return;
199         }
200
201         my $karma = &dbGet("karma", "nick",$term,"karma") || 0;
202         if ($inc eq '++') {
203             $karma++;
204         } else {
205             $karma--;
206         }
207
208         &dbSet("karma", "nick",$term,"karma",$karma);
209
210         return;
211     }
212
213     # here's where the external routines get called.
214     # if they return anything but null, that's the "answer".
215     if ($addressed) {
216         my $er = &Modules();
217         if ($er =~ /\S/) {
218             &performStrictReply($er) if ($er ne 'NOREPLY');
219             return 'SOMETHING 1';
220         }
221
222         ### FIXME: should this only apply to public messages?
223         if ($addrchar) {
224             &DEBUG("floodwho => '$floodwho'.");
225             delete $flood{$floodwho}{$message};
226             &status("short return due to unknown command.");
227             return 'ADDR CHAR';
228         }
229     }
230
231     if (&IsParam("factoids") and $param{'DBType'} =~ /^(mysql|pg|postgres|dbm)/i) {
232         &FactoidStuff();
233     } elsif ($param{'DBType'} =~ /^none$/i) {
234         return "NO FACTOIDS.";
235     } else {
236         &ERROR("INVALID FACTOID SUPPORT? ($param{'DBType'})");
237         &shutdown();
238         exit 0;
239     }
240 }
241
242 sub FactoidStuff {
243     # inter-infobot.
244     if ($msgType =~ /private/ and $message =~ s/^:INFOBOT://) {
245         ### identification.
246         &status("infobot <$nuh> identified") unless $infobots{$nuh};
247         $infobots{$nuh} = $who;
248
249         ### communication.
250
251         # query.
252         if ($message =~ /^QUERY (<.*?>) (.*)/) {        # query.
253             my ($target,$item) = ($1,$2);
254             $item =~ s/[.\?]$//;
255
256             &status(":INFOBOT:QUERY $who: $message");
257
258             if ($_ = &getFactoid($item)) {
259                 &msg($who, ":INFOBOT:REPLY $target $item =is=> $_");
260             }
261
262             return 'INFOBOT QUERY';
263         } elsif ($message =~ /^REPLY <(.*?)> (.*)/) {   # reply.
264             my ($target,$item) = ($1,$2);
265
266             &status(":INFOBOT:REPLY $who: $message");
267
268             my ($lhs,$mhs,$rhs) = $item =~ /^(.*?) =(.*?)=> (.*)/;
269
270             if ($param{'acceptUrl'} !~ /REQUIRE/ or $rhs =~ /(http|ftp|mailto|telnet|file):/) {
271                 &msg($target, "$who knew: $lhs $mhs $rhs");
272
273                 # "are" hack :)
274                 $rhs = "<REPLY> are" if ($mhs eq "are");
275                 &setFactInfo($lhs, "factoid_value", $rhs);
276             }
277
278             return 'INFOBOT REPLY';
279         } else {
280             &ERROR(":INFOBOT:UNKNOWN $who: $message");
281             return 'INFOBOT UNKNOWN';
282         }
283     }
284
285
286     # factoid forget.
287     if ($message =~ s/^forget\s+//i) {
288         return 'forget: no addr' unless ($addressed);
289
290         my $faqtoid = $message;
291         if ($faqtoid eq "") {
292             &help("forget");
293             return;
294         }
295
296         $faqtoid =~ tr/A-Z/a-z/;
297         my $result = &getFactoid($faqtoid);
298
299         if (defined $result) {
300             my $author = &getFactInfo($faqtoid, "created_by");
301             if (IsFlag("r") ne "r" && $author =~ /^\Q$who\E\!/i) {
302                 &msg($who, "you don't have access to remove that factoid");
303                 return;
304             }
305
306             return 'locked factoid' if (&IsLocked($faqtoid) == 1);
307
308             &status("forget: <$who> '$faqtoid' =is=> '$result'");
309             &delFactoid($faqtoid);
310
311             &performReply("i forgot $faqtoid");
312
313             $count{'Update'}++;
314         } else {
315             &performReply("i didn't have anything called '$faqtoid'");
316         }
317
318         return;
319     }
320
321     # factoid locking.
322     if ($message =~ /^((un)?lock)(\s+(.*))?\s*?$/i) {
323         return 'lock: no addr 2' unless ($addressed);
324
325         my $function = lc $1;
326         my $faqtoid  = lc $4;
327
328         if ($faqtoid eq "") {
329             &help($function);
330             return;
331         }
332
333         # strongly requested by #debian on 19991028. -xk
334         if (1 and $faqtoid !~ /^\Q$who\E$/i and &IsFlag("o") ne "o") {
335             &msg($who,"sorry, locking cannot be used since it can be abused unneccesarily.");
336             &status("Replace 1 with 0 in Process.pl#~324 for locking support.");
337             return;
338         }
339
340         if (&getFactoid($faqtoid) eq "") {
341             &msg($who, "factoid \002$faqtoid\002 does not exist");
342             return;
343         }
344
345         if ($function eq "lock") {
346             &CmdLock($faqtoid);
347         } else {
348             &CmdUnLock($faqtoid);
349         }
350
351         return;
352     }
353
354     # factoid rename.
355     if ($message =~ s/^rename(\s+|$)//) {
356         return 'rename: no addr' unless ($addressed);
357
358         if ($message eq "") {
359             &help("rename");
360             return;
361         }
362
363         if ($message =~ /^'(.*)'\s+'(.*)'$/) {
364             my($from,$to) = (lc $1, lc $2);
365
366             my $result = &getFactoid($from);
367             if (defined $result) {
368                 my $author = &getFactInfo($from, "created_by");
369                 if (&IsFlag("m") and $author =~ /^\Q$who\E\!/i) {
370                     &msg($who, "It's not yours to modify.");
371                     return 'NOREPLY';
372                 }
373
374                 if ($_ = &getFactoid($to)) {
375                     &performReply("destination factoid already exists.");
376                     return;
377                 }
378
379                 &setFactInfo($from,"factoid_key",$to);
380
381                 &status("rename: <$who> '$from' is now '$to'");
382                 &performReply("i renamed '$from' to '$to'");
383             } else {
384                 &performReply("i didn't have anything called '$from'");
385             }
386         } else {
387             &msg($who,"error: wrong format. ask me about 'help rename'.");
388         }
389
390         return;
391     }
392
393     # factoid substitution. (X =~ s/A/B/FLAG)
394     if ($message =~ m|^(.*?)\s+=~\s+s([/,#])(.+?)\2(.*?)\2([a-z]*);?\s*$|) {
395         my ($faqtoid,$delim,$op,$np,$flags) = (lc $1, $2, $3, $4, $5);
396         return 'subst: no addr' unless ($addressed);
397
398         # incorrect format.
399         if ($np =~ /$delim/) {
400             &msg($who,"looks like you used the delimiter too many times. You may want to use a different delimiter, like ':' or '#'.");
401             return;
402         }
403
404         # success.
405         if (my $result = &getFactoid($faqtoid)) {
406             return 'subst: locked' if (&IsLocked($faqtoid) == 1);
407             my $was = $result;
408
409             if (($flags eq "g" && $result =~ s/\Q$op/$np/gi) || $result =~ s/\Q$op/$np/i) {
410                 if (length $result > $param{'maxDataSize'}) {
411                     &performReply("that's too long");
412                     return;
413                 }
414                 &setFactInfo($faqtoid, "factoid_value", $result);
415                 &status("update: '$faqtoid' =is=> '$result'; was '$was'");
416                 &performReply("OK");
417             } else {
418                 &performReply("that doesn't contain '$op'");
419             }
420         } else {
421             &performReply("i didn't have anything called '$faqtoid'");
422         }
423
424         return;
425     }
426
427
428     # Fix up $message for question.
429     for ($message) {
430         # fix the string.
431         s/^hey([, ]+)where/where/i;
432         s/whois/who is/ig;
433         s/where can i find/where is/i;
434         s/how about/where is/i;
435         s/ da / the /ig;
436
437         # clear the string of useless words.
438         s/^(stupid )?q(uestion)?:\s+//i;
439         s/^(does )?(any|ne)(1|one|body) know //i;
440
441         s/^[uh]+m*[,\.]* +//i;
442
443         s/^well([, ]+)//i;
444         s/^still([, ]+)//i;
445         s/^(gee|boy|golly|gosh)([, ]+)//i;
446         s/^(well|and|but|or|yes)([, ]+)//i;
447
448         s/^o+[hk]+(a+y+)?([,. ]+)//i;
449         s/^g(eez|osh|olly)([,. ]+)//i;
450         s/^w(ow|hee|o+ho+)([,. ]+)//i;
451         s/^heya?,?( folks)?([,. ]+)//i;
452     }
453
454     if ($addressed and $message =~ s/^no([, ]+)(\Q$ident\E\,+)?\s*//i) {
455         $correction_plausible = 1;
456         &status("correction is plausible, initial negative and nick deleted ($&)") if ($param{VERBOSITY});
457     } else {
458         $correction_plausible = 0;
459     }
460
461     my $result = &doQuestion($message);
462
463     return 'result is NOREPLY' if ($result eq 'NOREPLY');
464
465     if (defined $result and $result ne "") {            # question.
466         &status("question: <$who> $message");
467         $count{'Question'}++;
468     } elsif (&IsParam("perlMath") and $addressed) {     # perl math.
469         &loadMyModule("perlMath");
470         my $newresult = &perlMath();
471
472         if (defined $newresult and $newresult ne "") {
473             $result = $newresult;
474             &status("math: <$who> $message => $result");
475         }
476     }
477
478     if ($result ne "") {
479         &performStrictReply($result);
480         return;
481     } else {
482         # why would a friendly bot get passed here?
483         if (&IsParam("friendlyBots")) {
484             return if (grep lc($_) eq lc($who), split(/\s+/, $param{'friendlyBots'}));
485         }
486
487         # do the statement.
488         if ($_ = &doStatement($message)) {
489             return;
490         }
491
492         if ($addressed) {
493             &status("unparseable: $message");
494             &performReply( &getRandom(keys %{$lang{'dunno'}}) );
495             $count{'Dunno'}++;
496         }
497     }
498 }
499
500 1;