commit ee4f56acf60ea6212ff282ef7f3d046ec8a54f9d Author: Michael Murtaugh Date: Sun Sep 27 18:59:47 2020 +0200 gulp diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..a4609f6 --- /dev/null +++ b/LICENSE @@ -0,0 +1,9 @@ + +Copyright (c) Kevin Lenzo, 1996-2000, except where noted +otherwise. + +The Infobot is covered under the same terms as Perl itself +(the Artistic License). This software is meant to be freely +available under those terms in perpetuity. + + diff --git a/README b/README new file mode 100644 index 0000000..4871027 --- /dev/null +++ b/README @@ -0,0 +1,146 @@ + +You will need to update your infobot.config +and infobot.users. See the example files. + +-- + +This requires perl 5. + +You should be able to start up just by running +infobot. If you are using macperl, you will +(currently) have to make one minor change (because +$^O didn't work for me under os8). + +The infobot uses parameter files, typically in the +params directory, to set up with. It treats anything +on the command line as a parameter file and tries to +load it. + +If you are using macperl, you will want to set +the value of the macperl parameter to 1 in the +two given param files (in the 'files' dir). + +By default, the infobot uses the IRC setup. This +may change. NOTE that the irc version has no output +by default; you'll have to turn up the debug level +to get more. + +to start up the infobot, just invoke it from the +command line. + + infobot + +--- + +A note on forms: you can prepend the tag +to values in the db to just get a reply with no +extra info. + +e.g. + + x => y + +then when you ask 'x?' it will just reply 'y' instead +of something like "i think x is y". + +--- + +* extending the bot by adding your own code + +try to keep your changes inside src/myRoutines.pl +so that you can easily just replace this file when +there are new revs. this is called just after some +of the normalization stuff in urlProcess.pl. take +a look at the file for details. + +basically, if myRoutines returns non-null, it's +taken to have 'caught' the event. you can just +return '' to let the rest of the processing go at +it. + +--- + +* update_db & dump_db + +update_db is a little perl script that will take a +flat ascii file and make an infobot-style db out +of it (currently just a couple of dbm files). You'll +want to make 2, even if theye contain only 1 element +each. it will also simply add (and overwrite entries +in) existing dbs. This is especially nice if +you don't allow updates to the databases through IRC +and just want a collection of permanent factoids. + +update_db + +where is an ascii file like (in the case +of an url-style infobot): + +infobot => at http://www.cs.cmu.edu/~lenzo/hocus.html + +one key => value per line. In the current setup, +you need an is-database and an are-database, mainly +for legacy reasons about representing plurality and +being able to give the proper form. in the infobot-is.txt +file and infobot-are.txt files you have examples. these +are a fine starting point: + +1.1 update_db infobot-is.txt infobot-is + update_db infobot-are.txt infobot-are + +2. Now you need to edit infobot to set up your bot. + Don't forget to set the path to perl properly at + the top and make it executable. + +3. Then try running infobot. At present, there's a + bunch of VERY BAD code in it, so don't use the -w + switch unless you want to fix a bunch of things and + mail me. + +Eventually, kill it and then you'll probably +want to crontab it. included is a sample crontab +and the script that you will need to edit. + +dump_db + +will just make a flat ascii file out of the named db, +e.g. + + dump_db infobot-is + +Both update_db and dump_db take an optional switch, -m, which tells them +what DBM module to use. You'll need to specify this if you set +DBMModule in your config file in order to get the bot to use something +other than Perl's default. Eg, + + update_db -m DB_File infobot-is.txt infobot-is + dump_db -m DB_File infobot-is + +good luck, and mail me! + +kevin +lenzo@cs.cmu.edu + +ps - i am just releasing this _now_ instead of waiting + to fix everything. If you use this and like it, + or even if you don't, please mail me! + +--- + +thanks to: + +You, for getting this and using this. Especially if +you mail me and let me put you on the mailing list. +lenzo@cs.cmu.edu + +special thanks to: + +steve orens (sorens) for being a tour-de-force beta bomber +yo for working with script. this is a big one! +amug and everyone there for hosting the undernet url +#macintosh for dealing with url through his troubled childhood +tris for being an early guinea pig +jadin for pointing out the @verb bug... fixed in 0.17b +chucky burnett for tons of stuff + + diff --git a/REVISIONS b/REVISIONS new file mode 100644 index 0000000..13699a9 --- /dev/null +++ b/REVISIONS @@ -0,0 +1,687 @@ +0.45.3 + +Really fix the stuff in DBM.pl for the %param hash. + +0.45.1,2 + +Fixed some path names, made a new tarball. + +0.45.0 + +Renamed the miscdir parameter to confdir (in 'infobot') +Renames 'files' directory to 'conf' +Seperated src/ into src/ and extras/ +Changed default name to 'i-bot' in the infobot.config file +Rationalized the names of the dbs to use dbname as a prefix + +0.44.5 + +Push ./src onto the path so Util.pm gets in. +New Airport.pl replaces METAR2 with a lot nicer stuff. + mendel++. Very nice example of a module with forking, + etc. +Fixed excuse.pl's return codes. +Roderick++'s extensive factoid locking patches for + sharing DBs between infobots. +Added scripts/make_snap and scripts/restore_snap , which + make and restore ASCII snapshots of the databases, + respectively. This is good to do periodically as a + backup. +Added stockquote.pl to get stock quotes (LotR++) and added + a boolean parameter ('stockquotes') to turn it on or off. +Fixed a bug in the http proxy in the RDF fetching code (LotR++) +Messages no longer record the apparent last channel + when given in private. +Changed src/excuse.pl to guard against the server being + down, though i'm afraid the server is never going + to come back up. +Cleaned extra white space off the end of parameter values + during the read of the config file. +Currency exchance is now case-insensetive. +There were several other small bugfixes that didn't make it + into this file during a move. + +0.44.4 + +Removed 'factpacks' subdirectory. These packs are all on + the web site (http://www.infobot.org), and more. +Tidying of purldoc code. +Tidying of W3Search triggers +Tidying of IMDB, Websters, etc. +Splitting lines in say()/msg() +HTTP proxy support +Little tidying of the Math code. +More informative return values from Process +Better support for `no, $nick, ...' +Much increased `tell' support +perlfaq' support: uses RSS to get faqtoids from perlfaqprime +Much needed fixes to Zippy factoids +Babelfish rewritten +Net::Telnet timeout fix to insult +Fixed `exchange' typo in infobot.config. +\| for quoting pipes in factoids, Avi++ +Added the channels patch. infobot.channels now sets channel-specific + options. The format is pretty much the same as the users file. +Documented all the extensions. +Fixed the `eval' command, which you shouldn't be using anyway. +Removed spurious line breaks in Zippy's data. +The `msgonly' parameter, if set, will see a question on channel and + respond to it via /msg +The `continuity' parameter controls how many seconds must elapse before + the infobot assumes you have stopped addressing it. Set this to 0, + and the infobot will never assume that it is being addressed. +Added a warning to Babel.pl if target language is `en' +Close `karma' and `seen' databases in &killed, now karma doesn't + get reset. + +0.44.3 + +NOTE: You must update WWW::Search to the latest version + for the Google search to work. +NOTE: As usual, the new features (mostly) have new + parameters that need to be defined in + files/infobot.config -- to update, you'll need + to move your dbm files into the new source + tree and edit infobot.config. this is the best way. +Made return values from myRoutines.pl said or messaged + rather than using &say and &msg inside myRoutines. + Use 'NOREPLY' to override this if you want to + use msg and/or say yourself (such as in a callback + or when forking). +Moved the current myRoutines.pl file to a file called + Extras.pl. myRoutines.pl is reserved for local + user extensions, and Extras.pl is now where the + add-ons in the distribution are. They both + behave the same as the old myRoutines.pl did. + Extras is called after myRoutines. +Moved several redirects out of Reply.pl and into Extras. +Added 'literal' query -- 'literal foo' will show the + factoid for the key foo, with tags and |s literally. +Added RDF/RSS support (LotR++) in RDF.pl. Uses the tag + and replaces it in-line. + RSS is RDF Site Summary; many sites now use this + standard format to encode their headlines/topics. + Requires XML::RSS. +Added currency exchange module (exchange.pl) from + bobby@bofh.dk (thanks!) +Added excuse module (excuse.pl), also from bobby@bofh.dk! +Added 'purldoc' -- ^Masque++ -- which searches through + perl FAQ question titles. +Removed usair module. They changed the interface and + this should just be re-written more gerally. +Added support for Zippy.pl, which provides Zippy witticisms. + i made it require to be addressed. "infobot, yow" or + "infobot, be zippy" is the trigger. (mendel++) + the parameter is "zippy" in infobot.config. +Added 'divine (.*)', a magic 8-ball (boojum++) +Made Search work again for users with the +s user flag set. + I still don't recommend this for bots with very big + dbs. +Another pass at getting the 'reload' code to work (Simon++). +Target adressing in 'tell' made more consistent (Simon++). +Now works with MD5 passwords also (thanks to Bobby Billingsley). +Added timeouts to LWP-using modules. +Fixed CTCP ping reply. +Started RIPE whois to complement Internic whois, moved the + whois stuff into myRoutines. This is getting to be + a mess and still needs work. (Thanks to Bo Krosgaard for + this suggestion). + +0.44.2 + +Added USAir flight information: 'usair flight 781'. requires LWP. + This should be replaced with a more general one. +Added keyed channel patch from Eden Li (tile). +Added new slashdot headline retrieval code care of Richard Hoelscher + (Rahga). It makes Chris Tessone's code go to the XML file on /. + Also restricted its recongized form to "slashdot" or "slashdot + headlines". Now called "Slashdot3". +Added a factpack on Security to factopacks/ submitted by Peter + Johnson (rottz), and one that has all the ports listed for tcp + and udp from Samy Kamkar (CommPort5). Keep it up! :) +Applied a patch to the insult server code from michael@limit.org. + should fix the function as well as "insult x in german". + btw, i can't send email to limit.org, so i hope he sees this :) +Modified METAR code from Lazarus Long + and added a status line so it tells the owner it requires + LWP and Geo::METAR. +Added Simon Cozens' Google search. Requires WWW::Search::Google. + "google for foo", "search google for foo". +Expanded the Google search to do everything WWW::Search knows about, + and to fork so it wouldn't block the bot. Dejanews, Google, + Gopher, Excite, Infoseek, HotBot, Lycos, AltaVista, Magellan, + PLweb, SFgate, and Verity. try 'search for '. + But you really need to install WWW::Search to use this. +Added "shut up" (which changes Addressing to "REQUIRE"), + "wake up" (changes it to "OPTIONAL"), and "showmode" that + tells which mode it's in. Aldebaran++ for this. the param + "shutup" controls whether this is on; turn it off if you always + want it to be REQUIRE. +Made the output of "seen" nicer; reports how long it's been. +By the way, the Nickometer code is due to Adam Spiers, and it + was one of the earlier, relatively undocumented add-ons that + made an example for others to start off with. Added comment. + + +0.44.1 + +Fixed the CTCP bug which people were exploiting to crash. Thanks! +Wrapped the babelfish translation code 'use's in evals so + lack of URI::Escape won't stop you from running the bot. +Added Chris Tessone's slashdot headlines module with a few minor + changes (the same eval trick as above). +Added some documentation to infobot_guide.html (gasp!) +Added some factpacks in factpacks/ that were on the web site. + +0.44.0 + +WARNING: many changes have been undocumented, but + i'm getting lots of requests to release the current + state -- warts and all. Here it is, 6:35 AM Jun 24 99, + an hour before yapc 99 opens. +many small things, as usual. +babel code (jdf++) for using babelfish to translate + things. 'translate to german: hello'. this + can be shortened to 'x to de hello'. *note: + LWP must be installed for this to work. +'insult server' code; probably not very useful. + Also requires LWP. + + +0.43.6 + +freeside++ for code to clean up the imbd redirect. +fimmtiu++ for 'your' patches. blame him now. +fixed the text of the foldoc redirect (TorgoX++) +added passwords for servers with passwords (ksiero++) + including server_pass in infobot.config +made s/// case-insensetive (mendel++) +added vhost support and vhost_name to infobot.config (elph++) +changed some trivial status messages to be prettier +made miscdir fully qualified, and changed it to ./files in + the default infobot.config file. +moved stray help setup code into a subroutine and call it + from Setup.pl +added "say" for +o (/msg say #channel foo) +made it so that +o can make the bot join any channel +added NOAA.pl, inspired by geniusj's sh script + to myRoutines.pl +added METAR support (mendel++ for metar.pl), and this + plus the weather routine make nice examples + +0.43.5 + +added as a species of : X is foo! +added murrayb++'s patches for an ignore list file +made help path relative (also murrayb++) +renamed "scripts/make_db" to "scripts/update_db" +added "scripts/unupdate_dbs" to back out all changes by nick + from a log file or part of a log file. good for removing + vandalism. +made 'forget' logging more friendly to reversing it +moved all the setup stuff more cleanly into Setup.pl +made the ignore list modifiab;e at run-time with the P flag + and added 'ignore' and 'unignore' commands via msg +added substitutions: X =~ s/A/B/ + +0.43.4 + +made private messages not respoken under the persistant + "seen" -- this was allowing people to get private + information on 0.43.3. 0.43.3 was only available for + a few hours, so i hope this impact is minimal. + +0.43.3 + +many undocumented little things. fixes, of course! +fixed the reply after seen. +made seen persistant. added the infobot.config line 'seen' + for the seen-db location +added what the last thing seen was. +made the karma path fully specified. + +0.43.2 + +fixed the learning from other bots based on URL policy + +0.43.1 + +minor fixes here and there. +fixed the math bug (finally! i think!) +several NL patches. Small CTCP fix. +some statement and question changes. nothing major. +wanted to get this version out before i tried getting + things working on a few more platforms. seems + pretty stable. + +0.43.0 + +* UPDATE YOUR irc.params to infobot.config FILES * +* UPDATE YOUR userfile.txt files to infobot.users FILES * +* SOME DOCUMENTATION is now in doc/infobot_guide.html + +changed DEBUG parameter name to VERBOSITY +removed the broken STANDALONE mode for now + and eviscerated the code for it +removed some lint from the params file +files/irc.params IS NOW CALLED files/infobot.config +removed vestigial paramdbm code. +removed MacOS-specific code. this needs-writing. +fixed the "out-loud" comment "you are not a bot owner" + to be silent +removed the vesitigial and misleading infobot.doc + and created some documentation ! in doc/infobot.html + and children +renamed userfile.txt to files/infobot.users +added variable interpolation to infobot.config so + you can use $ident and all previously-defined + parameter values in the assignent of subsequent + paramters. +moved userfile diagnostics into User.pl (!) from + top level infobot script +renamed crontab.infobot to infobot.crontab +converted all prints to status() for uniform logging + and console output +removed other vesitigal logging code (Log.pl) +redid the ansi color by type and status +made internic reply via msg only +removed MLF's -- these need rewriting +moved the addressing code ALL out of Irc*.pl +cleared initial negative on statements when the entry + doesn't yet exist (less weird factoids) +added 'also |' to add disjuncts easily +allowed coherent protection of any word from + processing using \. e.g. \is for + x \is y is y +added %channels, %seen, %verified hashes +added password + hostmask protection and command-on-request + with the syntax /msg + where is {eval (mode e), op (mode p), die (mode o)} +previously public bot commands are now private message only or + privmsg + password +added "sane" files (sane-is.txt amd sane-are.txt) that + will be loaded into the -is and -are dbs at startup + and will set some items to sane values. put things + that you want to be permanent in these. +isolated statement rejection code +moved math into Math.pl +moved search code into Search.pl +rolled the requires in the top level script into a + single loop that automatically loads all the perl + files in the src directory +fixed the interaction between addressing and volunteering. + minVolunteerLength applies only if addressing is not REQUIRED +fixed the grotty math bug in perlMath that prevented negative + numbers from evalling properly + +0.42.1 + +made it go for the _first_ verb rather than + the first verb in the list. cleaned up the + debug info. +fixed the underscore-erasing bug. +there was a problem is \b$verb\b missing + things like .is; fixed. +karma fix... allow "me", tolerate whitespace + (thanks fimmtiu and SirGawain) + +0.42 + +fixed an interaction between marked questions, + minimum volunteering length, and addressing. +allowed talk between friendly bots +rationalized some of the logging, so you can see + who did everything ('is also' updates, in + particular). +fixed the traceroute calling syntax +for some, karma didn't work with 0.41.5; it may now :) + +0.41.5 + +closed the traceroute hole +fixed the reverse DNS +fixed some 'huh?' replies -- made sure to return + the NOREPLY token in Update.pl +* desire: cut confirmation replies (mode) +* desire: silent mode (learn only) + +rev 0.41.0 - 0.41.4 + +many minor things, mostly natural language, + some infrastructure. allowed "forget" to + end with final punctuation. +added factpack subdirectory. use these to + load up the bot with things. more to come. +fixed "addressing" -> REQUIRE. + +revision 0.41 + +added "karma". now "x++" or "x--" will change x's karma. + "karma for x" will show it's current standing. This + idea came from dkindred@cs.cmu.edu and his plusplus + Zephyr bot. Darrel Kindred is the mastermind here; + I just liked the idea and added it. +added e mode in userfile to expose eval. this is not + recommended. requires a crypted pass, then + /msg bot eval + +revision 0.40.1 + +replaced default userfile and fixed a tiny bit of NL where + it would say "OK" even when X already was Y. +the next rev will be the one for MacPerl etc., i hope. this + was just a quick fix because 0.40 wasn't letting people + teach by default. + +revision 0.40 + +several small fixes -- fixed a big with article deletion, + made it so it doesn't echo when told to die by a non-master, + fixed a few NL things, removed the CTCP die command. +Mailing list opens. +I plan one more rev to make sure this pre-version works + with MacPerl, then we'll switch to the new model. + +revision 0.39 + +integrated wf's changes with my own NL stuff from + purl exploits. this is a quick-turnaround rev to + get things in place for an upcoming major rev. +since nslookup, etc are now keyworded, removed + ipmatch and dmatch regexen from their preconditions. +added param for default signoff message + +revision 0.38 + +user system reworked flags are settable to limit + access to the bot's features. Examples can + be found in files/userfile.txt. +non-blocking sockets added to allow use of DCC + and other various functions to come soon. + +revision 0.37 + +Standalone mode works again after an oops in the +hooks by wildy... :) + +revision 0.36 + +NL stuff, some fixes from purl. + +revision 0.35 + +new option; multiline factoids. you can use the + following syntax to teach infobot facts on + multiple lines: + infobot: something is + anything said from there on will be recorded + as part of the fact. make sure you designate + the end of the fact or it will continue adding + everything you say into the fact. + + this will end the fact and store it in the db. + made MLFs work with repeatIgnoreInterval to prevent + some nasty abuse potential; added status + line for repeat ignore + +revision 0.34 + +fixed the addressing bug found in Irc.pl +removed the "okay" message when it doesn't replace + a key with the same message; this makes it nicer + when more than one is on the same channel, though + they still all reply +changed the default params to make urls optional +fixed the "the" bug, and expanded the "can" grammar + to handle cases more flexibly. +undid some bug that were introduced in handing the + code back and forth +folded in code that got out of sync in parallel revs. + +revision 0.33.3 + +added the formatting of public channel messages and + changed the hook code to be a bit more sane + +revision 0.33.2 + +re changed infobot to OPTIONAL listening/learning + instead of just url's as default + +revision 0.33.1 + +added a few irc operator things in param file +fixed the math routines +commented out the dotwise domain thing in Question.pl + because its regex didn't function correctly, etc + maybe just use the one nslookup so it doesnt get + confused with messages. + +cleaned up for a hopefully stable-ish 0.33 + +revision 0.32b + +infobot doesn't require perl 5.004 anymore, you + can run safely with perl 5.001 i'm pretty sure. +added support for ANSI Color -- enjoy, you + can turn this on/off in the params file. also + might ansi-fy a few more parts. not much though. +fixed bugs with irc code where infobot + couldn't join &channels (local) or channels + with weird things like '!'. +-patrick + +fixed the :) bug +fixed non-default param file to files/irc.params +-kevin + +revision 0.31b + +ok, reintegrating the irc modules. +re-added $nuh support so that users can use their + passwords, etc. +made numbers with more than 16 digits "a very big + number" in the math handling. +it's indentation wars! now that the tabs are gone, + most things indent nicely. +cut out a few vestigial lines from the inlet code, + such as the hard-coded dbs (not used now anyway). +i'm still torn about the copyright/license thing. have + to figure out how to handle that. +changed the default nick back the Newbie. +removed the #$%#$% param db that was bugging me so + much. just read in the param file and be + happy. +renamed "run_infobots.pl" to "run_if_needed.pl" and + made a couple of minor changes in it. + + +revision 0.30b + +thanks, patrick! Patrick Cole (wildfire) did + everything for rev 029b... many many thanks. +made the irc version the default +changed the default server to cmu +changed the default channel to #infobot +will do more in the near future... +NOTE infobot now requires perl 5.004 + + +revision 0.29b + +the first and greatest appearance of the inlet code rolled + into infobot. new look makes it easier to see what's + going on and gives it a greater feel to it. All irc + code rewritten by Patrick Cole graciously +added a traceroute command for lazy people, etc +nslookup for domain lookups +reindented all the code by hand (ugh) because it was in an + "Eight Megs and Constantly Swapping" kind of way :) +infobot can now reconnect split servers ... + "/ctcp infobot autorecon on" +internic whois querys should work now hopefully + + +revision 0.28b + +the first appearance of "curl", the command-line url. + useful for one-line queries and updates of the db. + not as full-featured as the standalone url -- + these will probably merge. +fixed a minor bug in writeParamFile +woops. it was set to userLevel > 100 for the eval + instead of >= 100. + + +revision 0.27b + +aha! there was a bug in the argument parser; used pop + instead of shift. this ought to work better now. +added absolute path to url in in4m. use this if you're + going to invoke url from anywhere other than the + home directory. +cleaned up in4m (top level) somewhat +added mkpasswd and ckpasswd in anticipation of userlevels +added writeParamFile in urlParams.pl. I still would like + to get away from the param db and just read and write + a flat file. +allowed $date, $time variables in values, e.g. "date is $date" +allowed \i \me \my in values that prevents "person-switching", + e.g. "x is go ahead and tell \me" so it doesn't turn me + into "in4m" or whatever on output +moved $safeWho generation into &purifyNick, which makes a + nick safe to use in a regex (among other things). it + really just removes 'bad' characters. +lifted the 'forget' code above most of the text processing + so it's more wysiwyf ('what you see is what you forget'). +stamped out what i hope is the last nick bracket bug +lifted the normalize query and switch person calls into urlQuestion + so that they don't cause weird interaction problems +fixed a bug in 'you' (in switchPerson) referring to the bot +added a 'chomp' on reading init files to keep out extra \n's +added more stuff in urlUser.pl +removed the secretWord potential nightmare and replaced it + with the userlist potential nightmare +addusers, readUserFile, writeUserFile, ckuser, users, etc + etc. in urlUser.pl +userList parameter in irc.params, standalone.params +userlevel 100 exposes eval (!), userlevel 10 lets you + override the 'REQUIRE' option for urls. come to + think of it, REQUIRE could be a number... +allowed 'allowUrls' to be a number, in which case it is + interpreted as the min userlevel to enter a non-url + + +revision 0.26b + +added a '' prepended tag to allow simple responses + (thanks, scuzzi_) +made the default behaviour not to whine about things that + are already defined (...but x is y...) unless addressed + which makes it nicer when more than one are on the same + channel + + +revision 0.25b + +mucked around with run_infobots.pl to get it working with + cron more obviously +urlProcess had an old-style %params ; changed to %param +moved a check for null paramfile names into loadParams loop +fixed a bracketing error that led to irc mode overriding +made it optional to use the parameter dbm; it's actually + reasonable to just read the irc.params file only + and not go for the "persistant parameters" + + +revision 0.24b + +added a "commitDBM every Nth transaction" form of the parameter +made dbm retry 10 times to open if it fails +changed the default standalone params to point to the right files dir +added a 'usage' output to dump_db to match make_db +added param allowLeave, which lets people make the bot leave a chan +changed the top-level name to just in4m. +added args to the command line: -p, -i, -s, -h +added a src/myRoutines.pl file so people can customize easily + + +revision 0.23b + +fixed dump_db :/ silly me +fixed another little problem in urlDBM.pl + + +revision 0.22b + +set up params as a db. it's still a hack and needs work, + but it allows for persistant params that you can set + within a session. +fixed various problems in referring to the right dbs +removed gratuitous accesses to the dbs +exposed more stuff in the standalone version. see standalone.txt. +set up initialization of dbs within in4m.pl +removed RUN_ME_FIRST +changed %params to %param to make set look nicer +moved make_db and dump_db into scripts/ subdir + and cleaned them up slightly +renamed params/ to files/ +made a doc dir and put the README for standalone in there +added 'where is x at' form (thanks, scuzzi) + + +revision 0.21b + +got rid of the question count access to the db. +made -w happier. someday i'll make -s happy too. +added parameter files to make life better. +the first appearance of the standalone desktop interactive + version that doesn't depend on irc. +added params and hooks for the standalone version. +params{nick} behaviour made consistant (urlSetup was overriding). +@allowed_channels fixed to $params{'allowed_channels'}. +fixed the if (($params{'addressing'} eq 'REQUIRE') && $addressed) + to !addressed in urlStatement (thanks again, cburnett). +made it open and close dbm files on each update unless + told otherwise. some implementations did not guarantee + commit. you can check your implementation and set + this to null or something else if you have a smart dbm. +added params for maxKeyLength and maxDataLength. +added params and fixed the help files. help files are + still ugly in the standalone mode. +added allowUpdate parameter so you can have strictly answerbots; + this will tie in to having restricted lists of users + levels. +made it so by default the irc version has no output. turn + up the debug level if you need more insight into what's + going in. + + +revision 0.20b + +this was a quick rev. +fixed some of the gratuitous named stuff in urlProcess.pl +made it so dns wouldn't try to fork under macperl +got the tracking back up + + +revision 0.19b: + +changed the default db's to be infobot-is and infobot-are +changed RUN_ME_FIRST to deal with that and renamed the .txt files +made a wantNick param +make it so dbs are created if don't exist (as option) +fixed $addressed so it didn't just look for prefixes +fixed a couple of the parameters that weren't referring to the hash +changed $urlCount to $factoidCount + + +revision 0.18b: + +moved a bunch of params into the global hash %params +added ¶ms so people can see the settings + e.g. /msg in4m mysecretword ¶ms(); +added some parameters up-front for server, port, etc. +changed the bad nickname code +the burnett fix (:$realname) +added infobot.help as a default help file + diff --git a/conf/infobot-are.txt b/conf/infobot-are.txt new file mode 100644 index 0000000..42317d6 --- /dev/null +++ b/conf/infobot-are.txt @@ -0,0 +1,2 @@ +roses => red +violets => blue diff --git a/conf/infobot-is.txt b/conf/infobot-is.txt new file mode 100644 index 0000000..53b2151 --- /dev/null +++ b/conf/infobot-is.txt @@ -0,0 +1,2 @@ +oznoid => at mailto:lenzo@cs.cmu.edu or at http://www.cs.cmu.edu/~lenzo +infobot => at http://www.cs.cmu.edu/~infobot diff --git a/conf/infobot.channels b/conf/infobot.channels new file mode 100644 index 0000000..da40c27 --- /dev/null +++ b/conf/infobot.channels @@ -0,0 +1,10 @@ +# Channel File (c) 1999 Infobot & Associates + +ChannelEntry #test { + fallback yes; + addressing REQUIRE; + shutup TRUE; + msgonly TRUE; + continuity 0; +} + diff --git a/conf/infobot.config b/conf/infobot.config new file mode 100644 index 0000000..f4132c3 --- /dev/null +++ b/conf/infobot.config @@ -0,0 +1,256 @@ +# parameter settings file for the infobot +# kevin lenzo (lenzo@cs.cmu.edu) + +# note: +# '$var' means a parameter that has been named; it is interpolated. +# By convention, things with '.ext' (extensions) are text files, and +# things with hyphens in them are DBM file prefixes, used for run-time +# learning or state maintenance. +# +# Nota Bene: Comment out attributes you don't want. Note that the +# word "false" is actually a true value! use 0 or comment +# out options you don't want. + +# the internal name for this bot +ident xpubbot + +# the nickname we want +wantNick $ident + +# the prefix of the dbm files +dbname $ident + +# where to put logging info +logfile $dbname.log + +# plusplus, an idea hijacked from CMU zephyr community, +# and dkindred++ in particular. Otherwise known +# as 'karma'. this is persistant between shutdowns. + +plusplus $dbname-karma + +# persistant "seen" db +seen $dbname-seen + +# do we have an ignore database? uncomment this if not. +ignore $dbname-ignore + +# should we ALWAYS close and reopen dbm on update? +# some systems don't do commitment until quit. +# +# 0 => never force sync +# 1 => force sync on every update +# N => force sync every Nth update + +commitDBM 5 + +# Explicitly set the database module. The default is AnyDBM_File. If +# you want to use any shared database files (via sharedDBMs) you have to +# set this to DB_File. + +#DBMModule DB_File + +# Specify an extension which should be added to all database names. By +# default this is empty. + +#DBMExt .db + +# Specify which databases will be shared among multiple infobots on the +# same machine, and so require locking. By default none are shared. If +# you use this at all you have to set DBMModule to DB_File. This can be +# a list of database names, or /all (which means every database), or +# /all-but-ignore (which means every database except the ignore list). +# +# As of this writing, the databases are: +# +# is main database, for singular factoids +# are main database, for plural factoids +# ignore ignored nicks and user/host patterns +# plusplus karma +# seen last seen info by each nick + +#sharedDBMs is are plusplus +#sharedDBMs /all +#sharedDBMs /all-but-ignore + +# X is Y +# max length of X (the key, +# the 'left hand side' (LHS) of an assignment, +# or the first argument) + +maxKeySize 50 + + +# max length of Y (value or data, the 'right hand side', or 2nd argument) +maxDataSize 400 + +# REQUIRE, OPTIONAL, REJECT for different behaviour with URLs +# REQUIRE means it will need to be a url type (e.g. file:, http:) +# OPTIONAL will take anything +# REJECT will not accept any urls. this makes it easy to +# run 2 with different nicks and styles. + +acceptUrl OPTIONAL + +# IRC-related params +ircuser $ident +realname $ident +# server irc.infobot.org +server irc.freenode.net +port 6667 +allowed_channels #xpub #infobot #$ident #test + +# channels to join +# use #channel,key (thanks to tile++) for keyed channels + +# join_channels #infobot #$ident +join_channels #xpub + +# server password, if needed +# server_pass myserverpassword + +# vhost support... if you have a vhost, you can use this, +# otherwise it won't work. +# inm++, elph++ for this :) +# vhost_name f00.bar.org + +# nickServ_pass foo +# chanServ_pass bar + +# addressing is when you name the bot. if this is REQUIRE, +# the bot should only speak when spoken to. BUT it may listen. +# anything else will mean it can barge in when it thinks it +# knows something. +# "shutup" determines whether you can switch modes on the +# fly with the bot. if you use REQUIRE for addressing, you +# probably want to comment out the shutup line. + +addressing OPTIONAL +# shutup TRUE + +# ansi screen control is available from 0.32 onwards +# value of 1 means to use ANSI, 0 means generic bold +ansi_control 1 + +# things we may or may not want to allow. 1 = allow, 0 otherwise. +# do you want to be a desktop calc? +perlMath 1 +fortranMath 0 + +# do you want to allow DNS lookup/Internic/Traceroute? +allowDNS 1 +allowTraceroute 1 +allowInternic 1 + +# ord/chr etc +allowConv 1 + +# tell so-and-so about such-and-such +allowTelling 1 + +# let any old joe update stuff. if this is 0, you'll have to +# either change some code, do everything with e.g. update_db, +# or do something else arcane to get factoids in. +allowUpdate 1 + +# How much verbage to display on the console +VERBOSITY 1 + +# the magic hack word to unignore everyone +unignoreWord unignore-everyone + +# where configuration and help files and such live, the default is the +# files subdir of the main directory +confdir conf + +# my help file. this will get confdir prepended +# you may want to change this to $ident.help + +helpfile infobot.help + +srcdir src +extradir extras + +# within how long of getting the same reply should +# we not respond (irc mode only). in seconds. + +repeatIgnoreInterval 8 + +# in what contexts do we let people make the bot leave a +# channel (this is an or'd list; public private) + +allowLeave public + +# our user list default file (in miscdir) +# you may want to change this to $ident.users + +userList infobot.users + +# channel list, specifies options which differ from the defaults, by +# channel. + +channelList infobot.channels + +# default quit message +quitMsg regrouping; bbiab + + +# how long does something have to be before we'll just volunteer +# the answer without a question mark, question, or being addressed +minVolunteerLength 8 + +# other bots to ask for help + +# friendlyBots url purl script mrapi + +# sane defines that ALWAYS overwrite existing values at startup +# this is a prefix for the files (sane-is.txt, sane-are.txt) + +sanePrefix sane + +# allow weather and METAR lookups, respectively. These should +# actually be turned into a user modes. mendel++. Require +# LWP and metar requires Geo::METAR. +weather true +metar true + +# babelfish translator. jdf++. requires LWP, not included. +babel true + +# slashdot headlines. requires LWP, not included. get it from CPAN. +slash true + +# insult and excuse servers +insult true +excuse true + +# google search.. simon++ . expanded to www search using several +# engines since it was so easy once you have WWW::Search. +# use "update" if you want it to update the db, or comment +# out if you don't want it. requires WWW::Search, not included. +# use "forceupdate" to force a db update on every google search. +wwwsearch update + +# general headline-getter. uses RDF. (LotR++) +rss true + +# purldoc perl documentation lookup DMasque++, HJ++ +purldoc true +purldoc_trigger purldoc +purldoc_max_public 3 + +# speller. requires the ispell program. +ispell true + +#zippy quotes (infobot, yow or infobot, be zippy) +zippy true + +# the magic 8ball (divine) +magic8_answers $miscdir/magic8.txt + +# exchange rates (exchange 233 DEM to USD) +exchange true + +# stock quotes +stockquotes true + diff --git a/conf/infobot.config-dist b/conf/infobot.config-dist new file mode 100644 index 0000000..e71a470 --- /dev/null +++ b/conf/infobot.config-dist @@ -0,0 +1,254 @@ +# parameter settings file for the infobot +# kevin lenzo (lenzo@cs.cmu.edu) + +# note: +# '$var' means a parameter that has been named; it is interpolated. +# By convention, things with '.ext' (extensions) are text files, and +# things with hyphens in them are DBM file prefixes, used for run-time +# learning or state maintenance. +# +# Nota Bene: Comment out attributes you don't want. Note that the +# word "false" is actually a true value! use 0 or comment +# out options you don't want. + +# the internal name for this bot +ident i-bot + +# the nickname we want +wantNick $ident + +# the prefix of the dbm files +dbname $ident + +# where to put logging info +logfile $dbname.log + +# plusplus, an idea hijacked from CMU zephyr community, +# and dkindred++ in particular. Otherwise known +# as 'karma'. this is persistant between shutdowns. + +plusplus $dbname-karma + +# persistant "seen" db +seen $dbname-seen + +# do we have an ignore database? uncomment this if not. +ignore $dbname-ignore + +# should we ALWAYS close and reopen dbm on update? +# some systems don't do commitment until quit. +# +# 0 => never force sync +# 1 => force sync on every update +# N => force sync every Nth update + +commitDBM 5 + +# Explicitly set the database module. The default is AnyDBM_File. If +# you want to use any shared database files (via sharedDBMs) you have to +# set this to DB_File. + +#DBMModule DB_File + +# Specify an extension which should be added to all database names. By +# default this is empty. + +#DBMExt .db + +# Specify which databases will be shared among multiple infobots on the +# same machine, and so require locking. By default none are shared. If +# you use this at all you have to set DBMModule to DB_File. This can be +# a list of database names, or /all (which means every database), or +# /all-but-ignore (which means every database except the ignore list). +# +# As of this writing, the databases are: +# +# is main database, for singular factoids +# are main database, for plural factoids +# ignore ignored nicks and user/host patterns +# plusplus karma +# seen last seen info by each nick + +#sharedDBMs is are plusplus +#sharedDBMs /all +#sharedDBMs /all-but-ignore + +# X is Y +# max length of X (the key, +# the 'left hand side' (LHS) of an assignment, +# or the first argument) + +maxKeySize 50 + + +# max length of Y (value or data, the 'right hand side', or 2nd argument) +maxDataSize 400 + +# REQUIRE, OPTIONAL, REJECT for different behaviour with URLs +# REQUIRE means it will need to be a url type (e.g. file:, http:) +# OPTIONAL will take anything +# REJECT will not accept any urls. this makes it easy to +# run 2 with different nicks and styles. + +acceptUrl OPTIONAL + +# IRC-related params +ircuser $ident +realname $ident +server irc.infobot.org +port 6667 +allowed_channels #infobot #$ident #test + +# channels to join +# use #channel,key (thanks to tile++) for keyed channels + +join_channels #infobot #$ident + +# server password, if needed +# server_pass myserverpassword + +# vhost support... if you have a vhost, you can use this, +# otherwise it won't work. +# inm++, elph++ for this :) +# vhost_name f00.bar.org + +# nickServ_pass foo +# chanServ_pass bar + +# addressing is when you name the bot. if this is REQUIRE, +# the bot should only speak when spoken to. BUT it may listen. +# anything else will mean it can barge in when it thinks it +# knows something. +# "shutup" determines whether you can switch modes on the +# fly with the bot. if you use REQUIRE for addressing, you +# probably want to comment out the shutup line. + +addressing OPTIONAL +# shutup TRUE + +# ansi screen control is available from 0.32 onwards +# value of 1 means to use ANSI, 0 means generic bold +ansi_control 1 + +# things we may or may not want to allow. 1 = allow, 0 otherwise. +# do you want to be a desktop calc? +perlMath 1 +fortranMath 0 + +# do you want to allow DNS lookup/Internic/Traceroute? +allowDNS 1 +allowTraceroute 1 +allowInternic 1 + +# ord/chr etc +allowConv 1 + +# tell so-and-so about such-and-such +allowTelling 1 + +# let any old joe update stuff. if this is 0, you'll have to +# either change some code, do everything with e.g. update_db, +# or do something else arcane to get factoids in. +allowUpdate 1 + +# How much verbage to display on the console +VERBOSITY 1 + +# the magic hack word to unignore everyone +unignoreWord unignore-everyone + +# where configuration and help files and such live, the default is the +# files subdir of the main directory +confdir conf + +# my help file. this will get confdir prepended +# you may want to change this to $ident.help + +helpfile infobot.help + +srcdir src +extradir extras + +# within how long of getting the same reply should +# we not respond (irc mode only). in seconds. + +repeatIgnoreInterval 8 + +# in what contexts do we let people make the bot leave a +# channel (this is an or'd list; public private) + +allowLeave public + +# our user list default file (in miscdir) +# you may want to change this to $ident.users + +userList infobot.users + +# channel list, specifies options which differ from the defaults, by +# channel. + +channelList infobot.channels + +# default quit message +quitMsg regrouping; bbiab + + +# how long does something have to be before we'll just volunteer +# the answer without a question mark, question, or being addressed +minVolunteerLength 8 + +# other bots to ask for help + +# friendlyBots url purl script mrapi + +# sane defines that ALWAYS overwrite existing values at startup +# this is a prefix for the files (sane-is.txt, sane-are.txt) + +sanePrefix sane + +# allow weather and METAR lookups, respectively. These should +# actually be turned into a user modes. mendel++. Require +# LWP and metar requires Geo::METAR. +weather true +metar true + +# babelfish translator. jdf++. requires LWP, not included. +babel true + +# slashdot headlines. requires LWP, not included. get it from CPAN. +slash true + +# insult and excuse servers +insult true +excuse true + +# google search.. simon++ . expanded to www search using several +# engines since it was so easy once you have WWW::Search. +# use "update" if you want it to update the db, or comment +# out if you don't want it. requires WWW::Search, not included. +# use "forceupdate" to force a db update on every google search. +wwwsearch update + +# general headline-getter. uses RDF. (LotR++) +rss true + +# purldoc perl documentation lookup DMasque++, HJ++ +purldoc true +purldoc_trigger purldoc +purldoc_max_public 3 + +# speller. requires the ispell program. +ispell true + +#zippy quotes (infobot, yow or infobot, be zippy) +zippy true + +# the magic 8ball (divine) +magic8_answers $miscdir/magic8.txt + +# exchange rates (exchange 233 DEM to USD) +exchange true + +# stock quotes +stockquotes true + diff --git a/conf/infobot.crontab b/conf/infobot.crontab new file mode 100644 index 0000000..8dd9541 --- /dev/null +++ b/conf/infobot.crontab @@ -0,0 +1,2 @@ +*/5 * * * * /usr/users/you/infobot0.1b/run_infobots.pl > /dev/null + diff --git a/conf/infobot.help b/conf/infobot.help new file mode 100644 index 0000000..4118090 --- /dev/null +++ b/conf/infobot.help @@ -0,0 +1,13 @@ +main: i learn mainly by observing declarative statements such as "x is at http://www.xxx.com", and then reply when people ask things like "where can i find x?" + +author: oznoid (mailto:lenzo@ri.cmu.edu) is my author. + +corrections: If I come back with "...but x is at http://xx.xx.xx" or something like that, and you want to change the entry, use "no, x is at http://sdfsdfsdf". The "No," tells me to supercede the existing value. +corrections: You can add to an entry with "also". "X is also at ..." + +reply: There is a special tag, , that is used to override the usual response. Usually, a response is "X is Y", but it can be made "Y" by making the entry "X is Y". +reply: This is a good way to close junk entries; use "X is " with nothing after it. + +alternation: The | symbol in an entry causes an infobot to choose one of the replies at random. "X is Y|Z" will produce "X is Y" or "X is Z" randomly. + +karma: Karma is a community rating system. use "X++" to increase the karma, or "X--" to decrease it. Ask for ratings using "karma for X?" diff --git a/conf/infobot.help-dist b/conf/infobot.help-dist new file mode 100644 index 0000000..4118090 --- /dev/null +++ b/conf/infobot.help-dist @@ -0,0 +1,13 @@ +main: i learn mainly by observing declarative statements such as "x is at http://www.xxx.com", and then reply when people ask things like "where can i find x?" + +author: oznoid (mailto:lenzo@ri.cmu.edu) is my author. + +corrections: If I come back with "...but x is at http://xx.xx.xx" or something like that, and you want to change the entry, use "no, x is at http://sdfsdfsdf". The "No," tells me to supercede the existing value. +corrections: You can add to an entry with "also". "X is also at ..." + +reply: There is a special tag, , that is used to override the usual response. Usually, a response is "X is Y", but it can be made "Y" by making the entry "X is Y". +reply: This is a good way to close junk entries; use "X is " with nothing after it. + +alternation: The | symbol in an entry causes an infobot to choose one of the replies at random. "X is Y|Z" will produce "X is Y" or "X is Z" randomly. + +karma: Karma is a community rating system. use "X++" to increase the karma, or "X--" to decrease it. Ask for ratings using "karma for X?" diff --git a/conf/infobot.users b/conf/infobot.users new file mode 100644 index 0000000..15163a4 --- /dev/null +++ b/conf/infobot.users @@ -0,0 +1,42 @@ +# +# User File (c) 1998 Infobot & Associates +# +# FLAGS +# ---------------------- +# i Ignored Flag +# f MLF Usage Allowed +# t Teaching Allowed +# r Removing Allowed +# m Modifying Allowed +# c Part/Join Allowed +# s Searching Allowed (possibly computationally expensive) +# S user can make bot Say things +# e Extra Privs [ not implemented robustly: AVOID ] +# p oP on channel by public request +# ---------------------- +# o Owner Flag +# ---------------------- +# +# recommended default user flags: +trmc + +UserEntry default { + flags +trmcs; +} + +# here's an example entry + +UserEntry oznoid { + name "Kevin A. Lenzo"; + title "that guy"; + flags +ftrmcsSope; + pass rrmrxB6U4ryRk; + mask *!lenzo@*.speech.cs.cmu.edu; +} + +UserEntry plonk { + name "Eep Malloy" + title "that guy II"; + flags +trmcspo; + pass rrmrxB6U4ryRk; + mask *!*@*.static.telerama.com +} diff --git a/conf/infobot.users-dist b/conf/infobot.users-dist new file mode 100644 index 0000000..15163a4 --- /dev/null +++ b/conf/infobot.users-dist @@ -0,0 +1,42 @@ +# +# User File (c) 1998 Infobot & Associates +# +# FLAGS +# ---------------------- +# i Ignored Flag +# f MLF Usage Allowed +# t Teaching Allowed +# r Removing Allowed +# m Modifying Allowed +# c Part/Join Allowed +# s Searching Allowed (possibly computationally expensive) +# S user can make bot Say things +# e Extra Privs [ not implemented robustly: AVOID ] +# p oP on channel by public request +# ---------------------- +# o Owner Flag +# ---------------------- +# +# recommended default user flags: +trmc + +UserEntry default { + flags +trmcs; +} + +# here's an example entry + +UserEntry oznoid { + name "Kevin A. Lenzo"; + title "that guy"; + flags +ftrmcsSope; + pass rrmrxB6U4ryRk; + mask *!lenzo@*.speech.cs.cmu.edu; +} + +UserEntry plonk { + name "Eep Malloy" + title "that guy II"; + flags +trmcspo; + pass rrmrxB6U4ryRk; + mask *!*@*.static.telerama.com +} diff --git a/conf/magic8.txt b/conf/magic8.txt new file mode 100644 index 0000000..5035756 --- /dev/null +++ b/conf/magic8.txt @@ -0,0 +1,44 @@ +original => Outlook Not So Good +original => My Reply Is No +original => Don't Count On It +original => You May Rely On It +original => Ask Again Later +original => Most Likely +original => Cannot Predict Now +original => Yes +original => Yes Definitely +original => Better Not Tell You Now +original => It Is Certain +original => Very Doubtful +original => It Is Decidedly So +original => Concentrate and Ask Again +original => Signs Point to Yes +original => My Sources Say No +original => Without a Doubt +original => Reply Hazy, Try Again +original => As I See It, Yes +sarcastic => NOT +sarcastic => What do YOU think +sarcastic => Obviously +sarcastic => Ask me if I care +sarcastic => Yeah, and I'm the Pope +sarcastic => That's ridiculous +sarcastic => Who cares +sarcastic => Forget about it +sarcastic => You wish +sarcastic => Yeah, right +sarcastic => Sure +sarcastic => Get a clue +sarcastic => In your dreams +sarcastic => Oh, please +sarcastic => Whatever +sarcastic => As if +sarcastic => You've got to be kidding +sarcastic => Dumb question. Ask another +sarcastic => Not a chance +userdef => Outlook Sucks +userdef => THIS SPACE FOR RENT +userdef => Bugger Off +userdef => How appropriate, you fight like a cow +userdef => Eat more cheese, then ask again +userdef => When hell freezes over diff --git a/conf/sane-are.txt b/conf/sane-are.txt new file mode 100644 index 0000000..411b10b --- /dev/null +++ b/conf/sane-are.txt @@ -0,0 +1,6 @@ +what => +who => +when => +where => +why => +it => diff --git a/conf/sane-ignore.txt b/conf/sane-ignore.txt new file mode 100644 index 0000000..6cd1104 --- /dev/null +++ b/conf/sane-ignore.txt @@ -0,0 +1,3 @@ +*cthulhu!hastur@*unspeakable.net # an example nick!user@host ban +*!*@*nan*direct.ca +*!*@200.38.211.* diff --git a/conf/sane-is.txt b/conf/sane-is.txt new file mode 100644 index 0000000..3a8f8eb --- /dev/null +++ b/conf/sane-is.txt @@ -0,0 +1,8 @@ +what => +who => +when => +where => +why => +it => +how => +infobot guide => http://www.cs.cmu.edu/~infobot/infobot_guide.html diff --git a/doc/how_to_fix_files_uploaded_from_windows_to_unix.txt b/doc/how_to_fix_files_uploaded_from_windows_to_unix.txt new file mode 100644 index 0000000..918c2df --- /dev/null +++ b/doc/how_to_fix_files_uploaded_from_windows_to_unix.txt @@ -0,0 +1,37 @@ +FIXING PERL AND TEXT FILES THAT HAVE BEEN UPLOADED FROM WINDOWS + +OK when you upload a file from Windows, it contains all +these nasty control-M's on each line that screw everything +up. + +To see them, use + + cat -vet + +where is the name of some file you want to check. +You should see the control-M's. + +To get rid of them, use + + perl -pi -e 's/\cM//g' + +while is the file name. This does an in-place edit +that removes all the control-Ms. You can do this to a bunch +of files at once: + + perl -pi -e 's/\cM//g' + +or even + + perl -pi -e 's/\cM//g' * + +if all the files in the directory are text (like they ARE in +the files/ directory of the infobot). + + perl -pi -e 's/\cM//g' files/* src/* infobot + +from inside the infobot directory should clean everything up. +You should also clean any factpacks or factoid files or logs +that you use for processing. + +kevin diff --git a/doc/infobot_guide.html b/doc/infobot_guide.html new file mode 100644 index 0000000..8615a42 --- /dev/null +++ b/doc/infobot_guide.html @@ -0,0 +1,652 @@ + + + + + Infobot Guide 0.44.3 + + + +

Infobot Guide 0.44.3

+ +
+The canonical source for the infobot source and documentation is +http://www.cs.cmu.edu/~infobot. +
+

+The infobot connects to an Internet Relay Chat (IRC) server, +joins some channels (maybe), and begins accumulating factoids. +To run one, download the source, uncompress it, untar it, +edit the config files, and it up. +

+Interacting with the bot is pretty straightforward. Most of +the commands and variables available to users are listed below. +The bot will interact via message or on-channel. +

+ +


+

Interacting with an infobot

+ +
    +
  • setting factoids: X is Y +

    + Saying something like "X is Y" somewhere that the infobot + can see it will cause the bot to store a factoid, unless + X is already defined. It sets the value of X to Y. +

    +

  • accessing factoids: What is X? +

    + You can ask an infobot about something in a number of + different ways, including "what is X?", "where is X?", + or just plain "X?". +

    +
  • altering factoids: s/A/B/ +

    + if you just want to change a part of a factoid, use + the s///operator. you have to address the bot + or use a private medium to do this. +

    + MyBot, X =~ s/A/B/ +

    + will change the first occurence of A to B in the factoid + called X. +

    + +

  • appending to existing entries: also +

    + One can extend an existing factoid using the + keyword also +

    +

      + + poink is also a silly word + +
    +

    + +

  • erasing a factoid: forget +

    + A factoid can easily be deleted by using +

    +

    + + infobot, forget poink + + +

    + +

  • changing a factoid: no, ... +

    + You can change the entry for a factoid completely using +

    +

      + + no, infobot, x is wugga wugga. + +
    +

    + which deletes the prior entry (if possible) + and replaces it with the new one. +

    + +

  • having the bot tell someone else something: tell +

    + A user can ask an infobot to tell someone else something. +

    +

      + + infobot, tell fimmtiu about no web + +

      +

    + +
  • karma / plusplus +

    + karma for a concept may be incremented or decremeted using + ++ and --. You can get the + current karma 'score' for something by asking for it. +

    +

      + + oznoid++ +

      + oznoid-- +

      + karma for oznoid + +

      +

    + +
  • status +

    + infobots reply to status requests. +

    +

    + -> [url] status

    + [url!infobot@ALF5.SPEECH.CS.CMU.EDU] Since Fri Mar 26 06:42:27 1999, there have been 409 + modifications and 2604 questions. I have been awake for 5 days, 4 hours, 24 minutes, + 18 seconds this session, and currently reference 47529 factoids. +

    + +

    + +
  • joining an allowed channel: join #infobot +

    + On IRC, you can tell the infobot to join a channel + that it's allowed to join with +

    +

      + + infobot, join #infobot + +
    +

    + If it is allowed to (in its paramter settings), it + will try to join the channel. +

    + + +

  • leaving a channel: part #infobot +

    + This causes the bot to leave the given channel +

    +

      + + infobot, part #infobot + +
    +

    + leave is a synonym for part. +

    + +

  • random responses with | +

    + You can set a list from which to pick a random response by + using | +

    +

      + + x is a|b|c|d + +
    +

    + When x is asked about, the infobot will randomly choose from + the |-spearated list. +

    + +

  • The <reply> factoid tag. +

    + Normally, when the infobot replies to "What is X", it says + "X is Y". This form makes it just reply "Y". +

    +

      + + X is <reply> Y + +
    +

    + +

  • The <action> factoid tag (as of 0.43.5) +

    + This causes the bot to respond as with except + as an ACTION. +

    +

      + + X is <action> Y + +
    +

    + +

  • backwacking +

    + Use \ to protect items from evaluation. +

    +

      + + x is y is y + +
    +

    + will normally set x =is=> y is y, but +

    +

      + + x \is y is y + +
    +

    + will set +

    +

      + x is y =is=> y +
    +

    + The forget + and no (update) operators apply before checking + for this. This is also useful for getting around the + dereferencing of "i" and "me" and so on. +

    + +

  • the $who variable +

    + Contains the nickname person currently addressing the bot. + It can be used effectively in replies. +

    +

      + + nice day is <reply> you betcha, $who. + +
    +

    + +

  • the $date variable +

    + Contains the current date and time, at the bot's host. +

    + +

  • weather for KAGC (0.43.6+) +

    + Retrieves the weather from NOAA station KAGC. See www.noaa.gov. + Note: Requires LWP. +

    +

      +
    • metar KAGC (0.43.6+) +
    +

    + Retrieves METAR info from NOAA station KAGC. See www.noaa.gov. + Note: Requires Geo::METAR and LWP. +

    +

  • nslookup irc.cs.cmu.edu +

    + performs DNS lookup or reverse-lookup on the hostname or IP. +

    +

  • internic yahoo.com +

    + gets the internic WHOIS record +

    +

  • traceroute apple.com +

    + gets the traceroute results from the bot's machine to the target machine. Summary only. +

    +

  • imdb, websters, foldoc +

    + outputs a well-formed url for a search of IMDB (the Internet Movie DataBase), the Webster's 1913 dictionary, or the foldoc dictionary of geek terms. +

    +

      + + imdb for clerks

      + webster for lucre + +

    + +

    + +

  • New in 0.44.3: +

    +

      +
    • literal foo +

      + returns the value without the usual post-processing. +

      +
    • change 100 USD to DEM +

      + converts currency. Retrieves the current exchange rates from the net. + Requires LWP. +

      +
    • <rss="http://www.foo.com/summary.rss"> +

      + looks up the RSS file (RDF Site Summary) and returns it + in-place where the tag is. Requires XML::RSS and LWP. +

      +
    • give me an excuse, or excuse +

      + connects to the excuse server and returns an excuse. + requires Net::Telnet. +

      +
    +

    + +

  • Ignoring users: ignore nickname, ignore *.a.com +

    + Users with the P (oP) flag can tell the bot + to ignore people or hostmasks. And 'unignore'. + use 'ignorelist' to get the current list of ignored masks, + if you have the P flag. +

    +
  • op on channel +

    + The 'p' (oP) flag in the userfile allows this + to work. You'll need to set a hostmask. See + files/infobot.users Also uses a + crypted password. +

    +

    + + /msg <bot> <password> op + + +

    +

  • die +

    + If the bot owner (+O, Owner) says this or messages it to the bot, + it will kill itself. +

    +

+ +
+

scripts/utilities

+ + The infobot comes with some scripts for working with + the DBM files. +

+ +

    +
  • update_db +

    + This takes a flat ascii file and inserts it into a DBM file. + It creates a new DBM if it didn't exist. +

    +

      + + scripts/update_db factpacks/code_to_country.txt infobot-is + +
    +

    + will add the factoids in code_to_country.txt + to the infobot-is DBM. +

    + If you've set DBMModule in your config file, you + need to use the -m switch to specify the alternate + module. +

    +

      + + scripts/update_db -d DB_File factpacks/code_to_country.txt infobot-is + +
    +

    +

  • dump_db +

    + The converse. It dumps out the DBM file to a flat + ascii file. Note there is no extension on the DBM name, + even though the system may use one. +

    +

      + + scripts/dump_db infobot-is + +
    +

    + Note there is no extension on the DBM name, even though the + system may use one (like .pag and + .dir or .db). +

    + If you've set DBMModule in your config file, you + need to use the -m switch to specify the alternate + module. +

    +

      + + scripts/dump_db -m DB_File infobot-is + +
    +

    + +

+ +
+ +

add-on modules

+ +
    +
  • nickometer, by Adam Spiers. Guages + how 'lame' a nickname is, as a percentage!

    +

      + + nickometer l33tn1ck + +
    +

    + +

  • babel.pl by jdf. translates using the + babelfish + web site for machine translation. + In this implementation, English is assumed + to be the 'main' language, thus everything is + translated to or from another + language. +

    +

      + + (x|translate) (to|from) (de|fr|pt|es|it|german|french|portugese|spanish|italian) +

      + translate to german this is a test
      + x to german this is another test
      + x to de and a third
      + x from de ein bisschen Deutsch

      + German, French, Spanish, Italian, and Portugese are + currently supported by babelfish. + +

    +

    +

  • METAR support, courtesy of mendel

    + metar KAGC +

    + retrieves METAR information for KAGC, the Allegheny + County airport station. +

    +

  • NOAA weather station support, courtesy of oznoid

    +

      + weather KAGC +
    +

    + retrieves the + NOAA + weather information from (in this example) KAGC. uses the + same + codes + as metar info. +

    +

  • slashdot headlines, originally from Chris Tessone, + current version from Rahga.

    +

    +

      + slashdot
      + slashdot headlines +
    +

    + retrieves the current slashdot headlines from + www.slashdot.org. + +

  • W3Search: search web engines for links; thanks + to Simon Couzins for this one. Requires + WWW::Search and WWW::Search::Google. +
      + search google for foo
      + google for foo
      + altavista for foo
      + dejanews for foo +
    + Currently supports what WWW::Search and WWW::Search::Google + support, namely: Dejanews, Google, Gopher, Excite, Infoseek, + HotBot, Lycos, AltaVista, Magellan, PLweb, SFgate, and Verity. +

    +

  • US Airways In-flight info. +
      + usair flight 781 +
    + retrieves the in-flight information for the + appropriate USAir flight. Note: Requires LWP. +
+ +
+ +

setting up

+ +

configuration

+
    +
  • editing the parameter file +

    + + The parameter file, usually in files/infobot.config, + is the most direct way to customize the settings on your infobot. +

    + +

  • editing the user file +

    + + The user file, usually in files/infobot.users, + is the most direct way to customize the settings on your infobot. +

    + + +

  • editing the main script +

    + + There are certain items you may need to fiddle with + in the main script of the infobot, but normally you + shouldn't have to. The usual reasons are +

    +

      +
    • changing the bang path to perl +

      + If you get +

      +

        + + infobot: Command not found. + +
      +

      + or something like it, you need to edit the infobot + script at the top level directory (the script named + 'infobot') and set the path to you perl interpreter + in the very first line of the script to +

      +

        + + #!/path/to/perl + +
      +

      + with, of course, the full path to your perl binary. +

      + +

    • explicitly setting normally relative paths +

      + If you don't have . in your path, you will probably + need to set some variables explicitly that are normally + determined relative to the infobot script. This is + done in the 'infobot' script. +

      +

    +
  • Installing Modules to enable features +

    + Several add-ons, like weather and + web search require perl modules to + be installed. The easiest way to get all the + things you need is to install the CPAN.pm module, + available from CPAN, and use it to install what you need. This + is best done as root.

    + Once you have the CPAN module installed, use + it to install the required modules: +

    +

      +
    • the main thing: install Bundle::LWP +
    • for METAR: install Geo::METAR +
    • for W3Search: +
        +
      • install WWW::Search +
      • install WWW::Search::Google +
      +
    + Once these are installed, start or restart your infobot. +
+

+ +


+ +

running the infobot

+ +
    +
  • starting it up +

    + This should be as simple as entering the infobot + parent directory and executing +

    +

      + + infobot + +
    +

    + + This starts up the script and generates a whole lot of text. + It's useful and interesting to see what's going on "in the + infobot's head". You can control the amount of verbage + that comes out with the VERBOSITY parameter, + of you can dump all the output to the bitbucket and background + the process at the same time with +

    +

      + + nohup infobot > /dev/null & + +
    +

    + +

  • the console +

    + Should you choose to look at the stream if consciousness + in the bot, and you haven't reduced the output to nothing + or consigned it to the void, you will be presented with + the console. + +

    + The first thing you should see, assuming all goes well with + making a connection, is the motd (message-of-the-day) + of the server the bot has been configured to connect to. +

    + Next, you should see the result of the channel joins specified + in the parameter files, and you may see the bot recognizing + hostmasks of people in the userfile, if any have been put + in there. +

    + If you have the ansi_control paramter set, + and your terminal supports it, the output will be in color. +

    + NOTE that the 'console' is NOT interactive. You can't + type anything into it; it's just for viewing what's going on. +

    +

  • cronning the infobot +

    + You can set the infobot to automatically start up using + cron. See the included example crontab + file, in files/infobot.crontab +

+
+ +

shutting it down

+ + If you have set yourself as the bot's master in the user file + (infobot.users, unless you changed the default), + you can just say or message 'die' to the bot. +

+ Otherwise, kill the process or hit control-c in the console. +

+ +


+ +

the FAQ

+ The FAQ is available at + + http://www.cs.cmu.edu/~infobot/faq/. It is growing. Slowly. + +
+
infobot@protected.speech.cs.cmu.edu
+ + +Last modified: Tue Oct 26 14:24:41 EDT 1999 + + + diff --git a/doc/intro.bit b/doc/intro.bit new file mode 100644 index 0000000..aa6d10a --- /dev/null +++ b/doc/intro.bit @@ -0,0 +1,312 @@ +
+The canonical source for the infobot source and documentation is +http://www.infobot.org/. +
+

+The infobot connects to an Internet Relay Chat (IRC) server, +joins some channels (maybe), and begins accumulating factoids. +To run one, download the source, uncompress it, untar it, +edit the config files, and it up. +

+Interacting with the bot is pretty straightforward. Most of +the commands and variables available to users are listed below. +The bot will interact via message or on-channel. +

+ +


+

Interacting with an infobot

+ +
    +
  • setting factoids: X is Y +

    + Saying something like "X is Y" somewhere that the infobot + can see it will cause the bot to store a factoid, unless + X is already defined. It sets the value of X to Y. +

    +

  • accessing factoids: What is X? +

    + You can ask an infobot about something in a number of + different ways, including "what is X?", "where is X?", + or just plain "X?". +

    +
  • altering factoids: s/A/B/ +

    + if you just want to change a part of a factoid, use + the s///operator. you have to address the bot + or use a private medium to do this. +

    + MyBot, X =~ s/A/B/ +

    + will change the first occurence of A to B in the factoid + called X. +

    + +

  • appending to existing entries: also +

    + One can extend an existing factoid using the + keyword also +

    +

      + + poink is also a silly word + +
    +

    + +

  • erasing a factoid: forget +

    + A factoid can easily be deleted by using +

    +

    + + infobot, forget poink + + +

    + +

  • changing a factoid: no, ... +

    + You can change the entry for a factoid completely using +

    +

      + + no, infobot, x is wugga wugga. + +
    +

    + which deletes the prior entry (if possible) + and replaces it with the new one. +

    + +

  • having the bot tell someone else something: tell +

    + A user can ask an infobot to tell someone else something. +

    +

      + + infobot, tell fimmtiu about no web + +

      +

    + +
  • karma / plusplus +

    + karma for a concept may be incremented or decremeted using + ++ and --. You can get the + current karma 'score' for something by asking for it. +

    +

      + + oznoid++ +

      + oznoid-- +

      + karma for oznoid + +

      +

    + +
  • status +

    + infobots reply to status requests. +

    +

    + -> [url] status

    + [url!infobot@ALF5.SPEECH.CS.CMU.EDU] Since Fri Mar 26 06:42:27 1999, there have been 409 + modifications and 2604 questions. I have been awake for 5 days, 4 hours, 24 minutes, + 18 seconds this session, and currently reference 47529 factoids. +

    + +

    + +
  • joining an allowed channel: join #infobot +

    + On IRC, you can tell the infobot to join a channel + that it's allowed to join with +

    +

      + + infobot, join #infobot + +
    +

    + If it is allowed to (in its paramter settings), it + will try to join the channel. +

    + + +

  • leaving a channel: part #infobot +

    + This causes the bot to leave the given channel +

    +

      + + infobot, part #infobot + +
    +

    + leave is a synonym for part. +

    + +

  • random responses with | +

    + You can set a list from which to pick a random response by + using | +

    +

      + + x is a|b|c|d + +
    +

    + When x is asked about, the infobot will randomly choose from + the |-spearated list. +

    + +

  • The <reply> factoid tag. +

    + Normally, when the infobot replies to "What is X", it says + "X is Y". This form makes it just reply "Y". +

    +

      + + X is <reply> Y + +
    +

    + +

  • The <action> factoid tag (as of 0.43.5) +

    + This causes the bot to respond as with except + as an ACTION. +

    +

      + + X is <action> Y + +
    +

    + +

  • backwacking +

    + Use \ to protect items from evaluation. +

    +

      + + x is y is y + +
    +

    + will normally set x =is=> y is y, but +

    +

      + + x \is y is y + +
    +

    + will set +

    +

      + x is y =is=> y +
    +

    + The forget + and no (update) operators apply before checking + for this. This is also useful for getting around the + dereferencing of "i" and "me" and so on. +

    + +

  • the $who variable +

    + Contains the nickname person currently addressing the bot. + It can be used effectively in replies. +

    +

      + + nice day is <reply> you betcha, $who. + +
    +

    + +

  • the $date variable +

    + Contains the current date and time, at the bot's host. +

    + +

  • literal foo +

    + returns the value without the usual post-processing. +

    +

    + +

  • Ignoring users: ignore nickname, ignore *.a.com +

    + Users with the P (oP) flag can tell the bot + to ignore people or hostmasks. And 'unignore'. + use 'ignorelist' to get the current list of ignored masks, + if you have the P flag. +

    +
  • op on channel +

    + The 'p' (oP) flag in the userfile allows this + to work. You'll need to set a hostmask. See + files/infobot.users Also uses a + crypted password. +

    +

    + + /msg <bot> <password> op + + +

    +

  • die +

    + If the bot owner (+O, Owner) says this or messages it to the bot, + it will kill itself. +

    +

+ +
+

scripts/utilities

+ + The infobot comes with some scripts for working with + the DBM files. +

+ +

    +
  • update_db +

    + This takes a flat ascii file and inserts it into a DBM file. + It creates a new DBM if it didn't exist. +

    +

      + + scripts/update_db factpacks/code_to_country.txt infobot-is + +
    +

    + will add the factoids in code_to_country.txt + to the infobot-is DBM. +

    +

  • dump_db +

    + The converse. It dumps out the DBM file to a flat + ascii file. Note there is no extension on the DBM name, + even though the system may use one. +

    +

      + + scripts/dump_db infobot-is + +
    +

    + Note there is no extension on the DBM name, even though the + system may use one (like .pag and + .dir or .db). +

    + +

+ +
+ diff --git a/doc/makemanual.pl b/doc/makemanual.pl new file mode 100644 index 0000000..7221930 --- /dev/null +++ b/doc/makemanual.pl @@ -0,0 +1,86 @@ +# First stab at automagically generating the manual from the config +# files and module documentation. +# Simon Cozens, 1999- + +# DON'T, I'M NOT FINISHED YET! + +use Pod::Html; +use strict; +use vars qw($version $VER_MAJ $VER_MIN $VER_MOD); +sub status (@) {print "@_\n"} + +require "../src/Params.pl"; +require "../src/IrcExtras.pl"; + +# Things we know to be core modules: +my %source = map {$_, 1} qw{ + ANSI.pl IrcHooks.pl Reply.pl CTCP.pl + Search.pl Channel.pl Math.pl Setup.pl + DBM.pl Misc.pl Speller.pl Extras.pl + Norm.pl Statement.pl module-template Help.pl + Params.pl myRoutines.pl Process.pl Update.pl + Irc.pl Question.pl User.pl IrcExtras.pl +}; + + +status "Generating manual for $version"; +loadParamFiles($ARGV[0]||"../files/infobot.config"); + +open(OUT,">infobot-guide.html") + or die "! Couldn't write on infobot-guide.html: $!\n"; + +status "Writing the header..."; +print OUT < + + + + Infobot Guide $VER_MAJ\.$VER_MIN\.$VER_MOD + + + +

Infobot Guide $VER_MAJ\.$VER_MIN\.$VER_MOD

+ +EOF + +status "Writing the introduction and main commands summary..."; +open(BIT1, "intro.bit") + or die "! Can't load the introduction to the guide: $!\n"; +{ local $/=undef; print OUT ;} + +print "Scanning for extension modules..."; +opendir(DH, "../src/") or die "! Couldn't open source directory: $!\n"; +my @mods=(); +$|=1; +while (defined ($_=readdir(DH))) { + next unless -f "../src/$_"; + next if exists $source{$_}; + print "."; + read_it($_); +} + +status "\nWriting the rest of the document..."; +open(BIT1, "outro.bit") + or die "! Can't load the end of the guide: $!\n"; +{ local $/=undef; print OUT ;} + +status "Manual created succesfully."; + +sub read_it { + my $file=shift; + open (FH, "../src/$file") or die "! Couldn't open $file: $!\n"; + my $found=0; + my @pods; + local $/=""; + while () { + $found =1 if (/^=head1/); + push @pods, $_ if $found; + } + unless ($found) { + warn "\nNo documentation for $file; bad author!\n" unless $found; + return; + } + close FH; + # Process pods into HTML +} diff --git a/extras/ANSI.pl b/extras/ANSI.pl new file mode 100644 index 0000000..f795806 --- /dev/null +++ b/extras/ANSI.pl @@ -0,0 +1,66 @@ +require 5.001; + +%attributes = ('clear' => 0, + 'reset' => 0, + 'bold' => 1, + 'underline' => 4, + 'underscore' => 4, + 'blink' => 5, + 'reverse' => 7, + 'concealed' => 8, + 'black' => 30, 'on_black' => 40, + 'red' => 31, 'on_red' => 41, + 'green' => 32, 'on_green' => 42, + 'yellow' => 33, 'on_yellow' => 43, + 'blue' => 34, 'on_blue' => 44, + 'magenta' => 35, 'on_magenta' => 45, + 'cyan' => 36, 'on_cyan' => 46, + 'white' => 37, 'on_white' => 47); + +$b_black = cl('bold black'); $_black = cl('black'); +$b_red = cl('bold red'); $_red = cl('red'); +$b_green = cl('bold green'); $_green = cl('green'); +$b_yellow = cl('bold yellow'); $_yellow = cl('yellow'); +$b_blue = cl('bold blue'); $_blue = cl('blue'); +$b_magenta = cl('bold magenta'); $_magenta = cl('magenta'); +$b_cyan = cl('bold cyan'); $_cyan = cl('cyan'); +$b_white = cl('bold white'); $_white = cl('white'); +$_reset = cl('reset'); $_bold = cl('bold'); +$ob = cl('reset'); $b = cl('bold'); + +############################################################################ +# Implementation (attribute string form) +############################################################################ + +# Return the escape code for a given set of color attributes. +sub cl { + my @codes = map { split } @_; + my $attribute = ''; + foreach (@codes) { + $_ = lc $_; + unless (defined $attributes{$_}) { die "Invalid attribute name $_" } + $attribute .= $attributes{$_} . ';'; + } + chop $attribute; + ($attribute ne '') ? "\e[${attribute}m" : undef; +} + +# Given a string and a set of attributes, returns the string surrounded by +# escape codes to set those attributes and then clear them at the end of the +# string. If $EACHLINE is set, insert a reset before each occurrence of the +# string $EACHLINE and the starting attribute code after the string +# $EACHLINE, so that no attribute crosses line delimiters (this is often +# desirable if the output is to be piped to a pager or some other program). +sub c { + my $string = shift; + if (defined $EACHLINE) { + my $attr = cl (@_); + join $EACHLINE, + map { $_ ne "" ? $attr . $_ . "\e[0m" : "" } + split ($EACHLINE, $string); + } else { + cl (@_) . $string . "\e[0m"; + } +} + +1; diff --git a/extras/Aviation.pl b/extras/Aviation.pl new file mode 100644 index 0000000..fd5bbd5 --- /dev/null +++ b/extras/Aviation.pl @@ -0,0 +1,414 @@ +# +# aviation -- infobot module for various flight-planning bits. +# Was originally 'metar' until infobot 44.5. +# +# 1999/07/?? Rich Lafferty +# - Initial version +# 1999/08/02 lenzo@cs.cmu.edu +# - package, BEGIN, eval checks +# 1999/09/16 lenzo@cs.cmu.edu +# - added a timeout +# 2000/??/?? Lazarus Long +# - modified to weather.noaa.gov to reflect hostname change +# 2000/11/09 rich@alcor.concordia.ca +# - NAME CHANGE: now 'aviation' to reflect new functions +# - partial rewrite of metar code: now that we have 'weather', we +# don't need to massage the data for grounded people. +# - status() added to whine about missing modules +# - added more aviation functions (taf, great-circle, zulutime) +# 2000/11/17 rich@alcor.concordia.ca +# - rewrite each function into separate sub +# - fork to handle all requests (even though only web-based requests +# really need to fork. +# 2000/11/18 rich@alcor.concordia.ca +# - added airport name/code lookups, fixed minor bugs in other parts + +package Aviation; + +my ($no_aviation, $no_entities); + +BEGIN { + eval "use LWP::UserAgent"; + if ($@) { $no_aviation++}; + eval "use HTML::Entities"; + if ($@) { $no_entities++}; +} + +# Set the following to 1 if you want the forecast separators in +# a TAF (PROB, BECMG, FM, TEMPO) to be bold. For those that don't know +# from aviation forecasts, each of the above keywords signifies a new +# section of the TAF -- the equivalent, for example, of the "from 10 to 2" +# in "Sunny tomorrow; from 10 to 2, chance of showers". +my $taf_highlight_bold = 1; + +# +# Figure out what we're supposed to do, and do it +# +sub Aviation::get { + if ($no_aviation) { + &main::status("Aviation module requires LWP::UserAgent."); + return ''; + } + + my ($line, $callback) = @_; + $SIG{CHLD} = 'IGNORE'; + my $pid = eval { fork() }; # catch non-forking OSes and other errors + return 'NOREPLY' if $pid; # parent does nothing + if ($line =~ /^metar/i) { $callback->(metar($line)) } + elsif ($line =~ /^taf/i) { $callback->(taf($line)) } + elsif ($line =~ /^great[-\s]?circle/i) { $callback->(greatcircle($line)) } + elsif ($line =~ /^tsd/i) { $callback->(tsd($line)) } + elsif ($line =~ /^zulutime/i) { $callback->(zulutime($line)) } + elsif ($line =~ /^airport/i) { $callback->(airport($line)) } + elsif ($line =~ /^aviation/i) { $callback->(aviation($line)) } + else { $callback->("I think we just lost a wing!") } # reach here -> Extras.pl problem + exit 0 if defined $pid; # child exits, non-forking OS returns + +} + +# +# aviation - list available aviation functions +# +sub aviation { + return "My aviation-related functions are metar, taf, great-circle, tsd, zulutime, and airport. For help with any, ask me about ' help'."; +} + +# +# METAR - current weather observation +# +sub metar { + my $line = shift; + if ($line =~ /^metar\s+(for\s+)?(.*)/i) { + + # ICAO airport codes *can* contain numbers, despite earlier claims. + # Americans tend to use old FAA three-letter codes; luckily we can + # *usually* guess what they mean by prepending a 'K'. The author, + # being Canadian, is similarly lazy. + my $site_id = uc($2); + $site_id =~ s/[.?!]$//; + $site_id =~ s/\s+$//g; + return "'$site_id' doesn't look like a valid ICAO airport identifier." + unless $site_id =~ /^[\w\d]{3,4}$/; + $site_id = "C" . $site_id if length($site_id) == 3 && $site_id =~ /^Y/; + $site_id = "K" . $site_id if length($site_id) == 3; + + # HELP isn't an airport, so we use it for a reference work. + return "For observations, ask me 'metar '. For information on decoding Aerodrome Weather Observations (METAR), see http://www.avweb.com/toc/metartaf.html" + if $site_id eq 'HELP'; + + my $metar_url = "http://weather.noaa.gov/cgi-bin/mgetmetar.pl?cccc=$site_id"; + + # Grab METAR report from Web. + my $agent = new LWP::UserAgent; + if (my $proxy = main::getparam('httpproxy')) { $agent->proxy('http', $proxy) }; + $agent->timeout(10); + my $grab = new HTTP::Request GET => $metar_url; + + my $reply = $agent->request($grab); + + # If it can't find it, assume luser error :-) + return "Either $site_id doesn't exist (try a 4-letter station code like KAGC), or the site NOAA site is unavailable right now." + unless $reply->is_success; + + # extract METAR from incredibly and painfully verbose webpage + my $webdata = $reply->as_string; + $webdata =~ m/($site_id\s\d+Z.*?)'. For information on decoding Terminal Area Forecasts, see http://www.avweb.com/toc/metartaf.html" + if $site_id eq 'HELP'; + + my $taf_url = "http://weather.noaa.gov/cgi-bin/mgettaf.pl?cccc=$site_id"; + + # Grab METAR report from Web. + my $agent = new LWP::UserAgent; + if (my $proxy = main::getparam('httpproxy')) { $agent->proxy('http', $proxy) }; + $agent->timeout(10); + my $grab = new HTTP::Request GET => $taf_url; + + my $reply = $agent->request($grab); + + # If it can't find it, assume luser error :-) + return "I can't seem to retrieve data from weather.noaa.com right now." + unless $reply->is_success; + + # extract TAF from equally verbose webpage + my $webdata = $reply->as_string; + $webdata =~ m/($site_id( AMD)* \d+Z .*?)proxy('http', $proxy) }; + $agent->timeout(10); + my $grab = new HTTP::Request GET => $gc_url; + + my $reply = $agent->request($grab); + + # If it can't find it, assume luser error :-) + unless ($reply->is_success) { + return "I can't seem to retrieve data from www.landings.com right now."; + } + + # extract TAF from equally verbose webpage + my $webdata = $reply->as_string; + my $gcd; + if ($webdata =~ m/circle: ([.\d]+).*?, ([.\d]+).*?, ([.\d]+).*?heading: ([.\d]+)/s) { + $gcd = "Great-circle distance: $1 mi, $2 nm, $3 km, heading $4 degrees true"; + } + else { + $webdata =~ m/(No airport.*?database)/; + $gcd = $1; + } + + return $gcd; + } + else { + # malformed + return "That doesn't look right. The 'great-circle' command takes two airport identifiers and returns the great circle distance and heading between them."; + } +} + +# +# tsd -- calculate time, speed, distance, given any two +# +sub tsd { + my $line = shift; + return "To solve time/speed/distance problems, substitute 'x' for " . + "the unknown value in 'tsd TIME SPEED DISTANCE'. For example, " . + "'tsd 3 x 200' will solve for the speed in at which you can travel " . + "200 mi in 3h." if $line =~ /help/i; + + my ($time, $speed, $distance) = ($line =~ /^tsd\s+(\S+)\s+(\S+)\s+(\S+)$/); + + my $error; + $error++ unless $time && $speed && $distance; + + if ($time =~ /^[A-Za-z]$/) { # solve for time + $error++ unless $speed =~ /^[\d.]+$/; + $error++ unless $distance =~ /^[\d.]+$/; + return $distance / $speed unless $error; + } + elsif ($speed =~ /^[A-Za-z]$/) { # solve for speed + $error++ unless $time =~ /^[\d.]+$/; + $error++ unless $distance =~ /^[\d.]+$/; + return $distance / $time unless $error; + } + elsif ($distance =~ /^[A-Za-z]$/) { # solve for distance + $error++ unless $speed =~ /^[\d.]+$/; + $error++ unless $time =~ /^[\d.]+$/; + return $time * $speed unless $error; + } + + return "Your time/speed/distance problem looks incorrect. For help, try 'tsd help'."; + +} + + +# +# zulutime -- return current UTC time +# +sub zulutime { + $line = shift; + return "zulutime returns the time in DDHHMM format." if $line =~ /help/i; + return sprintf('%02d%02d%02dZ', reverse((gmtime())[1..3])); +} + +# +# airport -- look up airport by identifier (airport name for ___) or by +# name (airport code(s) for ___). To avoid confusion, we +# explicitly discard FAA-but-not-ICAO identifiers. +# +sub airport { + + my $line = shift; + if ($line =~ /^airport\s+(name|code|id)s?\s+(for\s+)?(.*)/i) { + my $function = lc($1); + my $query = $3; + + if ($function eq 'name') { + $query = "C" . $query if length($query) == 3 && $query =~ /^Y/; + $query = "K" . $query if length($query) == 3; + $query = uc($query); + $query =~ s/[.?!]$//; + $query =~ s/\s+$//; + + return "That doesn't look like a valid ICAO airport identifier. (Perhaps you mean 'airport code for $query'?)" + unless length($query) == 4; + + my $apt_url = "http://www6.landings.com/cgi-bin/nph-search_apt?1=$query&max_ret=1"; + + # Grab airport data from Web. + + my $agent = new LWP::UserAgent; + if (my $proxy = main::getparam('httpproxy')) { $agent->proxy('http', $proxy) }; + $agent->timeout(10); + my $grab = new HTTP::Request GET => $apt_url; + + my $reply = $agent->request($grab); + + # If it can't find it, assume luser error :-) + return "I can't seem to access my airport data -- perhaps try again later." + unless $reply->is_success; + + # extract csv-format airport data from incredibly and painfully verbose webpage + my $webdata = $reply->as_string; + @apt_lines = split (/\n/, $webdata); + + my $print_next = 0; + my $response = ''; + + foreach (@apt_lines) { + # skip over entries without ICAO idents (ICAO: n/a) + if (/\(ICAO: [^n]/) { $response .= "$_, "; $pnext = 1; } + elsif ($pnext) { $response .= $_; $pnext = 0; } + } + + $response =~ s/(<.*?>)+/ /g; # naive, but works in *this* case. + $response =~ s/.*?\) //; # strip (ICAO: foo) bit + $response =~ s/\s+/ /g; + $response =~ s/ ,/,/g; # pet peeve. + + if ($no_entities and $response =~ /(&.*?;)/) { + &main::status("Aviation module 'airport' function just output a raw HTML entity ($1) because you don't have HTML::Entities installed."); + $response .= "\n(Excuse the HTML entity. I don't have HTML::Entities handy.)"; + } + else { + $response = decode_entities($response); + } + + if ($response) { + return "$query is $response"; + } + else { + return "I can't find an airport for $query."; + } + + } + elsif ($function eq 'code' or $function eq 'id') { + $query =~ s/[.?!]$//; + $query =~ s/\s+$//; + my $apt_url = "http://www6.landings.com/cgi-bin/nph-search_apt?5=$query&max_ret=100"; + + # Grab airport data from Web. + + my $agent = new LWP::UserAgent; + if (my $proxy = main::getparam('httpproxy')) { $agent->proxy('http', $proxy) }; + $agent->timeout(10); + my $grab = new HTTP::Request GET => $apt_url; + + my $reply = $agent->request($grab); + + # If it can't find it, assume luser error :-) + return "I can't seem to access my airport data -- perhaps try again later." + unless $reply->is_success; + + # extract csv-format airport data from incredibly and painfully verbose webpage + my $webdata = $reply->as_string; + @apt_lines = split (/\n/, $webdata); + + my $response = ''; + + foreach (@apt_lines) { + $response .= "$1 " if m|\(ICAO: ([^n]+?)|; + } + + $response =~ s/(<.*?>)+/ /g; # naive, but works in *this* case. + + if ($response) { + return "$query may be: $response"; + } + else { + return "I can't find an airport code for $query."; + } + + } + # else fall through to malformed bit below + } + + # malformed + return "That doesn't look right. Try 'airport code for CITY' or 'airport name for CODE' instead."; +} + + +1; +__END__ diff --git a/extras/DNS.pl b/extras/DNS.pl new file mode 100644 index 0000000..46d2b2a --- /dev/null +++ b/extras/DNS.pl @@ -0,0 +1,89 @@ + +# infobot :: Kevin Lenzo (c) 1997 + +# once again, thanks to Patrick Cole + +#use POSIX; +use Socket; + +sub REAPER { + $SIG{CHLD} = \&REAPER; # loathe sysV + $waitedpid = wait; +} + +$SIG{CHLD} = \&REAPER; +$DNS_CACHE_EXPIRE_TIME = 7*24*60*60; + +sub DNS { + my $in = $_[0]; + my($match, $x, $y, $result); + + if (($DNS_CACHE{$in}) && ((time()-$DNS_TIME_CACHE{$in}) < $DNS_CACHE_EXPIRE_TIME)) { + return $DNS_CACHE{$in}; + } + + if (!defined($pid = fork)) { + return "no luck, $safeWho"; + } elsif ($pid) { + # parent + } else { + # child + if ($in =~ /(\d+\.\d+\.\d+\.\d+)/) { + &status("DNS query by IP address: $in"); + $match = $1; + $y = pack('C4', split(/\./, $match)); + $x = (gethostbyaddr($y, &AF_INET)); + if ($x !~ /^\s*$/) { + $result = $match." is ".$x unless ($x =~ /^\s*$/); + } else { + $result = "I can't seem to find that address in DNS"; + } + } else { + &status("DNS query by name: $in"); + $x = join('.',unpack('C4',(gethostbyname($in))[4])); + if ($x !~ /^\s*$/) { + $result = $in." is ".$x; + } else { + $result = "I can\'t find that machine name"; + } + } + $DNS_TIME_CACHE{$in} = time(); + $DNS_CACHE{$in} = $result; + + if ($msgType eq 'public') { + &say($result); + } else { + &msg($who, $result); + } + exit; # bye child + } +} + +1; + +__END__ + +=head1 NAME + +DNS.pl - Look up hosts in DNS + +=head1 PREREQUISITES + +None. + +=head1 PARAMETERS + +allowDNS + +=head1 PUBLIC INTERFACE + + nslookup|DNS [for] + +=head1 DESCRIPTION + +Looks up DNS entries for the given host using +C/C calls. + +=head1 AUTHORS + +Kevin Lenzo diff --git a/extras/Extras.pl b/extras/Extras.pl new file mode 100644 index 0000000..622d804 --- /dev/null +++ b/extras/Extras.pl @@ -0,0 +1,818 @@ +# Infobot extensions inside the distribution. +# Local extensions go in myRoutines.pl + +# Kevin A. Lenzo + +sub Extras { + # called after it decides if it's been addressed. + # you have access tothe global variables here, + # which is bad, but anyway. + + # you can return 'NOREPLY' if you want to stop + # processing past this point but don't want + # an answer. if you don't return NOREPLY, it + # will let all the rest of the default processing + # go to it. think of it as 'catching' the event. + + # $addressed is whether the infobot has been + # named or, if a private or standalone + # context, addressed is always 'true' + + # $msgType can be 'public', 'private', maybe 'dcc_chat' + + # $who is the sender of the message + + # $message is the current state of the input, after + # the addressing stuff stripped off the name + + # $origMessage is the text of the original message before + # any normalization or processing + + # you have access to all the routines in urlIrc.pl too, + # of course. + + # -- this section moved from Process.pl -- kl + + if ($addressed and $message =~ m|^\s*(.*?)\s+=~\s+s\/(.+?)\/(.*?)\/([a-z]*);?\s*$|) { + # substitution: X =~ s/A/B/ + + my ($X, $oldpiece, $newpiece, $flags) = ($1, $2, $3, $4); + my $matched = 0; + my $subst = 0; + my $op = quotemeta($oldpiece); + my $np = $newpiece; + $X = lc($X); + + foreach $d ("is","are") { + if ($r = get($d, $X)) { + my $old = $r; + $matched++; + if ($r =~ s/$op/$np/i) { + if (length($r) > getparam('maxDataSize')) { + if ($msgType =~ /private/) { + &msg($who, "That's too long, $who"); + } else { + &say("That's too long, $who"); + } + return 'NOREPLY'; + } + set($d, $X, $r); + &status("update: '$X =$d=> $r'; was '$old'"); + $subst++; + } + } + } + if ($matched) { + if ($subst) { + if ($msgType =~ /private/) { + &msg($who, "OK, $who"); + } else { + &say("OK, $who"); + } + return 'NOREPLY'; + } else { + if ($msgType =~ /private/) { + &msg($who, "That doesn't contain '$oldpiece'"); + } else { + &say("That doesn't contain '$oldpiece', $who"); + } + } + } else { + if ($msgType =~ /private/) { + &msg($who, "I didn't have anything matching '$X'"); + } else { + &say("I didn't have anything matching '$X', $who"); + } + } + return 'NOREPLY'; + } # end substitution + + if ($addressed and IsFlag("S")) { + if ($message =~ s/^\s*say\s+(\S+)\s+(.*)//) { + &msg($1, $2); + &msg($who, "ok."); + return 'NOREPLY'; + } + } + + if (($addressed) && ($message =~ /^\s*help\b/i)) { + $message =~ s/^\s*help\s*//i; + $message =~ s/\W+$//; + &help($message); + return 'NOREPLY'; + } + + if ($message =~ s/^forget\s+((a|an|the)\s+)?//i) { + # cut off final punctuation + $message =~ s/[.!?]+$//; + #return 'no authorization to lobotomize'; + #} + $k = &normquery($message); + $k = lc($k); + + $found = 0; + + foreach $d ("is", "are") { + if ($r = get($d, $k)) { + if (IsFlag("r") ne "r") { + performReply("you have no access to remove factoids"); + return 'NOREPLY'; + } + $found = 1 ; + &status("forget: <$who> $k =$d=> $r"); + clear($d, $k); + $factoidCount--; + } + } + if ($found == 1) { + if ($msgType !~ /public/) { + &msg($who, "$who: I forgot $k"); + } else { + &say("$who: I forgot $k"); + } + $l = $who; $l =~ s/^=//; + $updateCount++; + return 'NOREPLY'; + } else { + if ($msgType !~ /public/) { + &msg($who, "I didn't have anything matching $k"); + return 'NOREPLY'; + } else { + if ($addressed > 0) { + &say("$who, I didn't have anything matching $k"); + return 'NOREPLY'; + } + } + } + } # end forget + + + # Aldebaran++ ! + if (getparam("shutup") and $message =~ /^\s*wake\s*up\s*$/i ) { + if ($msgType =~ /public/) { + if ($addressed) { + if (rand() > 0.5) { + &performSay("Ok, ".$who.", I'll start talking."); + &status("Changing to Optional mode"); + # Oh shit. - Simon + $chanopts{Channel()}->{'addressing'} = 'OPTIONAL'; + return 'NOREPLY'; + } else { + &performSay(":O"); + return 'NOREPLY'; + } + } + } else { + &msg($who, "OK, I'll start talking."); + $param{'addressing'} = 'OPTIONAL'; + &status("Changing to Optional mode"); + return 'NOREPLY'; + } + } # end wake up + + if ($param{"shutup"} and $message =~ /^\s*shut\s*up\s*$/i ) { + if ($msgType =~ /public/) { + if ($addressed) { + if (rand() > 0.5) { + &performSay("Sorry, ".$who.", I'll keep my mouth shut. "); + $chanopts{Channel()}->{'addressing'} = 'REQUIRE'; + &status("Changing to Require mode"); + return 'NOREPLY'; + } else { + &performSay(":X"); + return 'NOREPLY'; + } + } + } else { + &msg($who, "Sorry, I'll try to be quiet."); + $param{'addressing'} = 'REQUIRE'; + &status("Changing to Require mode"); + return 'NOREPLY'; + } + } # end shut up + + # -- from here down, 'tell' needs to be worked into the forkers. + # anything that just returns a value will be handled automatically, + # but anything that forks will require special handling. + + # mendel++ + if (getparam('zippy')) { + if (my $resp = zippy::get($message)) { + return $resp; + } + } + + # Masque++ + my $triggers = getparam("purldoc_trigger") if getparam('purldoc'); + if (defined getparam('purldoc') and $message =~ s/^\s*$triggers\s+-?(\w+)/$1/) { + return &purldoc(); + } + + # from Chris Tessone: slashdot headlines + # "slashdot" or "slashdot headlines" + + if (defined(getparam('slash')) and $message =~ + /^\s*slashdot( headlines)?\W*\s*$/) { + my $headlines = &getslashdotheads(); + return $headlines; + } + + # internic or RIPE whois + if (getparam('allowInternic')) { + if ($message =~ /^(internic|ripe)(?: for)?\s+(\S+)$/i) { + my $where = $1; + my $what = $2; + &domain_summary($what, $where); + + return 'NOREPLY'; + } + } + + # currency exchanger, bobby@bofh.dk + if( defined(getparam('exchange')) + and getparam('exchange') + and ( $message =~ /^\s*(?:ex)?change\s+/i or $message =~ /^\s*currenc(?:ies|y) for\s/i )){ + + &status("message($message)"); + my $response=''; + + if ($pid = fork) { + # this takes some time, so fork. + return 'NOREPLY'; + } + + if ($message =~ /^\s*(?:ex)?change\s+([\d\.\,]+)\s+(\S+)\s+(?:into|to|for)\s+(\S+)/i) { + my($Amount,$From,$To) = ($1,$2,$3); + $From = uc $From; $To = uc $To; + &status("calling exchange($From, $To, $Amount) ..."); + $response = &exchange($From, $To, $Amount); + # Change Finland, purl! No no. How about 'currency for'. + # } elsif( $message =~ /^\s*(?:ex)?change ([\w\s]+)/) { + } elsif( $message =~ /^\s*currenc(?:ies|y) for\s(?:the\s)?([\w\s]+)/i ) { + # looking up the currency for a country + my $Country = $1; + &status("calling exchange($Country) ..."); + $response = &exchange($Country); + } else { + $response = "that doesn't look right"; + } + + &status("exchange got response($response)"); + + if($response =~ /^EXCHANGE: \S*/) { + &status($response); + } elsif ($msgType eq 'public') { + &say("$who: $response"); + } else{ + &msg($who, $response); + } + + # exit the child or it gets weird + exit 0; + } # end excange + + # Jonathan Feinberg's babel-bot -- jdf++ + if (defined getparam('babel') && + (1 or $addressed) && + $message =~ m{ + ^\s* + (?:babel(?:fish)?|x|xlate|translate) + \s+ + (to|from) # direction of translation (through) + \s+ + ($babel::lang_regex)\w* # which language? + \s* + (.+) # The phrase to be translated + }xoi) { + my $whom = $who; # building a closure, need lexical + my $callback = $msgType eq 'public' ? + sub{say("$who: $_[0]")} : sub{msg($who, $_[0])}; + &babel::forking_babelfish(lc $1, lc $2, $3, $callback); + return 'NOREPLY'; + } # end babel + + # insult server. patch thanks to michael@limit.org + if (getparam('insult') and ($message =~ /^\s*insult (.*)\s*$/)) { + my $person = $1; + my $language = "english"; + # Could have SWORN Simon patched this. Simon++ for the fix, either way. - 3Jul2K, Masque + # > purl, insult mountain dew + # mounta ist nichts aber ein gegorener Stapel des squishy Programmfehlerspit. + # if ($person =~ s/ in \s*($babel::lang_regex)\w*\s*$//xi) { + if ($person =~ s/ in \s*($babel::lang_regex)\w*\s*$//i) { + $language = lc($1); + } + $person = $who if $person =~ /^\s*me\s*$/i; + + my $insult = &insult(); + if ($person ne $who) { + $insult =~ s/^\s*You are/$person is/i; + } + + if ($insult =~ /\S/) { + if (getparam('babel') and ($language ne "english")) { + my $whom = $who; # building a closure, need lexical + my $callback = $msgType eq 'public' ? + sub{say("$_[0]")} : sub{msg($whom, $_[0])}; + &babel::forking_babelfish("to", $language, $insult, $callback); + return 'NOREPLY'; + } + } else { + $insult = "No luck, $who"; + } + + return $insult; + } # end insult + + if (getparam('weather') and ($message =~ /^\s*weather\s+(?:for\s+)?(.*?)\s*\?*\s*$/)) { + my $code = $1; + my $weath ; + if ($code =~ /^[a-zA-Z][a-zA-Z0-9]{3,4}$/) { + $weath = &Weather::NOAA::get($code); + } else { + $weath = "Try a 4-letter station code (see http://weather.noaa.gov/weather/curcond.html for locations and codes)"; + } +# if ($msgType eq 'public') { +# &say("$who: $weath"); +# } else { + &msg($who, $weath); +# } + return 'NOREPLY'; + } + + # This replaced 'metar'. Lotsa aviation stuff. Go look. + if(defined(getparam('aviation') or defined(getparam('metar'))) and + $message =~ /^(metar | + taf | + great[-\s]?circle | + zulutime | + tsd | + airport | + aviation)/xi) + { + my $callback = $msgType eq 'public' ? + sub{say("$who: $_[0]")} : sub{msg($who, $_[0])}; + &Aviation::get($message, $callback); + return 'NOREPLY'; + } + +# from Simon: google searching +# modified to fork and generally search by oznoid + + if(defined(getparam('wwwsearch')) and $message =~ + /^\s* + (?:search\s+)? + ($W3Search::regex) + \s+for\s+ + [\'\"]?(.*?)[\'\"]? + \s*\?*\s*$ + /ix ) { + my $callback = $msgType eq 'public' ? + sub{say("$who: $_[0]")} : sub{msg($who, $_[0])}; + &W3Search::forking_W3Search($1,$2,getparam('wwwsearch'), $callback); + return 'NOREPLY'; + } + + # Adam Spiers' nickometer + if ($message =~ /^\s*(?:lame|nick)-?o-?meter(?: for)? (\S+)/i) { + my $term = $1; + if (lc($term) eq 'me') { + $term = $who; + } + + $term =~ s/\?+\s*//; + + my $percentage = &nickometer($term); + + if ($percentage =~ /NaN/) { + $percentage = "off the scale"; + } else { + # $percentage = sprintf("%0.4f", $percentage); + $percentage =~ s/\.0+$//; + $percentage .= '%'; + } + + if ($msgType eq 'public') { + &say("'$term' is $percentage lame, $who"); + } else { + &msg($who, "the 'lame nick-o-meter' reading for $term is $percentage, $who"); + } + + return 'NOREPLY'; + } # end nick-o-meter + + if ($message =~ /^foldoc(?: for)?\s+(.*)/i) { + my ($terms) = $1; + $terms =~ s/\?\W*$//; + + my $key= $terms; + $key =~ s/\s+$//; + $key =~ s/^\s+//; + $key =~ s/\W+/+/g; + + my $reply = "$terms may be sought in foldoc at http://wombat.doc.ic.ac.uk/foldoc/foldoc.cgi?query=$key"; + + return $reply; + } + + if ($message =~ /^(?:quote|stock price)(?: of| for)? ([A-Z]{1,6})\?*$/) { + my $reply = "stock quotes for $1 may be sought at http://quote.yahoo.com/q?s=$1\&d=v1"; + + return $reply; + } + + if ($message =~ /^rot13\s+(.*)/i) { + # rot13 it + my $reply = $1; + $reply =~ y/A-Za-z/N-ZA-Mn-za-m/; + return $reply; + } + + # search imdb + if ($message =~ s/^\s*(search )?imdb (for )?//) { + $check = $message; + my $url = $message; + + # freeside++ for URL cleanup code + + my $date = ""; + if ($url =~ s/( \(\d+\))$//) { $date = $1; } + $url =~ s/^(The|A|An|Les) (.*)/$2, $1/i; + $url = "http://www.imdb.com/M/title-substring?title=$url$date&type=fuzzy"; + $url =~ s/ /+/g; + $V = "-> "; $orig_lhs = $message; $theVerb= "is"; + return "$message can be found at $url"; + } # end imdb + + if ($message =~ s/^\s*(search )?hyperarchive (for )?//) { + $message =~ /\w+/; + $check = $message; + my $q = $message; + $q =~ s/\W+//g; + $result = "http://hyperarchive.lcs.mit.edu/cgi-bin/NewSearch?key=$q"; + $V = "-> "; $orig_lhs = $message; $theVerb= "is"; + return "$message may be sought at $result"; + } + + # websters + if ($message =~ s/^\s*(search )?websters* (for )?//) { + $message =~ /\w+/; + $word = $&; + $check = $message; + my $q = $message; + $q =~ s/\W+/+/g; + $result = "http://work.ucsd.edu:5141/cgi-bin/http_webster?$word"; + $V = "-> "; $orig_lhs = $message; $theVerb= "is"; + return "$message may be sought at $result"; + } # end websters + + # -- from Question + + # Now with INTENSE CASE INSENSITIVITY! SUNDAY SUNDAY SUNDAY! + if ($message =~ /^seen (\S+)/i) { + my $person = $1; + $person =~ s/\?*\s*$//; + my $seen = &get(seen => lc $person); + if ($seen) { + my ($when,$where,$what) = split /$;/, $seen; + my $howlong = time() - $when; + $when = localtime $when; + + my $tstring = ($howlong % 60). " seconds ago"; + $howlong = int($howlong / 60); + + if ($howlong % 60) { + $tstring = ($howlong % 60). " minutes and $tstring"; + } + $howlong = int($howlong / 60); + + if ($howlong % 24) { + $tstring = ($howlong % 24). " hours, $tstring"; + } + $howlong = int($howlong / 24); + + if ($howlong % 365) { + $tstring = ($howlong % 365). " days, $tstring"; + } + $howlong = int($howlong / 365); + if ($howlong > 0) { + $tstring = "$howlong years, $tstring"; + } + + if ($msgType =~ /public/) { + &performSay("$person was last seen on $where $tstring, saying: $what [$when]"); + } else { + &msg($who, "$person was last seen on $where $tstring, saying: $what [$when]"); + } + return 'NOREPLY'; + } + + if ($msgType =~ /public/) { + &performSay("I haven't seen '$person', $who"); + } else { + &msg($who,"I haven't seen '$person', $who"); + } + return 'NOREPLY'; + } + + if ($message =~ /^\s*heya?,? /) { + return 'NOREPLY' unless $addressed; + } + + # Gotta be gender-neutral here... we're sensitive to purl's needs. :-) + if ($message =~ /(good(\s+fuckin[\'g]?)?\s+(bo(t|y)|g([ui]|r+)rl))|(bot(\s|\-)?snack)/i) { + &status("random praise [$msgType,$addressed]: $message"); + if ($msgType =~ /public/) { + if ($addressed) { + if (rand() < .5) { + &performSay("thanks $who :)"); + } else { + &performSay(":)"); + } + } + } else { + &msg($who, ":)"); + } + return 'NOREPLY'; + } + + if ($addressed) { + if ($message =~ /you (rock|rocks|rewl|rule|are so+ co+l)/) { + if ($msgType =~ /public/) { + if (rand() < .5) { + &performSay("thanks $who :)"); + } else { + &performSay(":)"); + } + return 'NOREPLY'; + } else { + &msg($who, ":)"); + } + } + if ($message =~ /thank(s| you)/i) { + if ($msgType =~ /public/) { + if (rand() < .5) { + &performSay($welcomes[int(rand(@welcomes))]." ".$who); + } else { + &performSay($who.": ".$welcomes[int(rand(@welcomes))]); + } + } else { + if (rand() < .5) { + &msg($who, $welcomes[int(rand(@welcomes))].", ".$who); + } else { + &msg($who, $welcomes[int(rand(@welcomes))]); + } + } + return 'NOREPLY'; + } + } + + if ($message =~ /^\s*(h(ello|i( there)?|owdy|ey|ola)|salut|bonjour|niihau|que\s*tal)( $param{nick})?\s*$/i) { + if (!$addressed and rand() > 0.35) { + # 65% chance of replying to a random greeting when not addressed + return 'NOREPLY'; + } + + my($r) = $hello[int(rand(@hello))]; + if ($msgType =~ /public/) { + &performSay($r.", $who"); + } else { + &msg($who, $r); + } + return 'NOREPLY'; + } + + if (($message =~ /^\s*(?:nslookup|dns)(?: for)?\s+(\S+)$/i) and getparam('allowDNS')) { + &status("DNS Lookup: $1"); + &DNS($1); + return 'NOREPLY'; + } + + if (getparam('ispell') and ($message =~ s/^spell(ing)? (?:of |for )?//)) { + &status("Spell: $message"); + &ispell($message); + return 'NOREPLY'; + } + + if (($message =~ /^traceroute (\S+)$/i) and getparam("allowTraceroute")) { + &status("traceroute to $1"); + &troute($1); + return 'NOREPLY'; + } + + if ($message =~ /^crypt\s*\(\s*(\S+)\s*(?:,| )\s*(\S+)/) { + my $cr = crypt($1, $2); + if ($msgType =~ /private/) { + &msg($who, $cr); + } else { + &performSay($cr); + } + return 'NOREPLY'; + } + + # may not want to cut off all: all i know is ... + # but for now seem mostly content-free + + if (getparam('allowLeave') =~ /$msgType/) { + if ($message =~ /(leave|part) ((\#|\&)\S+)/i) { + if (IsFlag("o") or $addressed) { + if (IsFlag("c") ne "c") { + &performReply("you don't have the channel flag"); + return 'NOREPLY'; + } + &channel($2); + &performSay("goodbye, $who."); + &status("PART $2 <$who>"); + &part($2); + return 'NOREPLY'; + } + } + } + + if ($msgType !~ /public/) { + # accept only msgs leaves/joins + my($ok_to_join); + + if ($message =~ /join ([\&\#]\S+)(?:\s+(\S+))?/i) { + # Thanks to Eden Li (tile) for the channel key patch + my($which, $key) = ($1, $2); + $key = defined ($key) ? " $key" : ""; + foreach $chan (split(/\s+/, $param{'allowed_channels'})) { + if (lc($which) eq lc($chan)) { + $ok_to_join = $which . $key; + last; + } + } + if (IsFlag("o")) { $ok_to_join = $which.$key }; + if ($ok_to_join) { + if (IsFlag("c") ne "c") { + &msg($who, "You don't have the channel flag"); + return 'NOREPLY'; + } + joinChan($ok_to_join); + &status("JOIN $ok_to_join <$who>"); + &msg($who, "joining $ok_to_join") + unless ($channel eq &channel()); + sleep(1); + # my $temp = &channel(); + # &performSay("hello, $who."); + # &channel($temp); + return 'NOREPLY'; + } else { + &msg($who, "I am not allowed to join that channel."); + return 'NOREPLY'; + } + } + } + + if (IsFlag("s") eq "s") { + if ($message =~ /^\s*(scan|search)\s*for\s+/i) { + if ($^O =~ /(win|mac)/i) { + # can't fork + &search($message); + } else { + &status("forking off: $message"); + if (my $cpid = fork) { + # do nothing if we're the parent + } else { + # we're the child + &search($message); + &status("child exit: $message"); + exit 0; + } + } + return 'NOREPLY'; + } + } + + if (getparam('allowConv')) { + if ($message =~ /^\s*(asci*|chr) (\d+)\s*$/) { + $num = $2; + if ($num < 32) { + $num += 64; + $res = "^".chr($num); + } else { + $res = chr($2); + } + if ($num == 0) { $res = "NULL"; } ; + return "ascii ".$2." is \'".$res."\'"; + } + if ($message =~ /^\s*ord (.)\s*$/) { + $res = $1; + if (ord($res) < 32) { + $res = chr(ord($res) + 64); + if ($res eq chr(64)) { + $res = 'NULL'; + } else { + $res = '^'.$res; + } + } + return "\'$res\' is ascii ".ord($1); + } + } + + if (getparam('plusplus')) { + my $message2 = $message; + + # Fixes the "soandso? has neutral karma" bug. - Masque, 12Apr2k + if ($message2 =~ s/^(?:karma|score)\s+(?:for\s+)?(.*?)\??$/$1/) { + + # Some people prefer to have a factoid for their karma. + # This was the default behavior, pre-0.43. + $answer = &doQuestion($msgType, $message, $msgFilter); + return $answer if $answer; + + $message2 = lc($message2); + $message2 =~ s/\s+/ /g; +&status("Karma string is currently \'$message2\'"); + $message2 ||= "blank karma"; + if ($message2 eq "me") { + $message2 = lc($who); + } + my $karma = &get(plusplus => $message2); + if ($karma) { + return "$message2 has karma of $karma"; + } else { + return "$message2 has neutral karma"; + } + } + } + + if (($addressed) && ($message =~ /^statu?s/)) { + $upString = &timeToString(time()-$startTime); + $eTime = &get("is", "the qEpochDate"); + return "Since $setup_time, there have been $updateCount " + . "modifications and $questionCount questions. " + . "I have been awake for $upString this session, " + . "and currently reference $factoidCount factoids. " + . "Addressing is in ".lc(getparam('addressing'))." mode."; + } + + # divine added routine (boojum++) + if ($message =~ /^(8-?ball|divine)\s+(.*)/i) { + my %m8ball = ('original' => 'shakes the psychic black sphere...', + 'sarcastic' => 'shakes the psychic purple sphere...', + 'userdef' => 'shakes the psychic prismatic sphere...', + ); + + if (!@m8_answers) { + my $answer_file = getparam('magic8_answers') || "$param{miscdir}/magic8.txt"; + + print "reading from $answer_file\n"; + + if (open MAGIC8, "<$answer_file") { + while () { + chomp; + push @m8_answers, $_; + } + } else { + @m8_answers = ('the Magic Ball is cloudy or missing a fact file.'); + } + } + + my ($type, $reply) = split /\s+=>\s+/, $m8_answers[rand(@m8_answers)]; + + if ($msgType eq 'public') { + &say("\cAACTION $m8ball{$type}\cA"); + &say("It says '$reply,' $who"); + } else { + &msg($who, "\cAACTION $m8ball{$type} \cA"); + &msg($who, "It says '$reply'."); + } + return 'NOREPLY'; + } # end divine + + # excuse server. bobby@bofh.dk + if (getparam('excuse') and + ($message =~ /^\s*(?:give\s+(.*)\s+an\s+excuse|excuse\s*(.*))\s*$/)) { + &status("excuses..."); + if ($1 ne 'in') { + $person = $1 || "me"; + } + + $person = $who if $person =~ /^\s*me\s*$/i; + + &status("calling &excuse()..."); + my $excuse = "$who: " . &excuse(); + if ($person ne $who) { + $excuse =~ s/^\s*Your excuse is/$who\'s excuse is/i; + } + + if (not $excuse) { + $excuse = "No luck getting an excuse, $who"; + } + + if ($msgType eq 'public') { + &say($excuse); + } else { + &msg($who, $excuse); + } + return 'NOREPLY'; + } # end excuse + + return undef; +} + + +1; + diff --git a/extras/Internic.pl b/extras/Internic.pl new file mode 100644 index 0000000..8d08cd7 --- /dev/null +++ b/extras/Internic.pl @@ -0,0 +1,144 @@ +# infobot :: Kevin Lenzo (c) 1997 + +use Socket; +use POSIX; + +sub I_REAPER { + $SIG{CHLD} = \&I_REAPER; + $waitedpid = wait; +} + +$SIG{CHLD} = \&I_REAPER; +$DOMAIN_CACHE_EXPIRE_TIME = 7*24*60*60; + +sub domain_summary { + # summarize the goo from internic + + my $item = $_[0]; + my @result; + my $result; + my @dom; + + if (($DOMAIN_CACHE{$item}) + && ((time()-$DOMAIN_TIME_CACHE{$item}) < $DOMAIN_CACHE_EXPIRE_TIME)) { + return $DOMAIN_CACHE{$item}; + } + + if (!defined($pid = fork)) { + return "no luck, $safeWho"; + } elsif ($pid) { + # parent + } else { + # child + @dom = &domain_lookup($item); + if ($dom[0] !~ /No match/) { + foreach (@dom) { + print ; + next if /^\s*$/; + s/:/: /; + s/\s+/ /g; + next if /^\s*Record/; + next if /^\s*Domain Name/; + # next if /^\s*\S+ Contact/; + # last if /^\s*Domain servers/; + last if /^To single out/; + if (s/the internic.*//i) { + push @result, $_; + last; + } + s/Administrative Contact/Admin/; + s/Technical Contact/Tech/; + s/Domain servers in listed order/DNS/; + push @result, $_; + last if ($#result > 15); + } + foreach (@result) { s/\s+/ /; s/^\s+//; } + foreach (0..$#result-1) { + $result[$_].="; " unless $result[$_]=~/:\s*$/; + } + $result = join("", @result); + $result =~ s/\s+;/;/g; + $result =~ s/\s+/ /g; + } else { + $result = "I can't find the domain $item"; + } + $DOMAIN_TIME_CACHE{$item} = time(); + $DOMAIN_CACHE{$item} = $result; + &msg($who, $result); + + exit; # exit child. + } +} + +sub domain_lookup { + # do the actual looking up + my($lookup) = @_; + my ($name, $aliases, $proto, $port, $len, + $this, $that, $thisaddr, $thataddr, $hostname); + + my @result; + + my $whois_server = 'rs.internic.net'; + my $whois_port = 43; + + $sockaddr = 'S n a4 x8'; + chop($hostname = `hostname`); + + ($name, $aliases, $proto) = getprotobyname('tcp'); + ($name, $aliases, $whois_port) = getservbyname($whois_port, 'tcp') + unless $whois_port =~ /^\d+$/; + ($name, $aliases, $type, $len, $thisaddr) = gethostbyname($hostname); + ($name, $aliases, $type, $len, $thataddr) = gethostbyname($whois_server); + + $this = pack($sockaddr, AF_INET, 0, $thisaddr); + $that = pack($sockaddr, AF_INET, $whois_port, $thataddr); + + socket(DOMAIN_SERVER, PF_INET, SOCK_STREAM, $proto) + || die "socket: $!"; + bind(DOMAIN_SERVER, $this) || die "bind: $!"; + connect(DOMAIN_SERVER, $that) || die "connect: $!"; + + select(DOMAIN_SERVER); $| = 1; + + print DOMAIN_SERVER $lookup."\r\n"; + + @result = (); + my $line; + while (($#result < 30) && ($line = )) { + next if (1.. $line =~ /Registrant:/); + push(@result,$line); + } + close(DOMAIN_SERVER); select(STDOUT); + + unshift @result, "Registrant: " if @result; + @result; +} + +1; + +__END__ + +=head1 NAME + +Internic.pl - look up Internic/RIPE whois records for a host + +=head1 PREREQUISITES + +Just the standard stuff. + +=head1 PARAMETERS + +allowInternic + +=head1 PUBLIC INTERFACE + + Internic|RIPE for + +=head1 DESCRIPTION + +Queries RIPE or the Internic for the whois information about the +supplied host, and formats it up nicely. + +=head1 AUTHORS + +Kevin Lenzo diff --git a/extras/Math.pl b/extras/Math.pl new file mode 100644 index 0000000..565edfb --- /dev/null +++ b/extras/Math.pl @@ -0,0 +1,161 @@ + +# infobot copyright (C) kevin lenzo 1997-98 + +if (!(%digits)) { + %digits = ( + "first", "1", + "second", "2", + "third", "3", + "fourth", "4", + "fifth", "5", + "sixth", "6", + "seventh", "7", + "eighth", "8", + "ninth", "9", + "tenth", "10", + "one", "1", + "two", "2", + "three", "3", + "four", "4", + "five", "5", + "six", "6", + "seven", "7", + "eight", "8", + "nine", "9", + "ten", "10" + ); +} + +sub math { + my $in = $_[0]; + # Math handling. + + foreach $x (keys %digits) { + $in =~ s/\b$x\b/$digits{$x}/g; + } + + if (getparam('fortranMath')) { + if ($in =~ /^calc\s+(.+)$/) { + $parm = $1; + $parm =~ s/\s//g; + #$parm =~ s/[a-zA-Z]//g; + status("bc: $parm"); + open(P, "echo '$parm'|bc 2>&1 |"); # dgl++ + $tmp = ''; + @prevs = (); + foreach $line (

) { + chomp $line; + $line =~ s/\\$//; + $line =~ s/\(standard_in\) 1: /$who: /; + $tmp = 0; + foreach $p (@prevs) { + if ($p eq $line) { + $tmp = 1; + } + } + if ($tmp == 0 && $line !~ /illegal character/) { + performReply($line); + } + push(@prevs, $line); + } + close(P); + return undef; + } + } + + if (getparam('perlMath')) { + if (($in !~ /^\s*$/) and ($in !~ /(\d+\.){2,}/)) { + my($locMsg) = $in; + + foreach (keys %digits) { + $locMsg =~ s/$_/$digits{$_}/g; + } + + while ($locMsg =~ /(exp ([\w\d]+))/) { + $exp = $1; + $val = exp($2); + $locMsg =~ s/$exp/+$val/g; + } + while ($locMsg =~ /(hex2dec\s*([0-9A-Fa-f]+))/) { + $exp = $1; + $val = hex($2); + $locMsg =~ s/$exp/+$val/g; + } + if ($locMsg =~ /^\s*(dec2hex\s*(\d+))\s*\?*/) { + $exp = $1; + $val = sprintf("%x", "$2"); + $locMsg =~ s/$exp/+$val/g; + } + $e = exp(1); + $locMsg =~ s/\be\b/$e/; + + while ($locMsg =~ /(log\s*((\d+\.?\d*)|\d*\.?\d+))\s*/) { + $exp = $1; + $res = $2; + if ($res == 0) { $val = "Infinity";} + else { $val = log($res); } ; + $locMsg =~ s/$exp/+$val/g; + } + + while ($locMsg =~ /(bin2dec ([01]+))/) { + $exp = $1; + $val = join ('', unpack ("B*", $2)) ; + $locMsg =~ s/$exp/+$val/g; + } + + while ($locMsg =~ /(dec2bin (\d+))/) { + $exp = $1; + $val = join('', unpack('B*', pack('N', $2))); + $val =~ s/^0+//; + $locMsg =~ s/$exp/+$val/g; + } + + $locMsg =~ s/ to the / ** /g; + $locMsg =~ s/\btimes\b/\*/g; + $locMsg =~ s/\bdiv(ided by)? /\/ /g; + $locMsg =~ s/\bover /\/ /g; + $locMsg =~ s/\bsquared/\*\*2 /g; + $locMsg =~ s/\bcubed/\*\*3 /g; + $locMsg =~ s/\bto\s+(\d+)(r?st|nd|rd|th)?( power)?/\*\*$1 /ig; + $locMsg =~ s/\bpercent of/*0.01*/ig; + $locMsg =~ s/\bpercent/*0.01/ig; + $locMsg =~ s/\% of\b/*0.01*/g; + $locMsg =~ s/\%/*0.01/g; + $locMsg =~ s/\bsquare root of (\d+)/$1 ** 0.5 /ig; + $locMsg =~ s/\bcubed? root of (\d+)/$1 **(1.0\/3.0) /ig; + $locMsg =~ s/ of / * /; + $locMsg =~ s/(bit(-| )?)?xor(\'?e?d( with))?/\^/g; + $locMsg =~ s/(bit(-| )?)?or(\'?e?d( with))?/\|/g; + $locMsg =~ s/bit(-| )?and(\'?e?d( with))?/\& /g; + $locMsg =~ s/(plus|and)/+/ig; + + if (($locMsg =~ /^\s*[-\d*+\s()\/^\.\|\&\*\!]+\s*$/) + && ($locMsg !~ /^\s*\(?\d+\.?\d*\)?\s*$/) + && ($locMsg !~ /^\s*$/) + && ($locMsg !~ /^\s*[( )]+\s*$/)) + { + # $tmpMsg = $locMsg; + + $locMsg = eval($locMsg); + + if ($locMsg =~ /^[-+\de\.]+$/) { + # $locMsg = sprintf("%1.12f", $locMsg); + $locMsg =~ s/\.0+$//; + $locMsg =~ s/(\.\d+)000\d+/$1/; + if (length($locMsg) > 30) { + $locMsg = "a number with quite a few digits..."; + } + + return $locMsg; + } else { + $locMsg = undef; + } + } + } + } + + + return undef; +} + +1; diff --git a/extras/NOAA.pl b/extras/NOAA.pl new file mode 100644 index 0000000..6047a43 --- /dev/null +++ b/extras/NOAA.pl @@ -0,0 +1,136 @@ +#!/usr/bin/perl + +package Weather; + +# kevin lenzo (C) 1999 -- get the weather forcast NOAA. +# feel free to use, copy, cut up, and modify, but if +# you do something cool with it, let me know. + +# 16-SEP-99 lenzo@cs.cmu.edu switched to LWP::UA and +# put in a timeout. + +my $no_weather; +my $cache_time = 60 * 40 ; # 40 minute cache time +my $default = 'KAGC'; + +BEGIN { + $no_weather = 0; + eval "use LWP::UserAgent"; + $no_weather++ if ($@); +} + +sub Weather::NOAA::get { + my ($station) = shift; + $station = uc($station); + my $result; + + if ($no_weather) { + return 0; + } else { + + if (exists $cache{$station}) { + my ($time, $response) = split $; , $cache{$station}; + if ((time() - $time) < $cache_time) { + return $response; + } + } + + my $ua = new LWP::UserAgent; + if (my $proxy = main::getparam('httpproxy')) { $ua->proxy('http', $proxy) }; + + $ua->timeout(10); + my $request = new HTTP::Request('GET', "http://tgsv22.nws.noaa.gov/weather/current/$station.html"); + my $response = $ua->request($request); + + if (!$response->is_success) { + return "Something failed in connecting to the NOAA web server. Try again later."; + } + + $content = $response->content; + + if ($content =~ /ERROR/i) { + return "I can't find that station code (see http://weather.noaa.gov/weather/curcond.html for locations codes)"; + } + + $content =~ s|.*?current weather conditions.*?||is; + + $content =~ s|.*?(?:\s*<[^>]+>)*\s*([^<]+)\s<.*?||is; + my $place = $1; + chomp $place; + + $content =~ s|.*?(?:\s*<[^>]+>)*\s*([^<]+)\s<.*?||is; + my $id = $1; + chomp $id; + + $content =~ s|.*?conditions at.*?||is; + + $content =~ s|.*?