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