gulp
commit
ee4f56acf6
@ -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.
|
||||
|
||||
|
@ -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 <reply>
|
||||
to values in the db to just get a reply with no
|
||||
extra info.
|
||||
|
||||
e.g.
|
||||
|
||||
x => <reply> 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 <inputfile> <dbname>
|
||||
|
||||
where <inputfile> 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 <dbname>
|
||||
|
||||
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
|
||||
|
||||
|
@ -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
|
||||
<rss="http://path/to/rdf/file"> 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 <lazarus@frontiernet.net>
|
||||
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 <engine> for <keywords>'.
|
||||
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 <botname> 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 <action> as a species of <reply>: X is <action> 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 <bot> <password> <command>
|
||||
where <command> 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 <pass> eval <perl code>
|
||||
|
||||
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:
|
||||
<mynick> infobot: something is <multi>
|
||||
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.
|
||||
<mynick> <end>
|
||||
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 '<reply>' 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
|
||||
|
@ -0,0 +1,2 @@
|
||||
roses => red
|
||||
violets => blue
|
@ -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
|
@ -0,0 +1,10 @@
|
||||
# Channel File (c) 1999 Infobot & Associates
|
||||
|
||||
ChannelEntry #test {
|
||||
fallback yes;
|
||||
addressing REQUIRE;
|
||||
shutup TRUE;
|
||||
msgonly TRUE;
|
||||
continuity 0;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -0,0 +1,2 @@
|
||||
*/5 * * * * /usr/users/you/infobot0.1b/run_infobots.pl > /dev/null
|
||||
|
@ -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, <reply>, 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 <reply> Y".
|
||||
reply: This is a good way to close junk entries; use "X is <reply>" 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?"
|
@ -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, <reply>, 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 <reply> Y".
|
||||
reply: This is a good way to close junk entries; use "X is <reply>" 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?"
|
@ -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
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
@ -0,0 +1,6 @@
|
||||
what => <reply>
|
||||
who => <reply>
|
||||
when => <reply>
|
||||
where => <reply>
|
||||
why => <reply>
|
||||
it => <reply>
|
@ -0,0 +1,3 @@
|
||||
*cthulhu!hastur@*unspeakable.net # an example nick!user@host ban
|
||||
*!*@*nan*direct.ca
|
||||
*!*@200.38.211.*
|
@ -0,0 +1,8 @@
|
||||
what => <reply>
|
||||
who => <reply>
|
||||
when => <reply>
|
||||
where => <reply>
|
||||
why => <reply>
|
||||
it => <reply>
|
||||
how => <reply>
|
||||
infobot guide => http://www.cs.cmu.edu/~infobot/infobot_guide.html
|
@ -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 <file>
|
||||
|
||||
where <file> 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' <file>
|
||||
|
||||
while <file> 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' <file1> <file2> <file3>
|
||||
|
||||
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
|
@ -0,0 +1,652 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>Infobot Guide 0.44.3</title>
|
||||
</head>
|
||||
|
||||
<body bgcolor="#ffffff">
|
||||
<h1>Infobot Guide 0.44.3</h1>
|
||||
|
||||
<hr>
|
||||
The canonical source for the infobot source and documentation is
|
||||
<a href="http://www.cs.cmu.edu/~infobot">http://www.cs.cmu.edu/~infobot</a>.
|
||||
<hr>
|
||||
<p>
|
||||
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.
|
||||
<p>
|
||||
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.
|
||||
<p>
|
||||
|
||||
<hr>
|
||||
<h2> Interacting with an infobot</h2>
|
||||
|
||||
<UL>
|
||||
<LI> <b>setting</b> factoids: X is Y
|
||||
<p>
|
||||
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.
|
||||
<p>
|
||||
<LI> <b>accessing</b> factoids: What is X?
|
||||
<p>
|
||||
You can ask an infobot about something in a number of
|
||||
different ways, including "what is X?", "where is X?",
|
||||
or just plain "X?".
|
||||
</p>
|
||||
<LI> <b>altering</b> factoids: s/A/B/
|
||||
<p>
|
||||
if you just want to change a <i>part</i> of a factoid, use
|
||||
the <code>s///</code>operator. you have to address the bot
|
||||
or use a private medium to do this.
|
||||
<p>
|
||||
MyBot, X =~ s/A/B/
|
||||
<p>
|
||||
will change the first occurence of A to B in the factoid
|
||||
called X.
|
||||
<p>
|
||||
|
||||
<LI>appending to existing entries: <b><code>also</code></b>
|
||||
<p>
|
||||
One can extend an existing factoid using the
|
||||
keyword <code>also</code>
|
||||
<p>
|
||||
<UL>
|
||||
<code>
|
||||
poink is also a silly word
|
||||
</code>
|
||||
</UL>
|
||||
<p>
|
||||
|
||||
<LI>erasing a factoid: <b><code>forget</code></b>
|
||||
<p>
|
||||
A factoid can easily be deleted by using
|
||||
<p>
|
||||
<DIR>
|
||||
<code>
|
||||
infobot, forget poink
|
||||
</code>
|
||||
</DIR>
|
||||
<p>
|
||||
|
||||
<LI>changing a factoid: <code><b>no,</b> ...</code>
|
||||
<p>
|
||||
You can change the entry for a factoid completely using
|
||||
<p>
|
||||
<UL>
|
||||
<code>
|
||||
no, infobot, x is wugga wugga.
|
||||
</code>
|
||||
</UL>
|
||||
<p>
|
||||
which deletes the prior entry (if possible)
|
||||
and replaces it with the new one.
|
||||
<p>
|
||||
|
||||
<LI> having the bot tell someone else something: <b><code>tell</code></b>
|
||||
<p>
|
||||
A user can ask an infobot to tell someone else something.
|
||||
<p>
|
||||
<UL>
|
||||
<code>
|
||||
infobot, tell fimmtiu about no web
|
||||
</code>
|
||||
<p>
|
||||
</UL>
|
||||
|
||||
<LI><b>karma</b> / plusplus
|
||||
<p>
|
||||
karma for a concept may be incremented or decremeted using
|
||||
<code>++</code> and <code>--</code>. You can get the
|
||||
current karma 'score' for something by asking for it.
|
||||
<p>
|
||||
<UL>
|
||||
<code>
|
||||
oznoid++
|
||||
<p>
|
||||
oznoid--
|
||||
<p>
|
||||
karma for oznoid
|
||||
</code>
|
||||
<p>
|
||||
</UL>
|
||||
|
||||
<LI> <code><b>status</b></code>
|
||||
<p>
|
||||
infobots reply to status requests.
|
||||
<p>
|
||||
<dir>
|
||||
-> [url] status<p>
|
||||
[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.
|
||||
</dir>
|
||||
|
||||
</p>
|
||||
|
||||
<LI>joining an allowed channel: <code><b>join</b> #infobot</code>
|
||||
<p>
|
||||
On IRC, you can tell the infobot to join a channel
|
||||
that it's allowed to join with
|
||||
<p>
|
||||
<UL>
|
||||
<code>
|
||||
infobot, join #infobot
|
||||
</code>
|
||||
</UL>
|
||||
<p>
|
||||
If it is allowed to (in its paramter settings), it
|
||||
will try to join the channel.
|
||||
<p>
|
||||
|
||||
|
||||
<LI>leaving a channel: <code><b>part</b> #infobot</code>
|
||||
<p>
|
||||
This causes the bot to leave the given channel
|
||||
<p>
|
||||
<UL>
|
||||
<code>
|
||||
infobot, part #infobot
|
||||
</code>
|
||||
</UL>
|
||||
<p>
|
||||
<code>leave</code> is a synonym for <code>part</code>.
|
||||
<p>
|
||||
|
||||
<LI><b>random</b> responses with <code>|</code>
|
||||
<p>
|
||||
You can set a list from which to pick a random response by
|
||||
using <code>|</code>
|
||||
<p>
|
||||
<UL>
|
||||
<code>
|
||||
x is a|b|c|d
|
||||
</code>
|
||||
</UL>
|
||||
<p>
|
||||
When x is asked about, the infobot will randomly choose from
|
||||
the <code>|</code>-spearated list.
|
||||
<p>
|
||||
|
||||
<LI> The <b><code><reply></code></b> factoid tag.
|
||||
<p>
|
||||
Normally, when the infobot replies to "What is X", it says
|
||||
"X is Y". This form makes it just reply "Y".
|
||||
<p>
|
||||
<UL>
|
||||
<code>
|
||||
X is <reply> Y
|
||||
</code>
|
||||
</UL>
|
||||
<p>
|
||||
|
||||
<LI> The <b><code><action></code></b> factoid tag (as of 0.43.5)
|
||||
<p>
|
||||
This causes the bot to respond as with <reply> except
|
||||
as an ACTION.
|
||||
<p>
|
||||
<UL>
|
||||
<code>
|
||||
X is <action> Y
|
||||
</code>
|
||||
</UL>
|
||||
<p>
|
||||
|
||||
<LI><b>backwacking</b>
|
||||
<p>
|
||||
Use <code>\</code> to protect items from evaluation.
|
||||
<p>
|
||||
<UL>
|
||||
<CODE>
|
||||
x is y is y
|
||||
</CODE>
|
||||
</UL>
|
||||
<p>
|
||||
will normally set <code>x =is=> y is y</code>, but
|
||||
<p>
|
||||
<UL>
|
||||
<CODE>
|
||||
x \is y is y
|
||||
</CODE>
|
||||
</UL>
|
||||
<p>
|
||||
will set
|
||||
<p>
|
||||
<UL>
|
||||
<code>x is y =is=> y</code>
|
||||
</UL>
|
||||
<p>
|
||||
The <code>forget</code>
|
||||
and <code>no</code> (update) operators apply before checking
|
||||
for this. This is also useful for getting around the
|
||||
dereferencing of "i" and "me" and so on.
|
||||
<p>
|
||||
|
||||
<LI>the <b><code>$who</code></b> variable
|
||||
<p>
|
||||
Contains the nickname person currently addressing the bot.
|
||||
It can be used effectively in replies.
|
||||
<p>
|
||||
<UL>
|
||||
<code>
|
||||
nice day is <reply> you betcha, $who.
|
||||
</code>
|
||||
</UL>
|
||||
<p>
|
||||
|
||||
<LI>the <b><code>$date</code></b> variable
|
||||
<p>
|
||||
Contains the current date and time, at the bot's host.
|
||||
<p>
|
||||
|
||||
<LI> <code><b>weather</b> for KAGC</code> (0.43.6+)
|
||||
<p>
|
||||
Retrieves the weather from NOAA station KAGC. See www.noaa.gov.
|
||||
Note: Requires LWP.
|
||||
<p>
|
||||
<UL>
|
||||
<LI> <code><b>metar</b> KAGC</code> (0.43.6+)
|
||||
</UL>
|
||||
<p>
|
||||
Retrieves METAR info from NOAA station KAGC. See www.noaa.gov.
|
||||
Note: Requires Geo::METAR and LWP.
|
||||
<p>
|
||||
<LI> <code><b>nslookup</b> irc.cs.cmu.edu</code>
|
||||
<p>
|
||||
performs DNS lookup or reverse-lookup on the hostname or IP.
|
||||
<p>
|
||||
<LI><code><b>internic</b> yahoo.com</code>
|
||||
<p>
|
||||
gets the internic WHOIS record
|
||||
<p>
|
||||
<LI><code><b>traceroute</b> apple.com</code>
|
||||
<p>
|
||||
gets the traceroute results from the bot's machine to the target machine. Summary only.
|
||||
<p>
|
||||
<LI><b>imdb, websters, foldoc</b>
|
||||
<p>
|
||||
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.
|
||||
<p>
|
||||
<UL>
|
||||
<code>
|
||||
imdb for clerks<p>
|
||||
webster for lucre
|
||||
</code>
|
||||
</UL>
|
||||
|
||||
<p>
|
||||
|
||||
<LI> New in 0.44.3:
|
||||
<p>
|
||||
<UL>
|
||||
<LI> <code><b>literal</b> foo</code>
|
||||
<p>
|
||||
returns the value without the usual post-processing.
|
||||
</p>
|
||||
<LI> <code><b>change</b> 100 USD to DEM</code>
|
||||
<p>
|
||||
converts currency. Retrieves the current exchange rates from the net.
|
||||
Requires LWP.
|
||||
</p>
|
||||
<LI> <code><rss="http://www.foo.com/summary.rss"></code>
|
||||
<p>
|
||||
looks up the RSS file (RDF Site Summary) and returns it
|
||||
in-place where the tag is. Requires XML::RSS and LWP.
|
||||
</p>
|
||||
<LI> <code>give me an excuse</code>, or <code>excuse</code>
|
||||
<p>
|
||||
connects to the excuse server and returns an excuse.
|
||||
requires Net::Telnet.
|
||||
</p>
|
||||
</UL>
|
||||
<p>
|
||||
|
||||
<LI>Ignoring users: <b>ignore</b> nickname, <b>ignore *.a.com</b>
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
<LI><code><b>op</b></code> on channel
|
||||
<p>
|
||||
The 'p' (oP) flag in the userfile allows this
|
||||
to work. You'll need to set a hostmask. See
|
||||
<code>files/infobot.users</code> Also uses a
|
||||
crypted password.
|
||||
<p>
|
||||
<dir>
|
||||
<code>
|
||||
/msg <bot> <password> op
|
||||
</code>
|
||||
</dir>
|
||||
<p>
|
||||
<LI><b><code>die</code></b>
|
||||
<p>
|
||||
If the bot owner (+O, Owner) says this or messages it to the bot,
|
||||
it will kill itself.
|
||||
<p>
|
||||
</UL>
|
||||
|
||||
<hr>
|
||||
<h2> scripts/utilities </h2>
|
||||
|
||||
The infobot comes with some scripts for working with
|
||||
the DBM files.
|
||||
<p>
|
||||
|
||||
<UL>
|
||||
<LI><code>update_db</code>
|
||||
<p>
|
||||
This takes a flat ascii file and inserts it into a DBM file.
|
||||
It creates a new DBM if it didn't exist.
|
||||
<p>
|
||||
<UL>
|
||||
<CODE>
|
||||
scripts/update_db factpacks/code_to_country.txt infobot-is
|
||||
</CODE>
|
||||
</UL>
|
||||
<p>
|
||||
will add the factoids in <code>code_to_country.txt</code>
|
||||
to the <code>infobot-is</code> DBM.
|
||||
<p>
|
||||
If you've set <code>DBMModule</code> in your config file, you
|
||||
need to use the <code>-m</code> switch to specify the alternate
|
||||
module.
|
||||
<p>
|
||||
<UL>
|
||||
<CODE>
|
||||
scripts/update_db -d DB_File factpacks/code_to_country.txt infobot-is
|
||||
</CODE>
|
||||
</UL>
|
||||
<p>
|
||||
<LI><code>dump_db</code>
|
||||
<p>
|
||||
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.
|
||||
<p>
|
||||
<UL>
|
||||
<CODE>
|
||||
scripts/dump_db infobot-is
|
||||
</CODE>
|
||||
</UL>
|
||||
<p>
|
||||
Note there is no extension on the DBM name, even though the
|
||||
system may use one (like <code>.pag</code> and
|
||||
<code>.dir</code> or <code>.db</code>).
|
||||
<p>
|
||||
If you've set <code>DBMModule</code> in your config file, you
|
||||
need to use the <code>-m</code> switch to specify the alternate
|
||||
module.
|
||||
<p>
|
||||
<UL>
|
||||
<CODE>
|
||||
scripts/dump_db -m DB_File infobot-is
|
||||
</CODE>
|
||||
</UL>
|
||||
<p>
|
||||
|
||||
</UL>
|
||||
|
||||
<hr>
|
||||
|
||||
<h3> add-on modules </h3>
|
||||
|
||||
<UL>
|
||||
<LI> <code>nickometer</code>, by Adam Spiers. Guages
|
||||
how 'lame' a nickname is, as a percentage!<p>
|
||||
<UL>
|
||||
<code>
|
||||
nickometer l33tn1ck
|
||||
</code>
|
||||
</UL>
|
||||
<p>
|
||||
|
||||
<LI> <code>babel.pl</code> by jdf. translates using the
|
||||
<a href="http://babelfish.altavista.com/">babelfish</a>
|
||||
web site for machine translation.
|
||||
In this implementation, English is assumed
|
||||
to be the 'main' language, thus everything is
|
||||
translated <code>to</code> or <code>from</code> another
|
||||
language.
|
||||
<p>
|
||||
<UL>
|
||||
<code>
|
||||
(x|translate) (to|from) (de|fr|pt|es|it|german|french|portugese|spanish|italian)
|
||||
<p>
|
||||
translate to german this is a test<br>
|
||||
x to german this is another test<br>
|
||||
x to de and a third<br>
|
||||
x from de ein bisschen Deutsch<p>
|
||||
German, French, Spanish, Italian, and Portugese are
|
||||
currently supported by babelfish.
|
||||
</code>
|
||||
</UL>
|
||||
<p>
|
||||
<LI> <code>METAR</code> support, courtesy of mendel<p>
|
||||
<code>metar KAGC</code>
|
||||
<p>
|
||||
retrieves METAR information for KAGC, the Allegheny
|
||||
County airport station.
|
||||
<p>
|
||||
<LI> <code>NOAA</code> weather station support, courtesy of oznoid<p>
|
||||
<ul>
|
||||
<code>weather KAGC</code>
|
||||
</ul>
|
||||
<p>
|
||||
retrieves the
|
||||
<a href="http://weather.noaa.gov/weather/curcond.html">NOAA</a>
|
||||
weather information from (in this example) KAGC. uses the
|
||||
same
|
||||
<a href="http://weather.noaa.gov/weather/curcond.html">codes</a>
|
||||
as metar info.
|
||||
<p>
|
||||
<LI> <code>slashdot</code> headlines, originally from Chris Tessone,
|
||||
current version from Rahga.<p>
|
||||
<p>
|
||||
<ul>
|
||||
<code>slashdot</code><br>
|
||||
<code>slashdot headlines</code>
|
||||
</ul>
|
||||
<p>
|
||||
retrieves the current slashdot headlines from
|
||||
<a href="http://www.slashdot.org">www.slashdot.org</a>.
|
||||
|
||||
<LI> W3Search: search web engines for links; thanks
|
||||
to Simon Couzins for this one. Requires
|
||||
WWW::Search and WWW::Search::Google.
|
||||
<ul>
|
||||
<code>search google for foo</code><br>
|
||||
<code>google for foo</code><br>
|
||||
<code>altavista for foo</code><br>
|
||||
<code>dejanews for foo</code>
|
||||
</ul>
|
||||
Currently supports what WWW::Search and WWW::Search::Google
|
||||
support, namely: Dejanews, Google, Gopher, Excite, Infoseek,
|
||||
HotBot, Lycos, AltaVista, Magellan, PLweb, SFgate, and Verity.
|
||||
<p>
|
||||
<LI>US Airways In-flight info.
|
||||
<ul>
|
||||
<code>usair flight 781</code>
|
||||
</ul>
|
||||
retrieves the in-flight information for the
|
||||
appropriate USAir flight. Note: Requires LWP.
|
||||
</UL>
|
||||
|
||||
<hr>
|
||||
|
||||
<h2> setting up </h2>
|
||||
|
||||
<h3> configuration </h3>
|
||||
<UL>
|
||||
<LI> <b> editing the parameter file </b>
|
||||
<p>
|
||||
|
||||
The parameter file, usually in <code>files/infobot.config</code>,
|
||||
is the most direct way to customize the settings on your infobot.
|
||||
<p>
|
||||
|
||||
<LI> <b>editing the user file</b>
|
||||
<p>
|
||||
|
||||
The user file, usually in <code>files/infobot.users</code>,
|
||||
is the most direct way to customize the settings on your infobot.
|
||||
<p>
|
||||
|
||||
|
||||
<LI> <b> editing the main script </b>
|
||||
<p>
|
||||
|
||||
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
|
||||
<p>
|
||||
<UL>
|
||||
<LI> <b> changing the bang path to perl </b>
|
||||
<p>
|
||||
If you get
|
||||
<p>
|
||||
<UL>
|
||||
<code>
|
||||
infobot: Command not found.
|
||||
</code>
|
||||
</UL>
|
||||
<p>
|
||||
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
|
||||
<p>
|
||||
<UL>
|
||||
<code>
|
||||
#!/path/to/perl
|
||||
</code>
|
||||
</UL>
|
||||
<p>
|
||||
with, of course, the full path to your perl binary.
|
||||
<p>
|
||||
|
||||
<LI> <b> explicitly setting normally relative paths </b>
|
||||
<p>
|
||||
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.
|
||||
<p>
|
||||
</ul>
|
||||
<LI> <b>Installing Modules to enable features</b>
|
||||
<p>
|
||||
Several add-ons, like <code>weather</code> and
|
||||
web <code>search</code> 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 <a href="http://www.perl.com/CPAN/modules-by-module/CPAN/">CPAN</a>, and use it to install what you need. This
|
||||
is best done as root.<p>
|
||||
Once you have the CPAN module installed, use
|
||||
it to install the required modules:
|
||||
<p>
|
||||
<ul>
|
||||
<li>the main thing: <code>install Bundle::LWP</code>
|
||||
<li>for METAR: <code>install Geo::METAR</code>
|
||||
<li>for W3Search:
|
||||
<ul>
|
||||
<li><code>install WWW::Search</code>
|
||||
<li><code>install WWW::Search::Google</code>
|
||||
</ul>
|
||||
</ul>
|
||||
Once these are installed, start or restart your infobot.
|
||||
</UL>
|
||||
<p>
|
||||
</UL>
|
||||
<hr>
|
||||
|
||||
<h3> running the infobot </h3>
|
||||
|
||||
<UL>
|
||||
<LI> <b>starting it up</b>
|
||||
<p>
|
||||
This should be as simple as entering the infobot
|
||||
parent directory and executing
|
||||
<p>
|
||||
<UL>
|
||||
<code>
|
||||
infobot
|
||||
</code>
|
||||
</UL>
|
||||
<p>
|
||||
|
||||
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 <code>VERBOSITY</code> parameter,
|
||||
of you can dump all the output to the bitbucket and background
|
||||
the process at the same time with
|
||||
<p>
|
||||
<UL>
|
||||
<code>
|
||||
nohup infobot > /dev/null &
|
||||
</code>
|
||||
</UL>
|
||||
<p>
|
||||
|
||||
<LI> <b>the console</b>
|
||||
<p>
|
||||
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 <b>console</b>.
|
||||
|
||||
<p>
|
||||
The first thing you should see, assuming all goes well with
|
||||
making a connection, is the <b>motd</b> (message-of-the-day)
|
||||
of the server the bot has been configured to connect to.
|
||||
<p>
|
||||
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.
|
||||
<p>
|
||||
If you have the <code>ansi_control</code> paramter set,
|
||||
and your terminal supports it, the output will be in color.
|
||||
<p>
|
||||
NOTE that the 'console' is NOT interactive. You can't
|
||||
type anything into it; it's just for viewing what's going on.
|
||||
<p>
|
||||
<LI> <b><code>cron</code>ning the infobot</b>
|
||||
<p>
|
||||
You can set the infobot to automatically start up using
|
||||
<code>cron</code>. See the included example <code>crontab</code>
|
||||
file, in <code>files/infobot.crontab</code>
|
||||
</UL>
|
||||
<hr>
|
||||
|
||||
<h3> shutting it down </h3>
|
||||
|
||||
If you have set yourself as the bot's master in the user file
|
||||
(<code>infobot.users</code>, unless you changed the default),
|
||||
you can just say or message 'die' to the bot.
|
||||
<p>
|
||||
Otherwise, kill the process or hit control-c in the console.
|
||||
<p>
|
||||
|
||||
<hr>
|
||||
|
||||
<h2> the FAQ </h2>
|
||||
The FAQ is available at
|
||||
<a href="http://www.cs.cmu.edu/~infobot/faq/">
|
||||
http://www.cs.cmu.edu/~infobot/faq/</a>. It is growing. Slowly.
|
||||
|
||||
<hr>
|
||||
<address><a href="mailto:infobot@protected.speech.cs.cmu.edu">infobot@protected.speech.cs.cmu.edu</a></address>
|
||||
<!-- Created: Sat Aug 15 12:00:57 EDT 1998 -->
|
||||
<!-- hhmts start -->
|
||||
Last modified: Tue Oct 26 14:24:41 EDT 1999
|
||||
<!-- hhmts end -->
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,312 @@
|
||||
<hr>
|
||||
The canonical source for the infobot source and documentation is
|
||||
<a href="http://www.infobot.org/">http://www.infobot.org/</a>.
|
||||
<hr>
|
||||
<p>
|
||||
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.
|
||||
<p>
|
||||
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.
|
||||
<p>
|
||||
|
||||
<hr>
|
||||
<h2> Interacting with an infobot</h2>
|
||||
|
||||
<UL>
|
||||
<LI> <b>setting</b> factoids: X is Y
|
||||
<p>
|
||||
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.
|
||||
<p>
|
||||
<LI> <b>accessing</b> factoids: What is X?
|
||||
<p>
|
||||
You can ask an infobot about something in a number of
|
||||
different ways, including "what is X?", "where is X?",
|
||||
or just plain "X?".
|
||||
</p>
|
||||
<LI> <b>altering</b> factoids: s/A/B/
|
||||
<p>
|
||||
if you just want to change a <i>part</i> of a factoid, use
|
||||
the <code>s///</code>operator. you have to address the bot
|
||||
or use a private medium to do this.
|
||||
<p>
|
||||
MyBot, X =~ s/A/B/
|
||||
<p>
|
||||
will change the first occurence of A to B in the factoid
|
||||
called X.
|
||||
<p>
|
||||
|
||||
<LI>appending to existing entries: <b><code>also</code></b>
|
||||
<p>
|
||||
One can extend an existing factoid using the
|
||||
keyword <code>also</code>
|
||||
<p>
|
||||
<UL>
|
||||
<code>
|
||||
poink is also a silly word
|
||||
</code>
|
||||
</UL>
|
||||
<p>
|
||||
|
||||
<LI>erasing a factoid: <b><code>forget</code></b>
|
||||
<p>
|
||||
A factoid can easily be deleted by using
|
||||
<p>
|
||||
<DIR>
|
||||
<code>
|
||||
infobot, forget poink
|
||||
</code>
|
||||
</DIR>
|
||||
<p>
|
||||
|
||||
<LI>changing a factoid: <code><b>no,</b> ...</code>
|
||||
<p>
|
||||
You can change the entry for a factoid completely using
|
||||
<p>
|
||||
<UL>
|
||||
<code>
|
||||
no, infobot, x is wugga wugga.
|
||||
</code>
|
||||
</UL>
|
||||
<p>
|
||||
which deletes the prior entry (if possible)
|
||||
and replaces it with the new one.
|
||||
<p>
|
||||
|
||||
<LI> having the bot tell someone else something: <b><code>tell</code></b>
|
||||
<p>
|
||||
A user can ask an infobot to tell someone else something.
|
||||
<p>
|
||||
<UL>
|
||||
<code>
|
||||
infobot, tell fimmtiu about no web
|
||||
</code>
|
||||
<p>
|
||||
</UL>
|
||||
|
||||
<LI><b>karma</b> / plusplus
|
||||
<p>
|
||||
karma for a concept may be incremented or decremeted using
|
||||
<code>++</code> and <code>--</code>. You can get the
|
||||
current karma 'score' for something by asking for it.
|
||||
<p>
|
||||
<UL>
|
||||
<code>
|
||||
oznoid++
|
||||
<p>
|
||||
oznoid--
|
||||
<p>
|
||||
karma for oznoid
|
||||
</code>
|
||||
<p>
|
||||
</UL>
|
||||
|
||||
<LI> <code><b>status</b></code>
|
||||
<p>
|
||||
infobots reply to status requests.
|
||||
<p>
|
||||
<dir>
|
||||
-> [url] status<p>
|
||||
[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.
|
||||
</dir>
|
||||
|
||||
</p>
|
||||
|
||||
<LI>joining an allowed channel: <code><b>join</b> #infobot</code>
|
||||
<p>
|
||||
On IRC, you can tell the infobot to join a channel
|
||||
that it's allowed to join with
|
||||
<p>
|
||||
<UL>
|
||||
<code>
|
||||
infobot, join #infobot
|
||||
</code>
|
||||
</UL>
|
||||
<p>
|
||||
If it is allowed to (in its paramter settings), it
|
||||
will try to join the channel.
|
||||
<p>
|
||||
|
||||
|
||||
<LI>leaving a channel: <code><b>part</b> #infobot</code>
|
||||
<p>
|
||||
This causes the bot to leave the given channel
|
||||
<p>
|
||||
<UL>
|
||||
<code>
|
||||
infobot, part #infobot
|
||||
</code>
|
||||
</UL>
|
||||
<p>
|
||||
<code>leave</code> is a synonym for <code>part</code>.
|
||||
<p>
|
||||
|
||||
<LI><b>random</b> responses with <code>|</code>
|
||||
<p>
|
||||
You can set a list from which to pick a random response by
|
||||
using <code>|</code>
|
||||
<p>
|
||||
<UL>
|
||||
<code>
|
||||
x is a|b|c|d
|
||||
</code>
|
||||
</UL>
|
||||
<p>
|
||||
When x is asked about, the infobot will randomly choose from
|
||||
the <code>|</code>-spearated list.
|
||||
<p>
|
||||
|
||||
<LI> The <b><code><reply></code></b> factoid tag.
|
||||
<p>
|
||||
Normally, when the infobot replies to "What is X", it says
|
||||
"X is Y". This form makes it just reply "Y".
|
||||
<p>
|
||||
<UL>
|
||||
<code>
|
||||
X is <reply> Y
|
||||
</code>
|
||||
</UL>
|
||||
<p>
|
||||
|
||||
<LI> The <b><code><action></code></b> factoid tag (as of 0.43.5)
|
||||
<p>
|
||||
This causes the bot to respond as with <reply> except
|
||||
as an ACTION.
|
||||
<p>
|
||||
<UL>
|
||||
<code>
|
||||
X is <action> Y
|
||||
</code>
|
||||
</UL>
|
||||
<p>
|
||||
|
||||
<LI><b>backwacking</b>
|
||||
<p>
|
||||
Use <code>\</code> to protect items from evaluation.
|
||||
<p>
|
||||
<UL>
|
||||
<CODE>
|
||||
x is y is y
|
||||
</CODE>
|
||||
</UL>
|
||||
<p>
|
||||
will normally set <code>x =is=> y is y</code>, but
|
||||
<p>
|
||||
<UL>
|
||||
<CODE>
|
||||
x \is y is y
|
||||
</CODE>
|
||||
</UL>
|
||||
<p>
|
||||
will set
|
||||
<p>
|
||||
<UL>
|
||||
<code>x is y =is=> y</code>
|
||||
</UL>
|
||||
<p>
|
||||
The <code>forget</code>
|
||||
and <code>no</code> (update) operators apply before checking
|
||||
for this. This is also useful for getting around the
|
||||
dereferencing of "i" and "me" and so on.
|
||||
<p>
|
||||
|
||||
<LI>the <b><code>$who</code></b> variable
|
||||
<p>
|
||||
Contains the nickname person currently addressing the bot.
|
||||
It can be used effectively in replies.
|
||||
<p>
|
||||
<UL>
|
||||
<code>
|
||||
nice day is <reply> you betcha, $who.
|
||||
</code>
|
||||
</UL>
|
||||
<p>
|
||||
|
||||
<LI>the <b><code>$date</code></b> variable
|
||||
<p>
|
||||
Contains the current date and time, at the bot's host.
|
||||
<p>
|
||||
|
||||
<LI> <code><b>literal</b> foo</code>
|
||||
<p>
|
||||
returns the value without the usual post-processing.
|
||||
</p>
|
||||
<p>
|
||||
|
||||
<LI>Ignoring users: <b>ignore</b> nickname, <b>ignore *.a.com</b>
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
<LI><code><b>op</b></code> on channel
|
||||
<p>
|
||||
The 'p' (oP) flag in the userfile allows this
|
||||
to work. You'll need to set a hostmask. See
|
||||
<code>files/infobot.users</code> Also uses a
|
||||
crypted password.
|
||||
<p>
|
||||
<dir>
|
||||
<code>
|
||||
/msg <bot> <password> op
|
||||
</code>
|
||||
</dir>
|
||||
<p>
|
||||
<LI><b><code>die</code></b>
|
||||
<p>
|
||||
If the bot owner (+O, Owner) says this or messages it to the bot,
|
||||
it will kill itself.
|
||||
<p>
|
||||
</UL>
|
||||
|
||||
<hr>
|
||||
<h2> scripts/utilities </h2>
|
||||
|
||||
The infobot comes with some scripts for working with
|
||||
the DBM files.
|
||||
<p>
|
||||
|
||||
<UL>
|
||||
<LI><code>update_db</code>
|
||||
<p>
|
||||
This takes a flat ascii file and inserts it into a DBM file.
|
||||
It creates a new DBM if it didn't exist.
|
||||
<p>
|
||||
<UL>
|
||||
<CODE>
|
||||
scripts/update_db factpacks/code_to_country.txt infobot-is
|
||||
</CODE>
|
||||
</UL>
|
||||
<p>
|
||||
will add the factoids in <code>code_to_country.txt</code>
|
||||
to the <code>infobot-is</code> DBM.
|
||||
<p>
|
||||
<LI><code>dump_db</code>
|
||||
<p>
|
||||
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.
|
||||
<p>
|
||||
<UL>
|
||||
<CODE>
|
||||
scripts/dump_db infobot-is
|
||||
</CODE>
|
||||
</UL>
|
||||
<p>
|
||||
Note there is no extension on the DBM name, even though the
|
||||
system may use one (like <code>.pag</code> and
|
||||
<code>.dir</code> or <code>.db</code>).
|
||||
<p>
|
||||
|
||||
</UL>
|
||||
|
||||
<hr>
|
||||
|
@ -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 <<EOF;
|
||||
|
||||
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>Infobot Guide $VER_MAJ\.$VER_MIN\.$VER_MOD</title>
|
||||
</head>
|
||||
|
||||
<body bgcolor="#ffffff">
|
||||
<h1>Infobot Guide $VER_MAJ\.$VER_MIN\.$VER_MOD</h1>
|
||||
|
||||
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 <BIT1>;}
|
||||
|
||||
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 <BIT1>;}
|
||||
|
||||
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 (<FH>) {
|
||||
$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
|
||||
}
|
@ -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;
|
@ -0,0 +1,414 @@
|
||||
#
|
||||
# aviation -- infobot module for various flight-planning bits.
|
||||
# Was originally 'metar' until infobot 44.5.
|
||||
#
|
||||
# 1999/07/?? Rich Lafferty <rich@alcor.concordia.ca>
|
||||
# - 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 <lazarus@frontiernet.net>
|
||||
# - 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 '<function name> 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 <code>'. 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.*?)</s;
|
||||
my $metar = $1;
|
||||
$metar =~ s/\n//gm;
|
||||
$metar =~ s/\s+/ /g;
|
||||
|
||||
# Sane?
|
||||
return "I can't find any observations for $site_id." if length($metar) < 10;
|
||||
|
||||
return $metar;
|
||||
}
|
||||
else {
|
||||
# malformed
|
||||
return "That doesn't look right. The 'metar' command takes an airport identifier and returns the current conditions at the airport in METAR format. (Also, try 'metar HELP'.)";
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# TAF - terminal area (aerodrome) forecast
|
||||
#
|
||||
sub taf {
|
||||
my $line = shift;
|
||||
if ($line =~ /^taf\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 a forecast, ask me 'taf <ICAO code>'. 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 .*?)</s;
|
||||
my $taf = $1;
|
||||
$taf =~ s/\n//gm;
|
||||
$taf =~ s/\s+/ /g;
|
||||
|
||||
# Optionally highlight beginnings of parts of the forecast. Some
|
||||
# find it useful, some find it obnoxious, so it's configurable. :-)
|
||||
$taf =~ s/(FM\d+Z?|TEMPO \d+|BECMG \d+|PROB\d+)/\cB$1\cB/g if $taf_highlight_bold;
|
||||
|
||||
# Sane?
|
||||
return "I can't find any forecast for $site_id." if length($taf) < 10;
|
||||
|
||||
return $taf;
|
||||
}
|
||||
else {
|
||||
# malformed
|
||||
return "That doesn't look right. The 'taf' command takes an airport identifier as an argument and returns the aerodrome forecast for the airport in TAF format. (Also, try 'taf HELP'.)";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#
|
||||
# greatcircle -- calculate great circle distance and heading between
|
||||
# two airports
|
||||
sub greatcircle {
|
||||
my $line = shift;
|
||||
if ($line =~ /^great-?circle\s+((from|between|for)\s+)?(\w+)\s+((and|to)\s)?(\w+)/i) {
|
||||
|
||||
# See metar part for explanation of this bit.
|
||||
my $orig_apt = uc($3);
|
||||
my $dest_apt = uc($6);
|
||||
|
||||
$dest_apt =~ s/[.?!]$//;
|
||||
$dest_apt =~ s/\s+$//g;
|
||||
|
||||
return "'$orig_apt' doesn't look like a valid ICAO airport identifier."
|
||||
unless $orig_apt =~ /^[\w\d]{3,4}$/;
|
||||
return "'$dest_apt' doesn't look like a valid ICAO airport identifier."
|
||||
unless $dest_apt =~ /^[\w\d]{3,4}$/;
|
||||
|
||||
$orig_apt = "C" . $orig_apt if length($orig_apt) == 3 && $orig_apt =~ /^Y/;
|
||||
$orig_apt = "K" . $orig_apt if length($orig_apt) == 3;
|
||||
|
||||
$dest_apt = "C" . $dest_apt if length($dest_apt) == 3 && $dest_apt =~ /^Y/;
|
||||
$dest_apt = "K" . $dest_apt if length($dest_apt) == 3;
|
||||
|
||||
my $gc_url = "http://www6.landings.com/cgi-bin/nph-dist_apt?airport1=$orig_apt&airport2=$dest_apt";
|
||||
|
||||
# Grab great-circle data
|
||||
my $agent = new LWP::UserAgent;
|
||||
if (my $proxy = main::getparam('httpproxy')) { $agent->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: <b>[^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: <b>([^n]+?)</b>|;
|
||||
}
|
||||
|
||||
$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__
|
@ -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] <host>
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Looks up DNS entries for the given host using
|
||||
C<gethostbyaddr>/C<gethostbyname> calls.
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
Kevin Lenzo
|
@ -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
|
||||
# <purl> 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 (<MAGIC8>) {
|
||||
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;
|
||||
|
@ -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 = <DOMAIN_SERVER>)) {
|
||||
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 <host>
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Queries RIPE or the Internic for the whois information about the
|
||||
supplied host, and formats it up nicely.
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
Kevin Lenzo
|
@ -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 (<P>) {
|
||||
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;
|
@ -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.*?</TR>||is;
|
||||
|
||||
$content =~ s|.*?<TR>(?:\s*<[^>]+>)*\s*([^<]+)\s<.*?</TR>||is;
|
||||
my $place = $1;
|
||||
chomp $place;
|
||||
|
||||
$content =~ s|.*?<TR>(?:\s*<[^>]+>)*\s*([^<]+)\s<.*?</TR>||is;
|
||||
my $id = $1;
|
||||
chomp $id;
|
||||
|
||||
$content =~ s|.*?conditions at.*?</TD>||is;
|
||||
|
||||
$content =~ s|.*?<OPTION SELECTED>\s+([^<]+)\s<OPTION>.*?</TR>||s;
|
||||
my $time = $1;
|
||||
$time =~ s/-//g;
|
||||
$time =~ s/\s+/ /g;
|
||||
|
||||
$content =~ s|\s(.*?)<TD COLSPAN=2>||s;
|
||||
my $features = $1;
|
||||
|
||||
while ($features =~ s|.*?<TD ALIGN[^>]*>(?:\s*<[^>]+>)*\s+([^<]+?)\s+<.*?<TD>(?:\s*<[^>]+>)*\s+([^<]+?)\s<.*?/TD>||s) {
|
||||
my ($f,$v) = ($1, $2);
|
||||
chomp $f; chomp $v;
|
||||
$feat{$f} = $v;
|
||||
}
|
||||
|
||||
$content =~ s|.*?>(\d+\S+\s+\(\S+\)).*?</TD>||s; # max temp;
|
||||
$max_temp = $1;
|
||||
$content =~ s|.*?>(\d+\S+\s+\(\S+\)).*?</TD>||s;
|
||||
$min_temp = $1;
|
||||
|
||||
if ($time) {
|
||||
$result = "$place; $id; last updated: $time";
|
||||
foreach (sort keys %feat) {
|
||||
next if $_ eq 'ob';
|
||||
$result .= "; $_: $feat{$_}";
|
||||
}
|
||||
my $t = time();
|
||||
$cache{$station} = join $;, $t, $result;
|
||||
} else {
|
||||
$result = "I can't find that station code (see http://weather.noaa.gov/weather/curcond.html for locations and codes)";
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
if (0) {
|
||||
if (-t STDIN) {
|
||||
my $result = Weather::NOAA::get($default);
|
||||
$result =~ s/; /\n/g;
|
||||
print "\n$result\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
NOAA.pl - Get the weather from a NOAA server
|
||||
|
||||
=head1 PREREQUISITES
|
||||
|
||||
LWP::UserAgent
|
||||
|
||||
=head1 PARAMETERS
|
||||
|
||||
weather
|
||||
|
||||
=head1 PUBLIC INTERFACE
|
||||
|
||||
weather [for] <station>
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Contacts C<weather.noaa.gov> and gets the weather report for a given
|
||||
station.
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
Kevin Lenzo
|
@ -0,0 +1,89 @@
|
||||
|
||||
# LotR++ for this one
|
||||
# minor mods by lenzo@cs.cmu.edu
|
||||
|
||||
BEGIN {
|
||||
eval qq{
|
||||
use LWP::UserAgent;
|
||||
use XML::RSS;
|
||||
use HTTP::Request::Common qw(GET);
|
||||
};
|
||||
|
||||
$no_headlines++ if($@);
|
||||
}
|
||||
|
||||
sub get_headlines {
|
||||
my ($rdf_loc) = @_;
|
||||
|
||||
if ($no_headlines) {
|
||||
return "error: RDF headlines require LWP::UserAgent, XML::RSS, and HTTP::Request... sorry.";
|
||||
}
|
||||
|
||||
if ($rdf_loc) {
|
||||
&status("getting headlines from $rdf_loc");
|
||||
|
||||
my $ua = new LWP::UserAgent;
|
||||
if (my $proxy = main::getparam('httpproxy')) { $ua->proxy('http', $proxy) };
|
||||
$ua->timeout(10);
|
||||
|
||||
my $request = new HTTP::Request ("GET", $rdf_loc);
|
||||
my $result = $ua->request ($request);
|
||||
|
||||
if ($result->is_success) {
|
||||
my ($str);
|
||||
$str = $result->content;
|
||||
$rss = new XML::RSS;
|
||||
eval { $rss->parse($str); };
|
||||
if ($@) {
|
||||
return "that gave some error";
|
||||
} else {
|
||||
my $return;
|
||||
|
||||
foreach my $item (@{$rss->{"items"}}) {
|
||||
$return .= $item->{"title"} . "; ";
|
||||
last if length($return) > $param{maxDataSize};
|
||||
}
|
||||
|
||||
$return =~ s/; $//;
|
||||
|
||||
return $return;
|
||||
}
|
||||
} else {
|
||||
return "error: $rdf_loc wasn't successful";
|
||||
}
|
||||
} else {
|
||||
return "error: no location stored for $where";
|
||||
}
|
||||
};
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
RDF.pl - Read RDF files into factoids
|
||||
|
||||
=head1 PREREQUISITES
|
||||
|
||||
LWP::UserAgent
|
||||
XML::RSS
|
||||
HTTP::Request::Common
|
||||
|
||||
=head1 PARAMETERS
|
||||
|
||||
rss
|
||||
|
||||
|
||||
=head1 PUBLIC INTERFACE
|
||||
|
||||
<site> is <rss="site.rdf">
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This allows you to read and parse RSS files; RSS is a format
|
||||
for getting news headlines off web news services.
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
LotR <martijn@earthling.net> and Kevin Lenzo, of course.
|
@ -0,0 +1,98 @@
|
||||
#####################
|
||||
# #
|
||||
# Slashdot.pl for #
|
||||
# SlashDot headline #
|
||||
# retrival #
|
||||
# tessone@imsa.edu #
|
||||
# Chris Tessone #
|
||||
# Licensing: #
|
||||
# Artistic License #
|
||||
# (as perl itself) #
|
||||
#####################
|
||||
#fixed up to use XML'd /. backdoor 7/31 by richardh@rahga.com
|
||||
#My only request if this gets included in infobot is that the
|
||||
#other header gets trimmed to 2 lines, dump the fluff ;) -rah
|
||||
|
||||
#added a status message so people know to install LWP - oznoid
|
||||
#also simplified the return code because it wasn't working.
|
||||
|
||||
use strict;
|
||||
|
||||
my $no_slashlines;
|
||||
|
||||
|
||||
BEGIN {
|
||||
$no_slashlines = 0;
|
||||
eval "use LWP::UserAgent";
|
||||
$no_slashlines++ if $@;
|
||||
}
|
||||
|
||||
sub getslashdotheads {
|
||||
# configure
|
||||
if ($no_slashlines) {
|
||||
&status("slashdot headlines requires LWP to be installed");
|
||||
return '';
|
||||
}
|
||||
my $ua = new LWP::UserAgent;
|
||||
if (my $proxy = main::getparam('httpproxy')) { $ua->proxy('http', $proxy) };
|
||||
$ua->timeout(12);
|
||||
my $maxheadlines=5;
|
||||
my $slashurl='http://www.slashdot.org/slashdot.xml';
|
||||
my $story=0;
|
||||
my $slashindex = new HTTP::Request('GET',$slashurl);
|
||||
my $response = $ua->request($slashindex);
|
||||
|
||||
if($response->is_success) {
|
||||
$response->content =~ /<time>(.*?)<\/time>/;
|
||||
my $lastupdate=$1;
|
||||
my $headlines = "Slashdot - Updated ".$lastupdate;
|
||||
my @indexhtml = split(/\n/,$response->content);
|
||||
|
||||
# gonna read in this xml stuff.
|
||||
foreach(@indexhtml) {
|
||||
if (/<story>/){$story++;}
|
||||
elsif (/<title>(.*?)<\/title>/){
|
||||
$headlines .= " | $1";
|
||||
}
|
||||
elsif (/<url>(.*?)<\/url>/){
|
||||
# do nothing
|
||||
}
|
||||
elsif (/<time>(.*?)<\/time>/){
|
||||
# do nothing
|
||||
}
|
||||
last if $story >= $maxheadlines;
|
||||
next;
|
||||
}
|
||||
|
||||
return $headlines;
|
||||
} else {
|
||||
return "I can't find the headlines.";
|
||||
}
|
||||
}
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Slashdot3.pl - Slashdot headlines grabber
|
||||
|
||||
=head1 PREREQUISITES
|
||||
|
||||
LWP::UserAgent
|
||||
|
||||
=head1 PARAMETERS
|
||||
|
||||
slashdot
|
||||
|
||||
=head1 PUBLIC INTERFACE
|
||||
|
||||
slashdot [headlines]
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Retrieves the headlines from Slashdot; probably obsoleted by RDF.
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
Chris Tessone <tessone@imsa.edu>
|
@ -0,0 +1,47 @@
|
||||
|
||||
# infobot :: Kevin Lenzo (c) 1997
|
||||
|
||||
# doce++ for the first version of this!
|
||||
|
||||
sub ispell {
|
||||
my $in = $_[0];
|
||||
|
||||
$in =~ s/^\s+//;
|
||||
$in =~ s/\s+$//;
|
||||
|
||||
return "$in looks funny" unless $in =~ /^\w+$/;
|
||||
|
||||
#derr@rostrum# ispell -a
|
||||
#@(#) International Ispell Version 3.1.20 10/10/95
|
||||
#peice
|
||||
#& peice 4 0: peace, pence, piece, price
|
||||
|
||||
my @tr = `echo $in | ispell -a -S`;
|
||||
|
||||
if (grep /^\*/, @tr) {
|
||||
my $result = "'$in' may be spelled correctly";
|
||||
if ($msgType =~ /private/) {
|
||||
&msg($who, $result);
|
||||
} else {
|
||||
&say("$who: $result");
|
||||
}
|
||||
} else {
|
||||
@tr = grep /^\s*&/, @tr;
|
||||
chomp $tr[0];
|
||||
($junk, $word, $junk, $junk, @rest) = split(/\ |\,\ /,$tr[0]);
|
||||
my $result = "Possible spellings for $in: @rest";
|
||||
if (scalar(@rest) == 0) {
|
||||
$result = "I can't find alternate spellings for '$in'";
|
||||
}
|
||||
if ($msgType =~ /private/) {
|
||||
&msg($who, $result);
|
||||
} else {
|
||||
&say($result);
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
|
||||
1;
|
||||
|
@ -0,0 +1,67 @@
|
||||
|
||||
# infobot :: Kevin Lenzo (c) 1997
|
||||
# with thanks to Patrick Cole
|
||||
|
||||
use POSIX;
|
||||
|
||||
sub T_REAPER {
|
||||
$SIG{CHLD} = \&REAPER; # loathe sysV
|
||||
$waitedpid = wait;
|
||||
}
|
||||
|
||||
$SIG{CHLD} = \&T_REAPER;
|
||||
|
||||
sub troute {
|
||||
my $in = $_[0];
|
||||
|
||||
if (!defined($pid = fork)) {
|
||||
return "no luck, $safeWho";
|
||||
} elsif ($pid) {
|
||||
# parent
|
||||
} else {
|
||||
# child
|
||||
if ($in !~ /^[-_a-zA-Z0-9]+(\.[-_a-zA-Z0-9]+)+$/) {
|
||||
&status("malformed traceroute: :$in:\n");
|
||||
exit;
|
||||
}
|
||||
|
||||
@tr = `traceroute $in`;
|
||||
chomp($out = $tr[@tr-1]);
|
||||
if ($msgType eq 'public') {
|
||||
&msg($who, $out);
|
||||
# &say($out);
|
||||
} else {
|
||||
&msg($who, $out);
|
||||
}
|
||||
exit; # kill child
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
DNS.pl - Look up hosts in DNS
|
||||
|
||||
=head1 PREREQUISITES
|
||||
|
||||
External `traceroute' application
|
||||
|
||||
=head1 PARAMETERS
|
||||
|
||||
allowTraceroute
|
||||
|
||||
=head1 PUBLIC INTERFACE
|
||||
|
||||
traceroute <host>
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Shells out to the `traceroute' application to trace the route to a
|
||||
host.
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
Kevin Lenzo and Patrick Cole
|
@ -0,0 +1,133 @@
|
||||
# WWWSearch backend, with queries updating the is-db (optionally)
|
||||
# Uses WWW::Search::Google and WWW::Search
|
||||
# originally Google.pl, drastically altered.
|
||||
|
||||
use strict;
|
||||
|
||||
package W3Search;
|
||||
|
||||
my @engines;
|
||||
my $no_W3Search;
|
||||
|
||||
BEGIN {
|
||||
$no_W3Search = 0;
|
||||
eval "use WWW::Search";
|
||||
$no_W3Search++ if $@;
|
||||
@engines = qw(AltaVista Dejanews Excite Gopher HotBot Infoseek
|
||||
Lycos Magellan PLweb SFgate Simple Verity Google);
|
||||
$W3Search::regex = join '|', @engines;
|
||||
}
|
||||
|
||||
sub forking_W3Search {
|
||||
if ($no_W3Search) {
|
||||
&main::status("W3Search: this requires WWW::Search::Google to operate.");
|
||||
return '';
|
||||
}
|
||||
|
||||
my ($where, $what, $type, $callback) = @_;
|
||||
$SIG{CHLD} = 'IGNORE';
|
||||
my $pid = eval { fork() }; # catch non-forking OSes and other errors
|
||||
return 'NOREPLY' if $pid; # parent does nothing
|
||||
$callback->(W3Search($where, $what, $type));
|
||||
exit 0 if defined $pid; # child exits, non-forking OS returns
|
||||
}
|
||||
|
||||
sub W3Search {
|
||||
if ($no_W3Search) {
|
||||
&status("WWW search requires WWW::Search and WWW::Search::Google");
|
||||
return 'sorry, can\'t do that';
|
||||
} else {
|
||||
my ($where, $what, $type) = @_;
|
||||
|
||||
my @matches = grep { lc($_) eq lc($where) ? $_ : undef } @engines;
|
||||
if (!@matches) {
|
||||
return "i don't know how to check '$where'";
|
||||
} else {
|
||||
$where = shift @matches;
|
||||
}
|
||||
|
||||
my $Search = new WWW::Search($where);
|
||||
my $Query = WWW::Search::escape_query($what);
|
||||
$Search->native_query($Query);
|
||||
|
||||
my ($Result, $r, $count);
|
||||
while ($r = $Search->next_result()) {
|
||||
if ($Result) {
|
||||
$Result .= " or ".$r->url();
|
||||
} else {
|
||||
$Result = $r->url();
|
||||
}
|
||||
last if ++$count >= 3;
|
||||
}
|
||||
|
||||
if ($Result) {
|
||||
if ($type =~ /update/) {
|
||||
$main::correction_plausible++ if $type =~ /force/i;
|
||||
$main::addressed++;
|
||||
$main::googling = 1;
|
||||
&main::update($what, "is", $Result);
|
||||
$main::googling = 0;
|
||||
}
|
||||
return "$where says $what is $Result";
|
||||
} else {
|
||||
return "$where can't find $what";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
W3Search.pl - Forking web search interface
|
||||
|
||||
=head1 PREREQUISITES
|
||||
|
||||
|
||||
WWW::Search
|
||||
WWW::Search::Google
|
||||
Probably some LWP stuff as well.
|
||||
|
||||
=head1 PARAMETERS
|
||||
|
||||
|
||||
wwwsearch
|
||||
|
||||
=over 4
|
||||
|
||||
=item update
|
||||
|
||||
URLs retrieved will be added to the `is' database if no entry for the
|
||||
search term exists.
|
||||
|
||||
=item force
|
||||
|
||||
URLs retrieved will be added to the `is' database even if a previous
|
||||
entry for the search term exists.
|
||||
|
||||
=back
|
||||
|
||||
=head1 PUBLIC INTERFACE
|
||||
|
||||
|
||||
[search] <engine> for <entry>
|
||||
|
||||
Where E<lt>C<engine>E<gt> is one of
|
||||
|
||||
AltaVista Dejanews Excite Gopher HotBot Infoseek
|
||||
Lycos Magellan PLweb SFgate Simple Verity Google
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
|
||||
Does exactly what it says on the tin; looks up things in web search
|
||||
engines and brings you back the results.
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
|
||||
Original Google.pl was by Simon <simon@brecon.co.uk>, converted and
|
||||
generalised to this by Kevin Lenzo <lenzo@cs.cmu.edu>. Documentation
|
||||
by Simon.
|
@ -0,0 +1,615 @@
|
||||
#
|
||||
# zippy -- infobot module for Zippy the Pinhead quotes
|
||||
# hacked up by Rich Lafferty (mendel) <rich@vax2.concordia.ca>
|
||||
#
|
||||
# Data gratuitously swiped from fortune-mod-9708, the 'fortune' program.
|
||||
#
|
||||
|
||||
package zippy;
|
||||
|
||||
my $no_zippy; # Can't think of any situation in which this won't work..
|
||||
|
||||
sub zippy::get {
|
||||
my $line = shift;
|
||||
unless ($line =~ /^yow[!? ]*$/i or $line =~ /^be zippy\?*$/i) {
|
||||
return '';
|
||||
}
|
||||
|
||||
unless (@yows) { # read data unless it's been read already.
|
||||
print "Reading...\n";
|
||||
while (<DATA>) {
|
||||
chomp;
|
||||
push @yows, $_;
|
||||
}
|
||||
}
|
||||
|
||||
if ($no_zippy) { # ..but just in case :-)
|
||||
return "YOW! I'm an INFOBOT without ZIPPY!" if $main::addressed;
|
||||
}
|
||||
|
||||
my $yow = $yows[rand(@yows)];
|
||||
|
||||
return $yow;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
=pod
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Zippy.pl - Yow! Am I having fun yet?
|
||||
|
||||
=head1 PREREQUISITES
|
||||
|
||||
None.
|
||||
|
||||
=head1 PARAMETERS
|
||||
|
||||
zippy
|
||||
|
||||
=head1 PUBLIC INTERFACE
|
||||
|
||||
[yow|be zippy]
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
It's OBVIOUS ... The FURS never reached ISTANBUL ... You were an EXTRA
|
||||
in the REMAKE of "TOPKAPI" ... Go home to your WIFE ... She's making
|
||||
FRENCH TOAST!
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
Rich Lafferty (mendel) <rich@vax2.concordia.ca>
|
||||
|
||||
=cut
|
||||
|
||||
__DATA__
|
||||
A can of ASPARAGUS, 73 pigeons, some LIVE ammo, and a FROZEN DAQUIRI!!
|
||||
A dwarf is passing out somewhere in Detroit!
|
||||
A shapely CATHOLIC SCHOOLGIRL is FIDGETING inside my costume..
|
||||
A wide-eyed, innocent UNICORN, poised delicately in a MEADOW filled with LILACS, LOLLIPOPS & small CHILDREN at the HUSH of twilight??
|
||||
Actually, what I'd like is a little toy spaceship!!
|
||||
All I can think of is a platter of organic PRUNE CRISPS being trampled by an army of swarthy, Italian LOUNGE SINGERS ...
|
||||
All of a sudden, I want to THROW OVER my promising ACTING CAREER, grow a LONG BLACK BEARD and wear a BASEBALL HAT!! ... Although I don't know WHY!!
|
||||
All of life is a blur of Republicans and meat!
|
||||
All right, you degenerates! I want this place evacuated in 20 seconds!
|
||||
All this time I've been VIEWING a RUSSIAN MIDGET SODOMIZE a HOUSECAT!
|
||||
Alright, you!! Imitate a WOUNDED SEAL pleading for a PARKING SPACE!!
|
||||
Am I accompanied by a PARENT or GUARDIAN?
|
||||
Am I elected yet?
|
||||
Am I in GRADUATE SCHOOL yet?
|
||||
Am I SHOPLIFTING?
|
||||
America!! I saw it all!! Vomiting! Waving! JERRY FALWELLING into your void tube of UHF oblivion!! SAFEWAY of the mind ...
|
||||
An air of FRENCH FRIES permeates my nostrils!!
|
||||
An INK-LING? Sure -- TAKE one!! Did you BUY any COMMUNIST UNIFORMS??
|
||||
An Italian is COMBING his hair in suburban DES MOINES!
|
||||
And furthermore, my bowling average is unimpeachable!!!
|
||||
ANN JILLIAN'S HAIR makes LONI ANDERSON'S HAIR look like RICARDO MONTALBAN'S HAIR!
|
||||
Are the STEWED PRUNES still in the HAIR DRYER?
|
||||
Are we live or on tape?
|
||||
Are we on STRIKE yet?
|
||||
Are we THERE yet?
|
||||
Are we THERE yet? My MIND is a SUBMARINE!!
|
||||
Are you mentally here at Pizza Hut??
|
||||
Are you selling NYLON OIL WELLS?? If so, we can use TWO DOZEN!!
|
||||
Are you still an ALCOHOLIC?
|
||||
As President I have to go vacuum my coin collection!
|
||||
Awright, which one of you hid my PENIS ENVY?
|
||||
BARBARA STANWYCK makes me nervous!!
|
||||
Barbie says, Take quaaludes in gin and go to a disco right away!
|
||||
But Ken says, WOO-WOO!! No credit at "Mr. Liquor"!!
|
||||
BARRY ... That was the most HEART-WARMING rendition of "I DID IT MY WAY" I've ever heard!!
|
||||
Being a BALD HERO is almost as FESTIVE as a TATTOOED KNOCKWURST.
|
||||
BELA LUGOSI is my co-pilot ...
|
||||
BI-BI-BI-BI-BI-BI-BI-BI-BI-BI-BI-BI-BI-BI-BI-BI-BI-BI-BI-BI-BI-BI-BI-BI- ... bleakness ... desolation ... plastic forks ...
|
||||
Bo Derek ruined my life!
|
||||
Boy, am I glad it's only 1971...
|
||||
Boys, you have ALL been selected to LEAVE th' PLANET in 15 minutes!!
|
||||
But they went to MARS around 1953!!
|
||||
But was he mature enough last night at the lesbian masquerade?
|
||||
Can I have an IMPULSE ITEM instead?
|
||||
Can you MAIL a BEAN CAKE?
|
||||
Catsup and Mustard all over the place! It's the Human Hamburger!
|
||||
CHUBBY CHECKER just had a CHICKEN SANDWICH in downtown DULUTH!
|
||||
Civilization is fun! Anyway, it keeps me busy!!
|
||||
Clear the laundromat!! This whirl-o-matic just had a nuclear meltdown!!
|
||||
Concentrate on th'cute, li'l CARTOON GUYS! Remember the SERIAL NUMBERS!! Follow the WHIPPLE AVE. EXIT!! Have a FREE PEPSI!! Turn LEFT at th'HOLIDAY INN!! JOIN the CREDIT WORLD!! MAKE me an OFFER!!!
|
||||
CONGRATULATIONS! Now should I make thinly veiled comments about DIGNITY, self-esteem and finding TRUE FUN in your RIGHT VENTRICLE??
|
||||
Content: 80% POLYESTER, 20% DACRONi ... The waitress's UNIFORM sheds TARTAR SAUCE like an 8" by 10" GLOSSY ...
|
||||
Could I have a drug overdose?
|
||||
Did an Italian CRANE OPERATOR just experience uninhibited sensations in a MALIBU HOT TUB?
|
||||
Did I do an INCORRECT THING??
|
||||
Did I say I was a sardine? Or a bus???
|
||||
Did I SELL OUT yet??
|
||||
Did YOU find a DIGITAL WATCH in YOUR box of VELVEETA?
|
||||
Did you move a lot of KOREAN STEAK KNIVES this trip, Dingy?
|
||||
DIDI ... is that a MARTIAN name, or, are we in ISRAEL?
|
||||
Didn't I buy a 1951 Packard from you last March in Cairo?
|
||||
Disco oil bussing will create a throbbing naugahide pipeline running straight to the tropics from the rug producing regions and devalue the dollar!
|
||||
Do I have a lifestyle yet?
|
||||
Do you guys know we just passed thru a BLACK HOLE in space?
|
||||
Do you have exactly what I want in a plaid poindexter bar bat??
|
||||
Do you like "TENDER VITTLES"?
|
||||
Do you think the "Monkees" should get gas on odd or even days?
|
||||
Does someone from PEORIA have a SHORTER ATTENTION span than me? does your DRESSING ROOM have enough ASPARAGUS?
|
||||
DON'T go!! I'm not HOWARD COSELL!! I know POLISH JOKES ... WAIT!!
|
||||
Don't go!! I AM Howard Cosell! ... And I DON'T know Polish jokes!!
|
||||
Don't hit me!! I'm in the Twilight Zone!!!
|
||||
Don't SANFORIZE me!!
|
||||
Don't worry, nobody really LISTENS to lectures in MOSCOW, either! ... FRENCH, HISTORY, ADVANCED CALCULUS, COMPUTER PROGRAMMING, BLACK STUDIES, SOCIOBIOLOGY! ... Are there any QUESTIONS??
|
||||
Edwin Meese made me wear CORDOVANS!!
|
||||
Eisenhower!! Your mimeograph machine upsets my stomach!!
|
||||
Either CONFESS now or we go to "PEOPLE'S COURT"!!
|
||||
Everybody gets free BORSCHT!
|
||||
Everybody is going somewhere!! It's probably a garage sale or a disaster Movie!!
|
||||
Everywhere I look I see NEGATIVITY and ASPHALT ...
|
||||
Excuse me, but didn't I tell you there's NO HOPE for the survival of OFFSET PRINTING? FEELINGS are cascading over me!!!
|
||||
Finally, Zippy drives his 1958 RAMBLER METROPOLITAN into the faculty dining room.
|
||||
First, I'm going to give you all the ANSWERS to today's test ... So just plug in your SONY WALKMANS and relax!!
|
||||
FOOLED you! Absorb EGO SHATTERING impulse rays, polyester poltroon!! for ARTIFICIAL FLAVORING!!
|
||||
Four thousand different MAGNATES, MOGULS & NABOBS are romping in my gothic solarium!!
|
||||
FROZEN ENTREES may be flung by members of opposing SWANSON SECTS ...
|
||||
FUN is never having to say you're SUSHI!!
|
||||
Gee, I feel kind of LIGHT in the head now, knowing I can't make my satellite dish PAYMENTS!
|
||||
Gibble, Gobble, we ACCEPT YOU ...
|
||||
Give them RADAR-GUIDED SKEE-BALL LANES and VELVEETA BURRITOS!!
|
||||
Go on, EMOTE! I was RAISED on thought balloons!!
|
||||
GOOD-NIGHT, everybody ... Now I have to go administer FIRST-AID to my pet LEISURE SUIT!!
|
||||
HAIR TONICS, please!!
|
||||
Half a mind is a terrible thing to waste!
|
||||
Hand me a pair of leather pants and a CASIO keyboard -- I'm living for today!
|
||||
Has everybody got HALVAH spread all over their ANKLES?? ... Now, it's time to "HAVE A NAGEELA"!! ... he dominates the DECADENT SUBWAY SCENE.
|
||||
He is the MELBA-BEING ... the ANGEL CAKE ... XEROX him ... XEROX him -- He probably just wants to take over my CELLS and then EXPLODE inside me like a BARREL of runny CHOPPED LIVER! Or maybe he'd like to PSYCHOLIGICALLY TERRORISE ME until I have no objection to a RIGHT-WING MILITARY TAKEOVER of my apartment!! I guess I should call AL PACINO!
|
||||
HELLO KITTY gang terrorizes town, family STICKERED to death!
|
||||
HELLO, everybody, I'm a HUMAN!!
|
||||
Hello, GORRY-O!! I'm a GENIUS from HARVARD!!
|
||||
Hello. I know the divorce rate among unmarried Catholic Alaskan females!!
|
||||
Hello. Just walk along and try NOT to think about your INTESTINES being almost FORTY YARDS LONG!!
|
||||
Hello... IRON CURTAIN? Send over a SAUSAGE PIZZA! World War III? No thanks!
|
||||
Hello? Enema Bondage? I'm calling because I want to be happy, I guess ...
|
||||
Here I am at the flea market but nobody is buying my urine sample bottles ...
|
||||
Here I am in 53 B.C. and all I want is a dill pickle!!
|
||||
Here I am in the POSTERIOR OLFACTORY LOBULE but I don't see CARL SAGAN anywhere!!
|
||||
Here we are in America ... when do we collect unemployment?
|
||||
Hey, wait a minute!! I want a divorce!! ... you're not Clint Eastwood!!
|
||||
Hey, waiter! I want a NEW SHIRT and a PONY TAIL with lemon sauce!
|
||||
Hiccuping & trembling into the WASTE DUMPS of New Jersey like some drunken CABBAGE PATCH DOLL, coughing in line at FIORUCCI'S!!
|
||||
Hmmm ... a CRIPPLED ACCOUNTANT with a FALAFEL sandwich is HIT by a TROLLEY-CAR ...
|
||||
Hmmm ... A hash-singer and a cross-eyed guy were SLEEPING on a deserted island, when ...
|
||||
Hmmm ... a PINHEAD, during an EARTHQUAKE, encounters an ALL-MIDGET FIDDLE ORCHESTRA ... ha ... ha ...
|
||||
Hmmm ... an arrogant bouquet with a subtle suggestion of POLYVINYL CHLORIDE ...
|
||||
Hold the MAYO & pass the COSMIC AWARENESS ...
|
||||
HOORAY, Ronald!! Now YOU can marry LINDA RONSTADT too!!
|
||||
How do I get HOME?
|
||||
How do you explain Wayne Newton's POWER over millions? It's th' MOUSTACHE ... Have you ever noticed th' way it radiates SINCERITY, HONESTY & WARMTH?
|
||||
It's a MOUSTACHE you want to take HOME and introduce to NANCY SINATRA!
|
||||
How many retured bricklayers from FLORIDA are out purchasing PENCIL
|
||||
SHARPENERS right NOW??
|
||||
How's it going in those MODULAR LOVE UNITS??
|
||||
How's the wife? Is she at home enjoying capitalism?
|
||||
hubub, hubub, HUBUB, hubub, hubub, hubub, HUBUB, hubub, hubub, hubub.
|
||||
HUGH BEAUMONT died in 1982!!
|
||||
HUMAN REPLICAS are inserted into VATS of NUTRITIONAL YEAST ...
|
||||
I always have fun because I'm out of my mind!!!
|
||||
I am a jelly donut. I am a jelly donut.
|
||||
I am a traffic light, and Alan Ginzberg kidnapped my laundry in 1927!
|
||||
I am covered with pure vegetable oil and I am writing a best seller!
|
||||
I am deeply CONCERNED and I want something GOOD for BREAKFAST!
|
||||
I am having FUN... I wonder if it's NET FUN or GROSS FUN?
|
||||
I am NOT a nut....
|
||||
I appoint you ambassador to Fantasy Island!!!
|
||||
I brought my BOWLING BALL -- and some DRUGS!!
|
||||
I can't decide which WRONG TURN to make first!! I wonder if BOB GUCCIONE has these problems!
|
||||
I can't think about that. It doesn't go with HEDGES in the shape of LITTLE LULU -- or ROBOTS making BRICKS ...
|
||||
I demand IMPUNITY!
|
||||
I didn't order any WOO-WOO ... Maybe a YUBBA ... But no WOO-WOO!
|
||||
I don't believe there really IS a GAS SHORTAGE.. I think it's all just a BIG HOAX on the part of the plastic sign salesmen -- to sell more numbers!!
|
||||
... I don't know why but, suddenly, I want to discuss declining I.Q. LEVELS with a blue ribbon SENATE SUB-COMMITTEE!
|
||||
I don't know WHY I said that ... I think it came from the FILLINGS in my read molars ...
|
||||
... I don't like FRANK SINATRA or his CHILDREN. I don't understand the HUMOUR of the THREE STOOGES!!
|
||||
I feel ... JUGULAR ...
|
||||
I feel better about world problems now!
|
||||
I feel like a wet parking meter on Darvon!
|
||||
I feel like I am sharing a ``CORN-DOG'' with NIKITA KHRUSCHEV ...
|
||||
I feel like I'm in a Toilet Bowl with a thumbtack in my forehead!!
|
||||
I feel partially hydrogenated!
|
||||
I fill MY industrial waste containers with old copies of the "WATCHTOWER" and then add HAWAIIAN PUNCH to the top ... They look NICE in the yard ...
|
||||
I guess it was all a DREAM ... or an episode of HAWAII FIVE-O ...
|
||||
I guess you guys got BIG MUSCLES from doing too much STUDYING!
|
||||
I had a lease on an OEDIPUS COMPLEX back in '81 ...
|
||||
I had pancake makeup for brunch!
|
||||
I have a TINY BOWL in my HEAD
|
||||
I have a very good DENTAL PLAN. Thank you.
|
||||
I have a VISION! It's a RANCID double-FISHWICH on an ENRICHED BUN!!
|
||||
I have accepted Provolone into my life!
|
||||
I have many CHARTS and DIAGRAMS..
|
||||
... I have read the INSTRUCTIONS ...
|
||||
-- I have seen the FUN --
|
||||
I have seen these EGG EXTENDERS in my Supermarket ... I have read the INSTRUCTIONS ...
|
||||
I have the power to HALT PRODUCTION on all TEENAGE SEX COMEDIES!!
|
||||
I HAVE to buy a new "DODGE MISER" and two dozen JORDACHE JEANS because my viewscreen is "USER-FRIENDLY"!!
|
||||
I haven't been married in over six years, but we had sexual counseling every day from Oral Roberts!!
|
||||
I hope I bought the right relish ... zzzzzzzzz ...
|
||||
I hope something GOOD came in the mail today so I have a REASON to live!!
|
||||
I hope the ``Eurythmics'' practice birth control ...
|
||||
I hope you millionaires are having fun! I just invested half your life savings in yeast!!
|
||||
I invented skydiving in 1989!
|
||||
I joined scientology at a garage sale!!
|
||||
I just forgot my whole philosophy of life!!!
|
||||
I just got my PRINCE bumper sticker ... But now I can't remember WHO he is ...
|
||||
I just had a NOSE JOB!!
|
||||
I just had my entire INTESTINAL TRACT coated with TEFLON!
|
||||
I just heard the SEVENTIES were over!! And I was just getting in touch with my LEISURE SUIT!!
|
||||
I just remembered something about a TOAD!
|
||||
I KAISER ROLL?! What good is a Kaiser Roll without a little COLE SLAW on the SIDE?
|
||||
I Know A Joke!!
|
||||
I know how to do SPECIAL EFFECTS!!
|
||||
I know th'MAMBO!! I have a TWO-TONE CHEMISTRY SET!!
|
||||
I know things about TROY DONAHUE that can't even be PRINTED!!
|
||||
I left my WALLET in the BATHROOM!!
|
||||
I like the way ONLY their mouths move ... They look like DYING OYSTERS
|
||||
I like your SNOOPY POSTER!!
|
||||
-- I love KATRINKA because she drives a PONTIAC. We're going away now. I fed the cat.
|
||||
I love ROCK 'N ROLL! I memorized the all WORDS to "WIPE-OUT" in 1965!!
|
||||
I need to discuss BUY-BACK PROVISIONS with at least six studio SLEAZEBALLS!!
|
||||
I once decorated my apartment entirely in ten foot salad forks!!
|
||||
I own seven-eighths of all the artists in downtown Burbank!
|
||||
I put aside my copy of "BOWLING WORLD" and think about GUN CONTROL legislation...
|
||||
I represent a sardine!!
|
||||
I request a weekend in Havana with Phil Silvers!
|
||||
... I see TOILET SEATS ...
|
||||
I selected E5 ... but I didn't hear "Sam the Sham and the Pharoahs"!
|
||||
I smell a RANCID CORN DOG!
|
||||
I smell like a wet reducing clinic on Columbus Day!
|
||||
I think I am an overnight sensation right now!!
|
||||
... I think I'd better go back to my DESK and toy with a few common MISAPPREHENSIONS ...
|
||||
I think I'll KILL myself by leaping out of this 14th STORY WINDOW while reading ERICA JONG'S poetry!!
|
||||
I think my career is ruined!
|
||||
I used to be a FUNDAMENTALIST, but then I heard about the HIGH RADIATION LEVELS and bought an ENCYCLOPEDIA!!
|
||||
... I want a COLOR T.V. and a VIBRATING BED!!!
|
||||
I want a VEGETARIAN BURRITO to go ... with EXTRA MSG!!
|
||||
I want a WESSON OIL lease!!
|
||||
I want another RE-WRITE on my CEASAR SALAD!!
|
||||
I want EARS! I want two ROUND BLACK EARS to make me feel warm 'n secure!!
|
||||
... I want FORTY-TWO TRYNEL FLOATATION SYSTEMS installed within SIX AND A HALF HOURS!!!
|
||||
I want the presidency so bad I can already taste the hors d'oeuvres.
|
||||
I want to dress you up as TALLULAH BANKHEAD and cover you with VASELINE and WHEAT THINS ...
|
||||
I want to kill everyone here with a cute colorful Hydrogen Bomb!!
|
||||
... I want to perform cranial activities with Tuesday Weld!!
|
||||
I want to read my new poem about pork brains and outer space ...
|
||||
I want to so HAPPY, the VEINS in my neck STAND OUT!!
|
||||
I want you to MEMORIZE the collected poems of EDNA ST VINCENT MILLAY ... BACKWARDS!!
|
||||
I want you to organize my PASTRY trays ... my TEA-TINS are gleaming in formation like a ROW of DRUM MAJORETTES -- please don't be FURIOUS with me --
|
||||
I was born in a Hostess Cupcake factory before the sexual revolution!
|
||||
I was making donuts and now I'm on a bus!
|
||||
I wish I was a sex-starved manicurist found dead in the Bronx!!
|
||||
I wish I was on a Cincinnati street corner holding a clean dog!
|
||||
I wonder if I could ever get started in the credit world?
|
||||
I wonder if I ought to tell them about my PREVIOUS LIFE as a COMPLETE STRANGER?
|
||||
I wonder if I should put myself in ESCROW!!
|
||||
I wonder if there's anything GOOD on tonight?
|
||||
I would like to urinate in an OVULAR, porcelain pool --
|
||||
I'd like MY data-base JULIENNED and stir-fried!
|
||||
I'd like some JUNK FOOD ... and then I want to be ALONE --
|
||||
I'll eat ANYTHING that's BRIGHT BLUE!!
|
||||
I'll show you MY telex number if you show me YOURS ...
|
||||
I'm a fuschia bowling ball somewhere in Brittany
|
||||
I'm a GENIUS! I want to dispute sentence structure with SUSAN SONTAG!!
|
||||
I'm a nuclear submarine under the polar ice cap and I need a Kleenex!
|
||||
I'm also against BODY-SURFING!!
|
||||
I'm also pre-POURED pre-MEDITATED and pre-RAPHAELITE!!
|
||||
I'm ANN LANDERS!! I can SHOPLIFT!!
|
||||
I'm changing the CHANNEL ... But all I get is commercials for "RONCO MIRACLE BAMBOO STEAMERS"!
|
||||
I'm continually AMAZED at th'breathtaking effects of WIND EROSION!!
|
||||
I'm definitely not in Omaha!
|
||||
I'm DESPONDENT ... I hope there's something DEEP-FRIED under this miniature DOMED STADIUM ...
|
||||
I'm dressing up in an ill-fitting IVY-LEAGUE SUIT!! Too late...
|
||||
I'm EMOTIONAL now because I have MERCHANDISING CLOUT!!
|
||||
I'm encased in the lining of a pure pork sausage!!
|
||||
I'm GLAD I remembered to XEROX all my UNDERSHIRTS!!
|
||||
I'm gliding over a NUCLEAR WASTE DUMP near ATLANTA, Georgia!!
|
||||
I'm having a BIG BANG THEORY!!
|
||||
I'm having a MID-WEEK CRISIS!
|
||||
I'm having a RELIGIOUS EXPERIENCE ... and I don't take any DRUGS
|
||||
I'm having a tax-deductible experience! I need an energy crunch!!
|
||||
I'm having an emotional outburst!!
|
||||
I'm having an EMOTIONAL OUTBURST!! But, uh, WHY is there a WAFFLE in my PAJAMA POCKET??
|
||||
I'm having BEAUTIFUL THOUGHTS about the INSIPID WIVES of smug and wealthy CORPORATE LAWYERS ...
|
||||
I'm having fun HITCHHIKING to CINCINNATI or FAR ROCKAWAY!! ...
|
||||
I'm IMAGINING a sensuous GIRAFFE, CAVORTING in the BACK ROOM of a KOSHER DELI
|
||||
I'm in direct contact with many advanced fun CONCEPTS.
|
||||
I'm into SOFTWARE!
|
||||
I'm meditating on the FORMALDEHYDE and the ASBESTOS leaking into my PERSONAL SPACE!!
|
||||
I'm mentally OVERDRAWN! What's that SIGNPOST up ahead? Where's ROD STERLING when you really need him?
|
||||
I'm not an Iranian!! I voted for Dianne Feinstein!!
|
||||
I'm not available for comment..
|
||||
I'm pretending I'm pulling in a TROUT! Am I doing it correctly??
|
||||
I'm pretending that we're all watching PHIL SILVERS instead of RICARDO MONTALBAN!
|
||||
I'm QUIETLY reading the latest issue of "BOWLING WORLD" while my wife and two children stand QUIETLY BY ...
|
||||
I'm rated PG-34!!
|
||||
I'm receiving a coded message from EUBIE BLAKE!!
|
||||
I'm RELIGIOUS!! I love a man with a HAIRPIECE!! Equip me with MISSILES!!
|
||||
I'm reporting for duty as a modern person. I want to do the Latin Hustle now!
|
||||
I'm shaving!! I'M SHAVING!!
|
||||
I'm sitting on my SPEED QUEEN ... To me, it's ENJOYABLE ... I'm WARM ... I'm VIBRATORY ...
|
||||
I'm thinking about DIGITAL READ-OUT systems and computer-generated IMAGE FORMATIONS ...
|
||||
I'm totally DESPONDENT over the LIBYAN situation and the price of CHICKEN ...
|
||||
I'm using my X-RAY VISION to obtain a rare glimpse of the INNER WORKINGS of this POTATO!!
|
||||
I'm wearing PAMPERS!!
|
||||
I'm wet! I'm wild!
|
||||
I'm young ... I'm HEALTHY ... I can HIKE THRU CAPT GROGAN'S LUMBAR REGIONS!
|
||||
I'm ZIPPY the PINHEAD and I'm totally committed to the festive mode.
|
||||
I've got a COUSIN who works in the GARMENT DISTRICT ...
|
||||
I've got an IDEA!! Why don't I STARE at you so HARD, you forget your SOCIAL SECURITY NUMBER!!
|
||||
I've read SEVEN MILLION books!! ... ich bin in einem dusenjet ins jahr 53 vor chr ... ich lande im antiken Rom ... einige gladiatoren spielen scrabble ... ich rieche PIZZA ...
|
||||
If a person is FAMOUS in this country, they have to go on the ROAD for MONTHS at a time and have their name misspelled on the SIDE of a GREYHOUND SCENICRUISER!!
|
||||
If elected, Zippy pledges to each and every American a 55-year-old houseboy ...
|
||||
If I am elected no one will ever have to do their laundry again!
|
||||
If I am elected, the concrete barriers around the WHITE HOUSE will be replaced by tasteful foam replicas of ANN MARGARET!
|
||||
If I felt any more SOPHISTICATED I would DIE of EMBARRASSMENT!
|
||||
If I had a Q-TIP, I could prevent th' collapse of NEGOTIATIONS!! ... If I had heart failure right now, I couldn't be a more fortunate man!!
|
||||
If I pull this SWITCH I'll be RITA HAYWORTH!! Or a SCIENTOLOGIST!
|
||||
if it GLISTENS, gobble it!!
|
||||
If our behavior is strict, we do not need fun!
|
||||
If Robert Di Niro assassinates Walter Slezak, will Jodie Foster marry Bonzo??
|
||||
In 1962, you could buy a pair of SHARKSKIN SLACKS, with a "Continental Belt," for $10.99!!
|
||||
In Newark the laundromats are open 24 hours a day!
|
||||
INSIDE, I have the same personality disorder as LUCY RICARDO!!
|
||||
Inside, I'm already SOBBING!
|
||||
Is a tattoo real, like a curb or a battleship? Or are we suffering in Safeway?
|
||||
Is he the MAGIC INCA carrying a FROG on his shoulders?? Is the FROG his GUIDELIGHT?? It is curious that a DOG runs already on the ESCALATOR ...
|
||||
Is it 1974? What's for SUPPER? Can I spend my COLLEGE FUND in one wild afternoon??
|
||||
Is it clean in other dimensions?
|
||||
Is it NOUVELLE CUISINE when 3 olives are struggling with a scallop in a plate of SAUCE MORNAY?
|
||||
Is something VIOLENT going to happen to a GARBAGE CAN?
|
||||
Is this an out-take from the "BRADY BUNCH"?
|
||||
Is this going to involve RAW human ecstasy?
|
||||
Is this TERMINAL fun?
|
||||
Is this the line for the latest whimsical YUGOSLAVIAN drama which also makes you want to CRY and reconsider the VIETNAM WAR?
|
||||
Isn't this my STOP?!
|
||||
It don't mean a THING if you ain't got that SWING!!
|
||||
It was a JOKE!! Get it?? I was receiving messages from DAVID LETTERMAN!!
|
||||
YOW!!
|
||||
It's a lot of fun being alive ... I wonder if my bed is made?!?
|
||||
It's NO USE ... I've gone to "CLUB MED"!!
|
||||
It's OBVIOUS ... The FURS never reached ISTANBUL ... You were an EXTRA in the REMAKE of "TOPKAPI" ... Go home to your WIFE ... She's making FRENCH TOAST!
|
||||
It's OKAY -- I'm an INTELLECTUAL, too.
|
||||
It's the RINSE CYCLE!! They've ALL IGNORED the RINSE CYCLE!!
|
||||
JAPAN is a WONDERFUL planet -- I wonder if we'll ever reach their level of COMPARATIVE SHOPPING ...
|
||||
Jesuit priests are DATING CAREER DIPLOMATS!!
|
||||
Jesus is my POSTMASTER GENERAL ...
|
||||
Kids, don't gross me off ... "Adventures with MENTAL HYGIENE" can be carried too FAR!
|
||||
Kids, the seven basic food groups are GUM, PUFF PASTRY, PIZZA, PESTICIDES, ANTIBIOTICS, NUTRA-SWEET and MILK DUDS!!
|
||||
Laundry is the fifth dimension!! ... um ... um ... th' washing machine is a black hole and the pink socks are bus drivers who just fell in!!
|
||||
LBJ, LBJ, how many JOKES did you tell today??!
|
||||
Leona, I want to CONFESS things to you ... I want to WRAP you in a SCARLET ROBE trimmed with POLYVINYL CHLORIDE ... I want to EMPTY your ASHTRAYS ...
|
||||
Let me do my TRIBUTE to FISHNET STOCKINGS ...
|
||||
Let's all show human CONCERN for REVERAND MOON's legal difficulties!!
|
||||
Let's send the Russians defective lifestyle accessories!
|
||||
Life is a POPULARITY CONTEST! I'm REFRESHINGLY CANDID!!
|
||||
Like I always say -- nothing can beat the BRATWURST here in DUSSELDORF!!
|
||||
Loni Anderson's hair should be LEGALIZED!!
|
||||
Look DEEP into the OPENINGS!! Do you see any ELVES or EDSELS ... or a HIGHBALL?? ...
|
||||
Look into my eyes and try to forget that you have a Macy's charge card!
|
||||
Look! A ladder! Maybe it leads to heaven, or a sandwich!
|
||||
LOOK!! Sullen American teens wearing MADRAS shorts and "Flock of Seagulls" HAIRCUTS!
|
||||
Make me look like LINDA RONSTADT again!!
|
||||
Mary Tyler Moore's SEVENTH HUSBAND is wearing my DACRON TANK TOP in a cheap hotel in HONOLULU!
|
||||
Maybe we could paint GOLDIE HAWN a rich PRUSSIAN BLUE --
|
||||
MERYL STREEP is my obstetrician!
|
||||
MMM-MM!! So THIS is BIO-NEBULATION!
|
||||
Mmmmmm-MMMMMM!! A plate of STEAMING PIECES of a PIG mixed with the shreds of SEVERAL CHICKENS!! ... Oh BOY!! I'm about to swallow a TORN-OFF section of a COW'S LEFT LEG soaked in COTTONSEED OIL and SUGAR!! ... Let's see ... Next, I'll have the GROUND-UP flesh of CUTE, BABY LAMBS fried in the MELTED, FATTY TISSUES from a warm-blooded animal someone once PETTED!! ... YUM!! That was GOOD!! For DESSERT, I'll have a TOFU BURGER with BEAN SPROUTS on a stone-ground, WHOLE WHEAT BUN!!
|
||||
Mr and Mrs PED, can I borrow 26.7% of the RAYON TEXTILE production of the INDONESIAN archipelago?
|
||||
My Aunt MAUREEN was a military advisor to IKE & TINA TURNER!!
|
||||
My BIOLOGICAL ALARM CLOCK just went off ... It has noiseless DOZE FUNCTION and full kitchen!!
|
||||
My CODE of ETHICS is vacationing at famed SCHROON LAKE in upstate New York!!
|
||||
My EARS are GONE!!
|
||||
My face is new, my license is expired, and I'm under a doctor's care!!!!
|
||||
My haircut is totally traditional!
|
||||
MY income is ALL disposable!
|
||||
My LESLIE GORE record is BROKEN ...
|
||||
My life is a patio of fun!
|
||||
My mind is a potato field ...
|
||||
My mind is making ashtrays in Dayton ...
|
||||
My nose feels like a bad Ronald Reagan movie ...
|
||||
My NOSE is NUMB!
|
||||
... My pants just went on a wild rampage through a Long Island Bowling Alley!!
|
||||
My pants just went to high school in the Carlsbad Caverns!!!
|
||||
My polyvinyl cowboy wallet was made in Hong Kong by Montgomery Clift!
|
||||
My uncle Murray conquered Egypt in 53 B.C. And I can prove it too!!
|
||||
My vaseline is RUNNING...
|
||||
NANCY!! Why is everything RED?!
|
||||
NATHAN ... your PARENTS were in a CARCRASH!! They're VOIDED -- They COLLAPSED They had no CHAINSAWS ... They had no MONEY MACHINES ... They did PILLS in SKIMPY GRASS SKIRTS ... Nathan, I EMULATED them ... but they were OFF-KEY ...
|
||||
NEWARK has been REZONED!! DES MOINES has been REZONED!!
|
||||
Nipples, dimples, knuckles, NICKLES, wrinkles, pimples!!
|
||||
Not SENSUOUS ... only "FROLICSOME" ... and in need of DENTAL WORK ... in PAIN!!!
|
||||
Now I am depressed ...
|
||||
Now I think I just reached the state of HYPERTENSION that comes JUST BEFORE you see the TOTAL at the SAFEWAY CHECKOUT COUNTER!
|
||||
Now I understand the meaning of "THE MOD SQUAD"!
|
||||
Now I'm being INVOLUNTARILY shuffled closer to the CLAM DIP with the BROKEN PLASTIC FORKS in it!!
|
||||
Now I'm concentrating on a specific tank battle toward the end of World War II!
|
||||
Now I'm having INSIPID THOUGHTS about the beatiful, round wives of HOLLYWOOD MOVIE MOGULS encased in PLEXIGLASS CARS and being approached by SMALL BOYS selling FRUIT ...
|
||||
Now KEN and BARBIE are PERMANENTLY ADDICTED to MIND-ALTERING DRUGS ...
|
||||
Now my EMOTIONAL RESOURCES are heavily committed to 23% of the SMELTING and REFINING industry of the state of NEVADA!!
|
||||
Now that I have my "APPLE", I comprehend COST ACCOUNTING!!
|
||||
Now, let's SEND OUT for QUICHE!!
|
||||
Of course, you UNDERSTAND about the PLAIDS in the SPIN CYCLE --
|
||||
Oh my GOD -- the SUN just fell into YANKEE STADIUM!!
|
||||
Oh, I get it!! "The BEACH goes on", huh, SONNY??
|
||||
Okay ... I'm going home to write the "I HATE RUBIK's CUBE HANDBOOK FOR DEAD CAT LOVERS" ...
|
||||
OKAY!! Turn on the sound ONLY for TRYNEL CARPETING, FULLY-EQUIPPED R.V.'S and FLOATATION SYSTEMS!!
|
||||
OMNIVERSAL AWARENESS?? Oh, YEH!! First you need four GALLONS of JELL-O and a BIG WRENCH!! ... I think you drop th'WRENCH in the JELL-O as if it was a FLAVOR, or an INGREDIENT ... ... or ... I ... um ... WHERE'S the WASHING MACHINES?
|
||||
On SECOND thought, maybe I'll heat up some BAKED BEANS and watch REGIS PHILBIN ... It's GREAT to be ALIVE!!
|
||||
On the other hand, life can be an endless parade of TRANSSEXUAL
|
||||
QUILTING BEES aboard a cruise ship to DISNEYWORLD if only we let it!!
|
||||
On the road, ZIPPY is a pinhead without a purpose, but never without a POINT.
|
||||
Once upon a time, four AMPHIBIOUS HOG CALLERS attacked a family of DEFENSELESS, SENSITIVE COIN COLLECTORS and brought DOWN their PROPERTY VALUES!!
|
||||
Once, there was NO fun ... This was before MENU planning, FASHION statements or NAUTILUS equipment ... Then, in 1985 ... FUN was completely encoded in this tiny MICROCHIP ... It contain 14,768 vaguely amusing SIT-COM pilots!! We had to wait FOUR BILLION years but we finally got JERRY LEWIS, MTV and a large selection of creme-filled snack cakes!
|
||||
One FISHWICH coming up!!
|
||||
ONE LIFE TO LIVE for ALL MY CHILDREN in ANOTHER WORLD all THE DAYS OF OUR LIVES.
|
||||
ONE: I will donate my entire "BABY HUEY" comic book collection to the downtown PLASMA CENTER ... TWO: I won't START a BAND called "KHADAFY & THE HIT SQUAD" ... THREE: I won't ever TUMBLE DRY my FOX TERRIER again!!
|
||||
... or were you driving the PONTIAC that HONKED at me in MIAMI last Tuesday?
|
||||
Our father who art in heaven ... I sincerely pray that SOMEBODY at this table will PAY for my SHREDDED WHAT and ENGLISH MUFFIN ... and also leave a GENEROUS TIP ....
|
||||
over in west Philadelphia a puppy is vomiting ...
|
||||
OVER the underpass! UNDER the overpass! Around the FUTURE and BEYOND REPAIR!!
|
||||
PARDON me, am I speaking ENGLISH?
|
||||
Pardon me, but do you know what it means to be TRULY ONE with your BOOTH!
|
||||
PEGGY FLEMMING is stealing BASKET BALLS to feed the babies in VERMONT.
|
||||
People humiliating a salami!
|
||||
PIZZA!!
|
||||
Place me on a BUFFER counter while you BELITTLE several BELLHOPS in the Trianon Room!! Let me one of your SUBSIDIARIES!
|
||||
Please come home with me ... I have Tylenol!!
|
||||
Psychoanalysis?? I thought this was a nude rap session!!!
|
||||
PUNK ROCK!! DISCO DUCK!! BIRTH CONTROL!!
|
||||
Quick, sing me the BUDAPEST NATIONAL ANTHEM!!
|
||||
RELATIVES!!
|
||||
Remember, in 2039, MOUSSE & PASTA will be available ONLY by prescription!!
|
||||
RHAPSODY in Glue!
|
||||
SANTA CLAUS comes down a FIRE ESCAPE wearing bright blue LEG WARMERS ... He scrubs the POPE with a mild soap or detergent for 15 minutes, starring JANE FONDA!!
|
||||
Send your questions to ``ASK ZIPPY'', Box 40474, San Francisco, CA 94140, USA
|
||||
SHHHH!! I hear SIX TATTOOED TRUCK-DRIVERS tossing ENGINE BLOCKS into empty OIL DRUMS ...
|
||||
Should I do my BOBBIE VINTON medley?
|
||||
Should I get locked in the PRINCICAL'S OFFICE today -- or have a VASECTOMY??
|
||||
Should I start with the time I SWITCHED personalities with a BEATNIK hair stylist or my failure to refer five TEENAGERS to a good OCULIST? Sign my PETITION.
|
||||
So this is what it feels like to be potato salad
|
||||
So, if we convert SUPPLY-SIDE SOYABEAN FUTURES into HIGH-YIELD T-BILL INDICATORS, the PRE-INFLATIONARY risks will DWINDLE to a rate of 2 SHOPPING SPREES per EGGPLANT!!
|
||||
Someone in DAYTON, Ohio is selling USED CARPETS to a SERBO-CROATIAN
|
||||
Sometime in 1993 NANCY SINATRA will lead a BLOODLESS COUP on GUAM!!
|
||||
Somewhere in DOWNTOWN BURBANK a prostitute is OVERCOOKING a LAMB CHOP!!
|
||||
Somewhere in suburban Honolulu, an unemployed bellhop is whipping up a batch of illegal psilocybin chop suey!!
|
||||
Somewhere in Tenafly, New Jersey, a chiropractor is viewing "Leave it
|
||||
to Beaver"!
|
||||
Spreading peanut butter reminds me of opera!! I wonder why?
|
||||
TAILFINS!! ... click ... Talking Pinhead Blues: Oh, I LOST my ``HELLO KITTY'' DOLL and I get BAD reception on channel TWENTY-SIX!!
|
||||
Th'HOSTESS FACTORY is closin' down and I just heard ZASU PITTS has been DEAD for YEARS.. (sniff)
|
||||
My PLATFORM SHOE collection was CHEWED up by th' dog, ALEXANDER HAIG won't let me take a SHOWER 'til Easter ... (snurf)
|
||||
So I went to the kitchen, but WALNUT PANELING whup me upside mah HAID!! (on no, no, no.. Heh, heh)
|
||||
TAPPING? You POLITICIANS! Don't you realize that the END of the "Wash Cycle" is a TREASURED MOMENT for most people?!
|
||||
Tex SEX! The HOME of WHEELS! The dripping of COFFEE!! Take me to Minnesota but don't EMBARRASS me!!
|
||||
Th' MIND is the Pizza Palace of th' SOUL
|
||||
Thank god!! ... It's HENNY YOUNGMAN!!
|
||||
The appreciation of the average visual graphisticator alone is worth
|
||||
the whole suaveness and decadence which abounds!!
|
||||
The entire CHINESE WOMEN'S VOLLEYBALL TEAM all share ONE personality -- and have since BIRTH!!
|
||||
The fact that 47 PEOPLE are yelling and sweat is cascading down my SPINAL COLUMN is fairly enjoyable!!
|
||||
The FALAFEL SANDWICH lands on my HEAD and I become a VEGETARIAN ...
|
||||
... the HIGHWAY is made out of LIME JELLO and my HONDA is a barbequeued OYSTER! Yum!
|
||||
The Korean War must have been fun. ... the MYSTERIANS are in here with my CORDUROY SOAP DISH!!
|
||||
The Osmonds! You are all Osmonds!! Throwing up on a freeway at dawn!!!
|
||||
The PILLSBURY DOUGHBOY is CRYING for an END to BURT REYNOLDS movies!!
|
||||
The PINK SOCKS were ORIGINALLY from 1952!! But they went to MARS around 1953!!
|
||||
The SAME WAVE keeps coming in and COLLAPSING like a rayon MUU-MUU ...
|
||||
There is no TRUTH. There is no REALITY. There is no CONSISTENCY.
|
||||
There are no ABSOLUTE STATEMENTS. I'm very probably wrong.
|
||||
There's a little picture of ED MCMAHON doing BAD THINGS to JOAN RIVERS in a $200,000 MALIBU BEACH HOUSE!!
|
||||
There's enough money here to buy 5000 cans of Noodle-Roni! "These are DARK TIMES for all mankind's HIGHEST VALUES!" "These are DARK TIMES for FREEDOM and PROSPERITY!" "These are GREAT TIMES to put your money on BAD GUY to kick the CRAP out of MEGATON MAN!"
|
||||
These PRESERVES should be FORCE-FED to PENTAGON OFFICIALS!!
|
||||
They collapsed ... like nuns in the street ... they had no teen appeal!
|
||||
This ASEXUAL PIG really BOILS my BLOOD ... He's so ... so ... URGENT!!
|
||||
"This is a job for BOB VIOLENCE and SCUM, the INCREDIBLY STUPID MUTANT DOG." -- Bob Violence
|
||||
This is a NO-FRILLS flight -- hold th' CANADIAN BACON!!
|
||||
This MUST be a good party -- My RIB CAGE is being painfully pressed up against someone's MARTINI!! ... this must be what it's like to be a COLLEGE GRADUATE!!
|
||||
This PIZZA symbolizes my COMPLETE EMOTIONAL RECOVERY!!
|
||||
This PORCUPINE knows his ZIPCODE ... And he has "VISA"!!
|
||||
This TOPS OFF my partygoing experience! Someone I DON'T LIKE is talking to me about a HEART-WARMING European film ...
|
||||
Those aren't WINOS -- that's my JUGGLER, my AERIALIST, my SWORD
|
||||
SWALLOWER, and my LATEX NOVELTY SUPPLIER!!
|
||||
Thousands of days of civilians ... have produced a ... feeling for the aesthetic modules --
|
||||
Today, THREE WINOS from DETROIT sold me a framed photo of TAB HUNTER before his MAKEOVER!
|
||||
Toes, knees, NIPPLES. Toes, knees, nipples, KNUCKLES ... Nipples, dimples, knuckles, NICKLES, wrinkles, pimples!! TONY RANDALL! Is YOUR life a PATIO of FUN??
|
||||
Uh-oh -- WHY am I suddenly thinking of a VENERABLE religious leader frolicking on a FORT LAUDERDALE weekend?
|
||||
Uh-oh!! I forgot to submit to COMPULSORY URINALYSIS!
|
||||
UH-OH!! I put on "GREAT HEAD-ON TRAIN COLLISIONS of the 50's" by mistake!!!
|
||||
UH-OH!! I think KEN is OVER-DUE on his R.V. PAYMENTS and HE'S having a NERVOUS BREAKDOWN too!! Ha ha.
|
||||
Uh-oh!! I'm having TOO MUCH FUN!!
|
||||
UH-OH!! We're out of AUTOMOBILE PARTS and RUBBER GOODS!
|
||||
Used staples are good with SOY SAUCE!
|
||||
VICARIOUSLY experience some reason to LIVE!!
|
||||
Vote for ME -- I'm well-tapered, half-cocked, ill-conceived and TAX-DEFERRED!
|
||||
Wait ... is this a FUN THING or the END of LIFE in Petticoat Junction??
|
||||
Was my SOY LOAF left out in th'RAIN? It tastes REAL GOOD!!
|
||||
We are now enjoying total mutual interaction in an imaginary hot tub ...
|
||||
We have DIFFERENT amounts of HAIR --
|
||||
We just joined the civil hair patrol!
|
||||
We place two copies of PEOPLE magazine in a DARK, HUMID mobile home. 45 minutes later CYNDI LAUPER emerges wearing a BIRD CAGE on her head!
|
||||
Well, here I am in AMERICA.. I LIKE it. I HATE it. I LIKE it. I
|
||||
HATE it. I LIKE it. I HATE it. I LIKE it. I HATE it. I LIKE ... EMOTIONS are SWEEPING over me!!
|
||||
Well, I'm a classic ANAL RETENTIVE!! And I'm looking for a way to VICARIOUSLY experience some reason to LIVE!!
|
||||
Well, I'm INVISIBLE AGAIN ... I might as well pay a visit to the LADIES ROOM ...
|
||||
Well, O.K. I'll compromise with my principles because of EXISTENTIAL DESPAIR!
|
||||
Were these parsnips CORRECTLY MARINATED in TACO SAUCE?
|
||||
What a COINCIDENCE! I'm an authorized "SNOOTS OF THE STARS" dealer!!
|
||||
What GOOD is a CARDBOARD suitcase ANYWAY?
|
||||
What I need is a MATURE RELATIONSHIP with a FLOPPY DISK ...
|
||||
What I want to find out is -- do parrots know much about Astro-Turf?
|
||||
What PROGRAM are they watching?
|
||||
What UNIVERSE is this, please??
|
||||
What's the MATTER Sid? ... Is your BEVERAGE unsatisfactory?
|
||||
When I met th'POPE back in '58, I scrubbed him with a MILD SOAP or DETERGENT for 15 minutes. He seemed to enjoy it ...
|
||||
When this load is DONE I think I'll wash it AGAIN ...
|
||||
When you get your PH.D. will you get able to work at BURGER KING?
|
||||
When you said "HEAVILY FORESTED" it reminded me of an overdue CLEANING
|
||||
BILL ... Don't you SEE? O'Grogan SWALLOWED a VALUABLE COIN COLLECTION and HAD to murder the ONLY MAN who KNEW!!
|
||||
Where do your SOCKS go when you lose them in th' WASHER?
|
||||
Where does it go when you flush?
|
||||
Where's SANDY DUNCAN?
|
||||
Where's th' DAFFY DUCK EXHIBIT??
|
||||
Where's the Coke machine? Tell me a joke!!
|
||||
While my BRAINPAN is being refused service in BURGER KING, Jesuit priests are DATING CAREER DIPLOMATS!!
|
||||
While you're chewing, think of STEVEN SPIELBERG'S bank account ... his will have the same effect as two "STARCH BLOCKERS"!
|
||||
WHO sees a BEACH BUNNY sobbing on a SHAG RUG?!
|
||||
WHOA!! Ken and Barbie are having TOO MUCH FUN!! It must be the NEGATIVE IONS!!
|
||||
Why are these athletic shoe salesmen following me??
|
||||
Why don't you ever enter any CONTESTS, Marvin?? Don't you know your own ZIPCODE?
|
||||
Why is everything made of Lycra Spandex?
|
||||
Why is it that when you DIE, you can't take your HOME ENTERTAINMENT CENTER with you??
|
||||
Will it improve my CASH FLOW?
|
||||
Will the third world war keep "Bosom Buddies" off the air?
|
||||
Will this never-ending series of PLEASURABLE EVENTS never cease?
|
||||
With YOU, I can be MYSELF ... We don't NEED Dan Rather ...
|
||||
World War III? No thanks!
|
||||
World War Three can be averted by adherence to a strictly enforced dress code!
|
||||
Wow! Look!! A stray meatball!! Let's interview it!
|
||||
Xerox your lunch and file it under "sex offenders"!
|
||||
Yes, but will I see the EASTER BUNNY in skintight leather at an IRON MAIDEN concert?
|
||||
You can't hurt me!! I have an ASSUMABLE MORTGAGE!!
|
||||
You mean now I can SHOOT YOU in the back and further BLUR th' distinction between FANTASY and REALITY?
|
||||
You mean you don't want to watch WRESTLING from ATLANTA?
|
||||
YOU PICKED KARL MALDEN'S NOSE!!
|
||||
You should all JUMP UP AND DOWN for TWO HOURS while I decide on a NEW CAREER!!
|
||||
You were s'posed to laugh!
|
||||
YOU!! Give me the CUTEST, PINKEST, most charming little VICTORIAN DOLLHOUSE you can find!! An make it SNAPPY!!
|
||||
Your CHEEKS sit like twin NECTARINES above a MOUTH that knows no BOUNDS -- Youth of today! Join me in a mass rally for traditional mental attitudes!
|
||||
Yow!
|
||||
Yow! Am I having fun yet?
|
||||
Yow! Am I in Milwaukee?
|
||||
Yow! And then we could sit on the hoods of cars at stop lights!
|
||||
Yow! Are we laid back yet?
|
||||
Yow! Are we wet yet?
|
||||
Yow! Are you the self-frying president?
|
||||
Yow! Did something bad happen or am I in a drive-in movie??
|
||||
Yow! I just went below the poverty line!
|
||||
Yow! I threw up on my window!
|
||||
Yow! I want my nose in lights!
|
||||
Yow! I want to mail a bronzed artichoke to Nicaragua!
|
||||
Yow! I'm having a quadrophonic sensation of two winos alone in a steel mill!
|
||||
Yow! I'm imagining a surfer van filled with soy sauce!
|
||||
Yow! Is my fallout shelter termite proof?
|
||||
Yow! Is this sexual intercourse yet?? Is it, huh, is it??
|
||||
Yow! It's a hole all the way to downtown Burbank!
|
||||
Yow! It's some people inside the wall! This is better than mopping!
|
||||
Yow! Maybe I should have asked for my Neutron Bomb in PAISLEY --
|
||||
Yow! Now I get to think about all the BAD THINGS I did to a BOWLING BALL when I was in JUNIOR HIGH SCHOOL!
|
||||
Yow! Now we can become alcoholics!
|
||||
Yow! Those people look exactly like Donnie and Marie Osmond!!
|
||||
Yow! We're going to a new disco!
|
||||
YOW!! Everybody out of the GENETIC POOL!
|
||||
YOW!! I'm in a very clever and adorable INSANE ASYLUM!!
|
||||
YOW!! Now I understand advanced MICROBIOLOGY and th' new TAX REFORM laws!!
|
||||
YOW!! The land of the rising SONY!!
|
||||
YOW!! Up ahead! It's a DONUT HUT!!
|
||||
YOW!! What should the entire human race DO?? Consume a fifth of
|
||||
CHIVAS REGAL, ski NUDE down MT. EVEREST, and have a wild SEX WEEKEND!
|
||||
YOW!!! I am having fun!!!
|
||||
Zippy's brain cells are straining to bridge synapses ...
|
@ -0,0 +1,146 @@
|
||||
#!/usr/bin/perl
|
||||
# This program is copyright Jonathan Feinberg 1999.
|
||||
|
||||
# This program is distributed under the same terms as infobot.
|
||||
|
||||
# Jonathan Feinberg
|
||||
# jdf@pobox.com
|
||||
# http://pobox.com/~jdf/
|
||||
|
||||
# Version 1.0
|
||||
# First public release.
|
||||
#
|
||||
# hacked by Tim@Rikers.org to handle new URL and layout
|
||||
|
||||
package babel;
|
||||
use strict;
|
||||
|
||||
my $no_babel;
|
||||
|
||||
BEGIN {
|
||||
eval "use URI::Escape"; # utility functions for encoding the
|
||||
if ($@) { $no_babel++}; # babelfish request
|
||||
eval "use LWP::UserAgent";
|
||||
if ($@) { $no_babel++};
|
||||
}
|
||||
|
||||
BEGIN {
|
||||
# Translate some feasible abbreviations into the ones babelfish
|
||||
# expects.
|
||||
use vars qw!%lang_code $lang_regex!;
|
||||
%lang_code = (
|
||||
fr => 'fr',
|
||||
sp => 'es',
|
||||
po => 'pt',
|
||||
pt => 'pt',
|
||||
it => 'it',
|
||||
ge => 'de',
|
||||
de => 'de',
|
||||
gr => 'de',
|
||||
en => 'en'
|
||||
);
|
||||
|
||||
# Here's how we recognize the language you're asking for. It looks
|
||||
# like RTSL saves you a few keystrokes in #perl, huh?
|
||||
$lang_regex = join '|', keys %lang_code;
|
||||
}
|
||||
|
||||
|
||||
sub forking_babelfish {
|
||||
return '' if $no_babel;
|
||||
my ($direction, $lang, $phrase, $callback) = @_;
|
||||
$SIG{CHLD} = 'IGNORE';
|
||||
my $pid = eval { fork() }; # catch non-forking OSes and other errors
|
||||
return if $pid; # parent does nothing
|
||||
$callback->(babelfish($direction, $lang, $phrase));
|
||||
exit 0 if defined $pid; # child exits, non-forking OS returns
|
||||
}
|
||||
|
||||
sub babelfish {
|
||||
return '' if $no_babel;
|
||||
my ($direction, $lang, $phrase) = @_;
|
||||
|
||||
$lang = $lang_code{$lang};
|
||||
|
||||
my $ua = new LWP::UserAgent;
|
||||
$ua->timeout(5);
|
||||
|
||||
my $req =
|
||||
#HTTP::Request->new('POST', 'http://babelfish.altavista.digital.com/cgi-bin/translate');
|
||||
#HTTP::Request->new('POST', 'http://babelfish.altavista.com/translate.dyn');
|
||||
HTTP::Request->new('POST', 'http://babelfish.altavista.com/raging/translate.dyn');
|
||||
$req->content_type('application/x-www-form-urlencoded');
|
||||
|
||||
my $tolang = "en_$lang";
|
||||
my $toenglish = "${lang}_en";
|
||||
|
||||
if ($direction eq 'to') {
|
||||
return translate($phrase, $tolang, $req, $ua);
|
||||
}
|
||||
elsif ($direction eq 'from') {
|
||||
return translate($phrase, $toenglish, $req, $ua);
|
||||
}
|
||||
|
||||
my $last_english = $phrase;
|
||||
my $last_lang;
|
||||
my %results = ();
|
||||
my $i = 0;
|
||||
while ($i++ < 7) {
|
||||
last if $results{$phrase}++;
|
||||
$last_lang = $phrase = translate($phrase, $tolang, $req, $ua);
|
||||
last if $results{$phrase}++;
|
||||
$last_english = $phrase = translate($phrase, $toenglish, $req, $ua);
|
||||
}
|
||||
return $last_english;
|
||||
}
|
||||
|
||||
|
||||
sub translate {
|
||||
return '' if $no_babel;
|
||||
my ($phrase, $languagepair, $req, $ua) = @_;
|
||||
|
||||
my $urltext = uri_escape($phrase);
|
||||
$req->content("urltext=$urltext&lp=$languagepair");
|
||||
|
||||
my $res = $ua->request($req);
|
||||
|
||||
if ($res->is_success) {
|
||||
my $html = $res->content;
|
||||
# This method subject to change with the whims of Altavista's design
|
||||
# staff.
|
||||
#print "$html\n===============\n";
|
||||
# look for the first :< which should be the "To English:<", etc.
|
||||
# strip any trailing tags, grab text that follows up to the next tag.
|
||||
my (undef,$translated) = ($html =~ m{:(<[^>]*>\s*)+([^<]*)}sx);
|
||||
#print "$translated\n===============\n";
|
||||
# my ($translated) = ($html =~ m{:(<[^>]*>\s*)+([^<]*)}sx);
|
||||
#print "$translated\n===============\n";
|
||||
# ($html =~ m{<textarea[^>]*>
|
||||
# \s*
|
||||
# ([^<]*)
|
||||
# }sx);
|
||||
# ($html =~ m{<br>
|
||||
# \s+
|
||||
# <font\ face="arial,\ helvetica">
|
||||
# \s*
|
||||
# (?:\*\*\s+time\ out\s+\*\*)?
|
||||
# \s*
|
||||
# ([^<]*)
|
||||
# }sx);
|
||||
$translated =~ s/\n/ /g;
|
||||
$translated =~ s/\s*$//;
|
||||
return $translated;
|
||||
} else {
|
||||
return ":("; # failure
|
||||
}
|
||||
}
|
||||
|
||||
if (0) {
|
||||
if (-t STDIN) {
|
||||
my $result = babel::babelfish('to','sp','hello world');
|
||||
$result =~ s/; /\n/g;
|
||||
print "Babelfish says: $result\n";
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
@ -0,0 +1,395 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
# exchange.pl - currency exchange "module"
|
||||
#
|
||||
# Last update: 990818 08:30:10, bobby@bofh.dk
|
||||
#
|
||||
|
||||
BEGIN {
|
||||
eval qq{
|
||||
use LWP::UserAgent;
|
||||
use HTTP::Request::Common qw(POST GET);
|
||||
};
|
||||
|
||||
$no_exchange++ if($@);
|
||||
}
|
||||
|
||||
sub exchange {
|
||||
my($From, $To, $Amount) = @_;
|
||||
|
||||
return "exchange.pl: not configured. needs LWP::UserAgent and HTTP::Request::Common"
|
||||
if( $no_exchange );
|
||||
|
||||
my $retval = '';
|
||||
|
||||
my $ua = new LWP::UserAgent;
|
||||
$ua->agent("Mozilla/4.5 " . $ua->agent); # Let's pretend
|
||||
if (my $proxy = main::getparam('httpproxy')) { $ua->proxy('http', $proxy) };
|
||||
$ua->timeout(10);
|
||||
|
||||
my $Referer = 'http://www.xe.net/ucc/full.shtml';
|
||||
my $Converter='http://www.xe.net/ucc/convert.cgi';
|
||||
|
||||
# Get a list of currency abbreviations...
|
||||
my $grab = GET $Referer;
|
||||
my $reply = $ua->request($grab);
|
||||
if (!$reply->is_success) {
|
||||
return "EXCHANGE: ".$reply->status_line;
|
||||
}
|
||||
my $html = $reply->as_string;
|
||||
my %Currencies = (grep /\S+/,
|
||||
($html =~ /option value="([^"]+)">.*?,\s*([^<]+)</gi)
|
||||
);
|
||||
|
||||
my %CurrLookup = reverse ($html =~ /option value="([^"]+)">([^<]+)</gi);
|
||||
|
||||
%tld2country = &GetTlds;
|
||||
if( $From =~ /^\.(\w\w)$/ ){ # Probably a tld
|
||||
$From = $tld2country{uc $1};
|
||||
}
|
||||
if( $To =~ /^\.(\w\w)$/ ){ # Probably a tld
|
||||
$To = $tld2country{uc $1};
|
||||
}
|
||||
|
||||
if($#_ == 0){
|
||||
# Country lookup
|
||||
# crysflame++ for the space fix.
|
||||
$retval = '';
|
||||
foreach my $Found (grep /$From/i, keys %CurrLookup){
|
||||
$Found =~ s/,/ uses/g;
|
||||
$retval .= "$Found, ";
|
||||
}
|
||||
$retval =~ s/(?:, )?\|?$//;
|
||||
return substr($retval, 0, 510);
|
||||
}else{
|
||||
|
||||
# Make sure that $Amount is of the form \d+(\.\d\d)?
|
||||
$Amount =~ s/[,.](\d\d)$/\01$1/;
|
||||
$Amount =~ s/[,.]//g;
|
||||
$Amount =~ s/\01/./;
|
||||
|
||||
# Get the exact currency abbreviations
|
||||
my $newFrom = &GetAbb($From, %CurrLookup);
|
||||
my $newTo = &GetAbb($To, %CurrLookup);
|
||||
|
||||
$From = $newFrom if $newFrom;
|
||||
$To = $newTo if $newTo;
|
||||
|
||||
if( exists $Currencies{$From} and exists $Currencies{$To} ){
|
||||
|
||||
my $req = POST $Converter,
|
||||
[ timezone => 'UTC',
|
||||
From => $From,
|
||||
To => $To,
|
||||
Amount => $Amount,
|
||||
];
|
||||
|
||||
# Falsify where we came from
|
||||
$req->referer($Referer);
|
||||
|
||||
my $res = $ua->request($req); # Submit request
|
||||
|
||||
if ($res->is_success) { # Went through ok
|
||||
my $html = $res->as_string;
|
||||
|
||||
my ($When, $Cfrom, $Cto) =
|
||||
grep /\S+/, ($html =~ m/Rates as of (\d{4}\.\d\d.\d\d\s\d\d:\d\d:\d\d\s\S+)|([\d,.]+)\s*$From|([\d,.]+)\s* $To/gi);
|
||||
|
||||
if ($When) {
|
||||
return "$Cfrom ($Currencies{$From}) makes ".
|
||||
"$Cto ($Currencies{$To})"; # ." ($When)\n";
|
||||
} else {
|
||||
return "i got some error trying that";
|
||||
}
|
||||
} else { # Oh dear.
|
||||
return "EXCHANGE: ". $res->status_line;
|
||||
}
|
||||
}else{
|
||||
return "Don't know about \"$From\" as a currency" if( ! exists $Currencies{$From} );
|
||||
return "Don't know about \"$To\" as a currency" if( ! exists $Currencies{$To} );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub GetAbb {
|
||||
my($LookFor,%Hash) = @_;
|
||||
|
||||
my $Found = (grep /$LookFor/i, keys %Hash)[0];
|
||||
$Found =~ m/\((\w\w\w)\)/;
|
||||
return $1;
|
||||
}
|
||||
|
||||
sub GetTlds {
|
||||
my %Hash = (
|
||||
"AF", "AFGHANISTAN",
|
||||
"AL", "ALBANIA",
|
||||
"DZ", "ALGERIA",
|
||||
"AS", "AMERICAN SAMOA",
|
||||
"AD", "ANDORRA",
|
||||
"AO", "ANGOLA",
|
||||
"AI", "ANGUILLA",
|
||||
"AQ", "ANTARCTICA",
|
||||
"AG", "ANTIGUA AND BARBUDA",
|
||||
"AR", "ARGENTINA",
|
||||
"AM", "ARMENIA",
|
||||
"AW", "ARUBA",
|
||||
"AU", "AUSTRALIA",
|
||||
"AT", "AUSTRIA",
|
||||
"AZ", "AZERBAIJAN",
|
||||
"BS", "BAHAMAS",
|
||||
"BH", "BAHRAIN",
|
||||
"BD", "BANGLADESH",
|
||||
"BB", "BARBADOS",
|
||||
"BY", "BELARUS",
|
||||
"BE", "BELGIUM",
|
||||
"BZ", "BELIZE",
|
||||
"BJ", "BENIN",
|
||||
"BM", "BERMUDA",
|
||||
"BT", "BHUTAN",
|
||||
"BO", "BOLIVIA",
|
||||
"BA", "BOSNIA AND HERZEGOWINA",
|
||||
"BW", "BOTSWANA",
|
||||
"BV", "BOUVET ISLAND",
|
||||
"BR", "BRAZIL",
|
||||
"IO", "BRITISH INDIAN OCEAN TERRITORY",
|
||||
"BN", "BRUNEI DARUSSALAM",
|
||||
"BG", "BULGARIA",
|
||||
"BF", "BURKINA FASO",
|
||||
"BI", "BURUNDI",
|
||||
"KH", "CAMBODIA",
|
||||
"CM", "CAMEROON",
|
||||
"CA", "CANADA",
|
||||
"CV", "CAPE VERDE",
|
||||
"KY", "CAYMAN ISLANDS",
|
||||
"CF", "CENTRAL AFRICAN REPUBLIC",
|
||||
"TD", "CHAD",
|
||||
"CL", "CHILE",
|
||||
"CN", "CHINA",
|
||||
"CX", "CHRISTMAS ISLAND",
|
||||
"CC", "COCOS (KEELING) ISLANDS",
|
||||
"CO", "COLOMBIA",
|
||||
"KM", "COMOROS",
|
||||
"CG", "CONGO",
|
||||
"CD", "CONGO, THE DEMOCRATIC REPUBLIC OF THE",
|
||||
"CK", "COOK ISLANDS",
|
||||
"CR", "COSTA RICA",
|
||||
"CI", "COTE D'IVOIRE",
|
||||
"HR", "CROATIA (local name: Hrvatska)",
|
||||
"CU", "CUBA",
|
||||
"CY", "CYPRUS",
|
||||
"CZ", "CZECH REPUBLIC",
|
||||
"DK", "DENMARK",
|
||||
"DJ", "DJIBOUTI",
|
||||
"DM", "DOMINICA",
|
||||
"DO", "DOMINICAN REPUBLIC",
|
||||
"TP", "EAST TIMOR",
|
||||
"EC", "ECUADOR",
|
||||
"EG", "EGYPT",
|
||||
"SV", "EL SALVADOR",
|
||||
"GQ", "EQUATORIAL GUINEA",
|
||||
"ER", "ERITREA",
|
||||
"EE", "ESTONIA",
|
||||
"ET", "ETHIOPIA",
|
||||
"FK", "FALKLAND ISLANDS (MALVINAS)",
|
||||
"FO", "FAROE ISLANDS",
|
||||
"FJ", "FIJI",
|
||||
"FI", "FINLAND",
|
||||
"FR", "FRANCE",
|
||||
"FX", "FRANCE, METROPOLITAN",
|
||||
"GF", "FRENCH GUIANA",
|
||||
"PF", "FRENCH POLYNESIA",
|
||||
"TF", "FRENCH SOUTHERN TERRITORIES",
|
||||
"GA", "GABON",
|
||||
"GM", "GAMBIA",
|
||||
"GE", "GEORGIA",
|
||||
"DE", "GERMANY",
|
||||
"GH", "GHANA",
|
||||
"GI", "GIBRALTAR",
|
||||
"GR", "GREECE",
|
||||
"GL", "GREENLAND",
|
||||
"GD", "GRENADA",
|
||||
"GP", "GUADELOUPE",
|
||||
"GU", "GUAM",
|
||||
"GT", "GUATEMALA",
|
||||
"GN", "GUINEA",
|
||||
"GW", "GUINEA-BISSAU",
|
||||
"GY", "GUYANA",
|
||||
"HT", "HAITI",
|
||||
"HM", "HEARD AND MC DONALD ISLANDS",
|
||||
"VA", "HOLY SEE (VATICAN CITY STATE)",
|
||||
"HN", "HONDURAS",
|
||||
"HK", "HONG KONG",
|
||||
"HU", "HUNGARY",
|
||||
"IS", "ICELAND",
|
||||
"IN", "INDIA",
|
||||
"ID", "INDONESIA",
|
||||
"IR", "IRAN (ISLAMIC REPUBLIC OF)",
|
||||
"IQ", "IRAQ",
|
||||
"IE", "IRELAND",
|
||||
"IL", "ISRAEL",
|
||||
"IT", "ITALY",
|
||||
"JM", "JAMAICA",
|
||||
"JP", "JAPAN",
|
||||
"JO", "JORDAN",
|
||||
"KZ", "KAZAKHSTAN",
|
||||
"KE", "KENYA",
|
||||
"KI", "KIRIBATI",
|
||||
"KP", "KOREA, DEMOCRATIC PEOPLE'S REPUBLIC OF",
|
||||
"KR", "KOREA, REPUBLIC OF",
|
||||
"KW", "KUWAIT",
|
||||
"KG", "KYRGYZSTAN",
|
||||
"LA", "LAO PEOPLE'S DEMOCRATIC REPUBLIC",
|
||||
"LV", "LATVIA",
|
||||
"LB", "LEBANON",
|
||||
"LS", "LESOTHO",
|
||||
"LR", "LIBERIA",
|
||||
"LY", "LIBYAN ARAB JAMAHIRIYA",
|
||||
"LI", "LIECHTENSTEIN",
|
||||
"LT", "LITHUANIA",
|
||||
"LU", "LUXEMBOURG",
|
||||
"MO", "MACAU",
|
||||
"MK", "MACEDONIA, THE FORMER YUGOSLAV REPUBLIC OF",
|
||||
"MG", "MADAGASCAR",
|
||||
"MW", "MALAWI",
|
||||
"MY", "MALAYSIA",
|
||||
"MV", "MALDIVES",
|
||||
"ML", "MALI",
|
||||
"MT", "MALTA",
|
||||
"MH", "MARSHALL ISLANDS",
|
||||
"MQ", "MARTINIQUE",
|
||||
"MR", "MAURITANIA",
|
||||
"MU", "MAURITIUS",
|
||||
"YT", "MAYOTTE",
|
||||
"MX", "MEXICO",
|
||||
"FM", "MICRONESIA, FEDERATED STATES OF",
|
||||
"MD", "MOLDOVA, REPUBLIC OF",
|
||||
"MC", "MONACO",
|
||||
"MN", "MONGOLIA",
|
||||
"MS", "MONTSERRAT",
|
||||
"MA", "MOROCCO",
|
||||
"MZ", "MOZAMBIQUE",
|
||||
"MM", "MYANMAR",
|
||||
"NA", "NAMIBIA",
|
||||
"NR", "NAURU",
|
||||
"NP", "NEPAL",
|
||||
"NL", "NETHERLANDS",
|
||||
"AN", "NETHERLANDS ANTILLES",
|
||||
"NC", "NEW CALEDONIA",
|
||||
"NZ", "NEW ZEALAND",
|
||||
"NI", "NICARAGUA",
|
||||
"NE", "NIGER",
|
||||
"NG", "NIGERIA",
|
||||
"NU", "NIUE",
|
||||
"NF", "NORFOLK ISLAND",
|
||||
"MP", "NORTHERN MARIANA ISLANDS",
|
||||
"NO", "NORWAY",
|
||||
"OM", "OMAN",
|
||||
"PK", "PAKISTAN",
|
||||
"PW", "PALAU",
|
||||
"PA", "PANAMA",
|
||||
"PG", "PAPUA NEW GUINEA",
|
||||
"PY", "PARAGUAY",
|
||||
"PE", "PERU",
|
||||
"PH", "PHILIPPINES",
|
||||
"PN", "PITCAIRN",
|
||||
"PL", "POLAND",
|
||||
"PT", "PORTUGAL",
|
||||
"PR", "PUERTO RICO",
|
||||
"QA", "QATAR",
|
||||
"RE", "REUNION",
|
||||
"RO", "ROMANIA",
|
||||
"RU", "RUSSIAN FEDERATION",
|
||||
"RW", "RWANDA",
|
||||
"KN", "SAINT KITTS AND NEVIS",
|
||||
"LC", "SAINT LUCIA",
|
||||
"VC", "SAINT VINCENT AND THE GRENADINES",
|
||||
"WS", "SAMOA",
|
||||
"SM", "SAN MARINO",
|
||||
"ST", "SAO TOME AND PRINCIPE",
|
||||
"SA", "SAUDI ARABIA",
|
||||
"SN", "SENEGAL",
|
||||
"SC", "SEYCHELLES",
|
||||
"SL", "SIERRA LEONE",
|
||||
"SG", "SINGAPORE",
|
||||
"SK", "SLOVAKIA (Slovak Republic)",
|
||||
"SI", "SLOVENIA",
|
||||
"SB", "SOLOMON ISLANDS",
|
||||
"SO", "SOMALIA",
|
||||
"ZA", "SOUTH AFRICA",
|
||||
"GS", "SOUTH GEORGIA AND THE SOUTH SANDWICH ISLANDS",
|
||||
"ES", "SPAIN",
|
||||
"LK", "SRI LANKA",
|
||||
"SH", "ST. HELENA",
|
||||
"PM", "ST. PIERRE AND MIQUELON",
|
||||
"SD", "SUDAN",
|
||||
"SR", "SURINAME",
|
||||
"SJ", "SVALBARD AND JAN MAYEN ISLANDS",
|
||||
"SZ", "SWAZILAND",
|
||||
"SE", "SWEDEN",
|
||||
"CH", "SWITZERLAND",
|
||||
"SY", "SYRIAN ARAB REPUBLIC",
|
||||
"TW", "TAIWAN, PROVINCE OF CHINA",
|
||||
"TJ", "TAJIKISTAN",
|
||||
"TZ", "TANZANIA, UNITED REPUBLIC OF",
|
||||
"TH", "THAILAND",
|
||||
"TG", "TOGO",
|
||||
"TK", "TOKELAU",
|
||||
"TO", "TONGA",
|
||||
"TT", "TRINIDAD AND TOBAGO",
|
||||
"TN", "TUNISIA",
|
||||
"TR", "TURKEY",
|
||||
"TM", "TURKMENISTAN",
|
||||
"TC", "TURKS AND CAICOS ISLANDS",
|
||||
"TV", "TUVALU",
|
||||
"UG", "UGANDA",
|
||||
"UA", "UKRAINE",
|
||||
"AE", "UNITED ARAB EMIRATES",
|
||||
"GB", "UNITED KINGDOM",
|
||||
"US", "UNITED STATES",
|
||||
"UM", "UNITED STATES MINOR OUTLYING ISLANDS",
|
||||
"UY", "URUGUAY",
|
||||
"UZ", "UZBEKISTAN",
|
||||
"VU", "VANUATU",
|
||||
"VE", "VENEZUELA",
|
||||
"VN", "VIET NAM",
|
||||
"VG", "VIRGIN ISLANDS (BRITISH)",
|
||||
"VI", "VIRGIN ISLANDS (U.S.)",
|
||||
"WF", "WALLIS AND FUTUNA ISLANDS",
|
||||
"EH", "WESTERN SAHARA",
|
||||
"YE", "YEMEN",
|
||||
"YU", "YUGOSLAVIA",
|
||||
"ZM", "ZAMBIA",
|
||||
"ZW", "ZIMBABWE",
|
||||
);
|
||||
return %Hash;
|
||||
}
|
||||
|
||||
"That's all folks ;-)";
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
exchange.pl - Exchange between currencies
|
||||
|
||||
=head1 PREREQUISITES
|
||||
|
||||
LWP::UserAgent
|
||||
HTTP::Request::Common
|
||||
|
||||
=head1 PARAMETERS
|
||||
|
||||
exchange
|
||||
|
||||
=head1 PUBLIC INTERFACE
|
||||
|
||||
Exchange <amount> <currency> for|[in]to <currency>
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Contacts C<www.xe.net> and grabs the exchange rates; warning - the
|
||||
currency code is a bit cranky.
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
Bobby <bobby@bofh.dk>
|
@ -0,0 +1,29 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
# excuse.pl - serve up bofh-style excuses
|
||||
#
|
||||
# lenzo@cs.cmu.edu -- fixed return codes
|
||||
# updated 990818 08:31:11, bobby@bofh.dk
|
||||
#
|
||||
|
||||
BEGIN {
|
||||
eval "use Net::Telnet";
|
||||
$no_excuse++ if ($@) ;
|
||||
}
|
||||
|
||||
sub excuse {
|
||||
my $host = "bofh.engr.wisc.edu";
|
||||
my $port = 666;
|
||||
my $t = Net::Telnet->new(Host => $host,
|
||||
Errmode => "return",
|
||||
Port => $port);
|
||||
if (defined $t) {
|
||||
$t->waitfor("/Your excuse is: /");
|
||||
my $reply = $t->get;
|
||||
return $reply;
|
||||
} else {
|
||||
return "The server at $host (port $port) appears to be down.";
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
@ -0,0 +1,48 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
my $no_insult;
|
||||
|
||||
BEGIN {
|
||||
eval "use Net::Telnet ();";
|
||||
$no_insult++ if ($@) ;
|
||||
}
|
||||
|
||||
sub insult {
|
||||
# alex ayars was a sport and constributed a patch
|
||||
my $t = new Net::Telnet (Errmode => "return", Timeout => 3);
|
||||
$t->Net::Telnet::open(Host => "insulthost.colorado.edu", Port => "1695");
|
||||
my $line = $t->Net::Telnet::getline(Timeout => 4);
|
||||
return $line;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
insult.pl - Contact the Insult Server for an insult
|
||||
|
||||
=head1 PREREQUISITES
|
||||
|
||||
Net::Telnet
|
||||
|
||||
=head1 PARAMETERS
|
||||
|
||||
insult
|
||||
|
||||
=head1 PUBLIC INTERFACE
|
||||
|
||||
insult <foo>
|
||||
|
||||
If you have Babel enabled,
|
||||
|
||||
insult <foo> in <language code>
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Produces an insult from the Insult Server.
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
<michael@limit.org>
|
@ -0,0 +1,51 @@
|
||||
# Template infobot extension
|
||||
|
||||
use strict;
|
||||
|
||||
BEGIN {
|
||||
# eval your modules here
|
||||
}
|
||||
|
||||
sub extension {
|
||||
# Do stuff, return something
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Filename.pl - Description
|
||||
|
||||
=head1 PREREQUISITES
|
||||
|
||||
Some::Module
|
||||
|
||||
=head1 PARAMETERS
|
||||
|
||||
switchname
|
||||
|
||||
=over 4
|
||||
|
||||
=item value1
|
||||
|
||||
Description
|
||||
|
||||
=item value2
|
||||
|
||||
Description
|
||||
|
||||
=back
|
||||
|
||||
=head1 PUBLIC INTERFACE
|
||||
|
||||
Here you put how you call your sub from the bot user's point of view
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
What is it?
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
Who are you?
|
@ -0,0 +1,63 @@
|
||||
# Infobot user extension stubs
|
||||
# Kevin A. Lenzo
|
||||
|
||||
# put your routines in here.
|
||||
|
||||
@howAreYa = ("just great", "peachy", "mas o menos",
|
||||
"you know how it is", "eh, ok", "pretty good. how about you");
|
||||
|
||||
sub myRoutines {
|
||||
# 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.
|
||||
|
||||
# example:
|
||||
|
||||
if ($addressed) {
|
||||
# only if the infobot is addressed
|
||||
if ($message =~ /how (the hell )?are (ya|you)( doin\'?g?)?\?*$/) {
|
||||
return $howAreYa[rand($#howAreYa)];
|
||||
}
|
||||
|
||||
} else {
|
||||
# we haven't been addressed, but we are still listening
|
||||
}
|
||||
|
||||
# another example: rot13
|
||||
|
||||
if ($message =~ /^rot13\s+(.*)/i) {
|
||||
# rot13 it
|
||||
my $reply = $1;
|
||||
$reply =~ y/A-Za-z/N-ZA-Mn-za-m/;
|
||||
return $reply;
|
||||
}
|
||||
|
||||
return undef; # do nothing and let the other routines have a go
|
||||
# Extras.pl is called next; look there for more complex examples.
|
||||
}
|
||||
|
||||
1;
|
||||
|
@ -0,0 +1,205 @@
|
||||
#!/usr/bin/perl -w
|
||||
#
|
||||
# Lame-o-Nickometer backend
|
||||
#
|
||||
# (c) 1998 Adam Spiers <adam.spiers@new.ox.ac.uk>
|
||||
#
|
||||
# You may do whatever you want with this code, but give me credit.
|
||||
#
|
||||
# $Id: nickometer.pl,v 1.1 2000/12/09 22:24:17 lenzo Exp $
|
||||
#
|
||||
|
||||
use strict;
|
||||
use Getopt::Std;
|
||||
use Math::Trig;
|
||||
|
||||
use vars qw($VERSION $score $verbose);
|
||||
|
||||
$VERSION = '$Revision: 1.1 $'; # '
|
||||
$VERSION =~ s/^.*?([\d.]+).*?$/$1/;
|
||||
|
||||
sub nickometer ($) {
|
||||
local $_ = shift;
|
||||
|
||||
local $score = 0;
|
||||
|
||||
# Deal with special cases (precede with \ to prevent de-k3wlt0k)
|
||||
my %special_cost = (
|
||||
'69' => 500,
|
||||
'dea?th' => 500,
|
||||
'dark' => 400,
|
||||
'n[i1]ght' => 300,
|
||||
'n[i1]te' => 500,
|
||||
'fuck' => 500,
|
||||
'sh[i1]t' => 500,
|
||||
'coo[l1]' => 500,
|
||||
'kew[l1]' => 500,
|
||||
'lame' => 500,
|
||||
'dood' => 500,
|
||||
'dude' => 500,
|
||||
'[l1](oo?|u)[sz]er' => 500,
|
||||
'[l1]eet' => 500,
|
||||
'e[l1]ite' => 500,
|
||||
'[l1]ord' => 500,
|
||||
'pron' => 1000,
|
||||
'warez' => 1000,
|
||||
'xx' => 100,
|
||||
'\[rkx]0' => 1000,
|
||||
'\0[rkx]' => 1000,
|
||||
);
|
||||
|
||||
foreach my $special (keys %special_cost) {
|
||||
my $special_pattern = $special;
|
||||
my $raw = ($special_pattern =~ s/^\\//);
|
||||
my $nick = $_;
|
||||
unless ($raw) {
|
||||
$nick =~ tr/023457+8/ozeasttb/;
|
||||
}
|
||||
&punish($special_cost{$special}, "matched special case /$special_pattern/")
|
||||
if $nick =~ /$special_pattern/i;
|
||||
}
|
||||
|
||||
# Allow Perl referencing
|
||||
s/^\\([A-Za-z])/$1/;
|
||||
|
||||
# Keep me safe from Pudge ;-)
|
||||
s/\^(pudge)/$1/i;
|
||||
|
||||
# C-- ain't so bad either
|
||||
s/^C--$/C/;
|
||||
|
||||
# Punish consecutive non-alphas
|
||||
s/([^A-Za-z0-9]{2,})
|
||||
/my $consecutive = length($1);
|
||||
&punish(&slow_pow(10, $consecutive),
|
||||
"$consecutive total consecutive non-alphas")
|
||||
if $consecutive;
|
||||
$1
|
||||
/egx;
|
||||
|
||||
# Remove balanced brackets and punish for unmatched
|
||||
while (s/^([^()]*) (\() (.*) (\)) ([^()]*) $/$1$3$5/x ||
|
||||
s/^([^{}]*) (\{) (.*) (\}) ([^{}]*) $/$1$3$5/x ||
|
||||
s/^([^\[\]]*) (\[) (.*) (\]) ([^\[\]]*) $/$1$3$5/x)
|
||||
{
|
||||
print "Removed $2$4 outside parentheses; nick now $_\n" if $verbose;
|
||||
}
|
||||
my $parentheses = tr/(){}[]/(){}[]/;
|
||||
&punish(&slow_pow(10, $parentheses),
|
||||
"$parentheses unmatched " .
|
||||
($parentheses == 1 ? 'parenthesis' : 'parentheses'))
|
||||
if $parentheses;
|
||||
|
||||
# Punish k3wlt0k
|
||||
my @k3wlt0k_weights = (5, 5, 2, 5, 2, 3, 1, 2, 2, 2);
|
||||
for my $digit (0 .. 9) {
|
||||
my $occurrences = s/$digit/$digit/g || 0;
|
||||
&punish($k3wlt0k_weights[$digit] * $occurrences * 30,
|
||||
$occurrences . ' ' .
|
||||
(($occurrences == 1) ? 'occurrence' : 'occurrences') .
|
||||
" of $digit")
|
||||
if $occurrences;
|
||||
}
|
||||
|
||||
# An alpha caps is not lame in middle or at end, provided the first
|
||||
# alpha is caps.
|
||||
my $orig_case = $_;
|
||||
s/^([^A-Za-z]*[A-Z].*[a-z].*?)[_-]?([A-Z])/$1\l$2/;
|
||||
|
||||
# A caps first alpha is sometimes not lame
|
||||
s/^([^A-Za-z]*)([A-Z])([a-z])/$1\l$2$3/;
|
||||
|
||||
# Punish uppercase to lowercase shifts and vice-versa, modulo
|
||||
# exceptions above
|
||||
my $case_shifts = &case_shifts($orig_case);
|
||||
&punish(&slow_pow(9, $case_shifts),
|
||||
$case_shifts . ' case ' .
|
||||
(($case_shifts == 1) ? 'shift' : 'shifts'))
|
||||
if ($case_shifts > 1 && /[A-Z]/);
|
||||
|
||||
# Punish lame endings (TorgoX, WraithX et al. might kill me for this :-)
|
||||
&punish(50, 'last alpha lame') if $orig_case =~ /[XZ][^a-zA-Z]*$/;
|
||||
|
||||
# Punish letter to numeric shifts and vice-versa
|
||||
my $number_shifts = &number_shifts($_);
|
||||
&punish(&slow_pow(9, $number_shifts),
|
||||
$number_shifts . ' letter/number ' .
|
||||
(($number_shifts == 1) ? 'shift' : 'shifts'))
|
||||
if $number_shifts > 1;
|
||||
|
||||
# Punish extraneous caps
|
||||
my $caps = tr/A-Z/A-Z/;
|
||||
&punish(&slow_pow(7, $caps), "$caps extraneous caps") if $caps;
|
||||
|
||||
# Now punish anything that's left
|
||||
my $remains = $_;
|
||||
$remains =~ tr/a-zA-Z0-9//d;
|
||||
my $remains_length = length($remains);
|
||||
|
||||
&punish(50 * $remains_length + &slow_pow(9, $remains_length),
|
||||
$remains_length . ' extraneous ' .
|
||||
(($remains_length == 1) ? 'symbol' : 'symbols'))
|
||||
if $remains;
|
||||
|
||||
print "\nRaw lameness score is $score\n" if $verbose;
|
||||
|
||||
# Use an appropriate function to map [0, +inf) to [0, 100)
|
||||
my $percentage = 100 *
|
||||
(1 + tanh(($score-400)/400)) *
|
||||
(1 - 1/(1+$score/5)) / 2;
|
||||
|
||||
my $digits = 2 * (2 - &round_up(log(100 - $percentage) / log(10)));
|
||||
|
||||
return sprintf "%.${digits}f", $percentage;
|
||||
}
|
||||
|
||||
sub case_shifts ($) {
|
||||
# This is a neat trick suggested by freeside. Thanks freeside!
|
||||
|
||||
my $shifts = shift;
|
||||
|
||||
$shifts =~ tr/A-Za-z//cd;
|
||||
$shifts =~ tr/A-Z/U/s;
|
||||
$shifts =~ tr/a-z/l/s;
|
||||
|
||||
return length($shifts) - 1;
|
||||
}
|
||||
|
||||
sub number_shifts ($) {
|
||||
my $shifts = shift;
|
||||
|
||||
$shifts =~ tr/A-Za-z0-9//cd;
|
||||
$shifts =~ tr/A-Za-z/l/s;
|
||||
$shifts =~ tr/0-9/n/s;
|
||||
|
||||
return length($shifts) - 1;
|
||||
}
|
||||
|
||||
sub slow_pow ($$) {
|
||||
my ($x, $y) = @_;
|
||||
|
||||
return $x ** &slow_exponent($y);
|
||||
}
|
||||
|
||||
sub slow_exponent ($) {
|
||||
my $x = shift;
|
||||
|
||||
return 1.3 * $x * (1 - atan($x/6) *2/pi);
|
||||
}
|
||||
|
||||
sub round_up ($) {
|
||||
my $float = shift;
|
||||
|
||||
return int($float) + ((int($float) == $float) ? 0 : 1);
|
||||
}
|
||||
|
||||
sub punish ($$) {
|
||||
my ($damage, $reason) = @_;
|
||||
|
||||
return unless $damage;
|
||||
|
||||
$score += $damage;
|
||||
print "$damage lameness points awarded: $reason\n" if $verbose;
|
||||
}
|
||||
|
||||
1;
|
@ -0,0 +1,242 @@
|
||||
# purldoc.pl - Part of the kinder, gentler #Perl.
|
||||
|
||||
# Though he hates to admit it, this was written by the gent
|
||||
# on EFNet #Perl known most often as Masque. Comments to
|
||||
# masque@pound.perl.org. This code is covered under the same
|
||||
# license as the rest of infobot.
|
||||
|
||||
# Eternal thanks to oznoid for writing the other bits, and
|
||||
# for being a good friend to all Perldom. We're fortunate
|
||||
# to have him.
|
||||
|
||||
# Please note that in this version, purldoc only searches the
|
||||
# question _titles_. This is MUCH faster, and reduces the
|
||||
# amount of work that the host machine has to do. This is
|
||||
# the same way that perldoc -q does it, so don't complain
|
||||
# _too_ loudly.
|
||||
|
||||
# KNOWN BUGS: Still sucks in many ways.
|
||||
|
||||
# removed all throttling code and replaced with returning
|
||||
# \n-delimited clumps rather than direct msg or say.
|
||||
|
||||
sub purldoc {
|
||||
my @results;
|
||||
my $msg_params;
|
||||
my $msg_limit = 6;
|
||||
|
||||
# changed this to just return the answers, mainly -- kl
|
||||
($message, $msg_params) = split /;/, $message, 2;
|
||||
|
||||
print "got: $message\n";
|
||||
|
||||
my $pd_return = &purldoc_lookup($message, \@results);
|
||||
return $pd_return unless @results;
|
||||
|
||||
my $res = '';
|
||||
|
||||
# removed the public/private distinction to be handled in
|
||||
# the calling code -- kl
|
||||
|
||||
# This is one of those ideas that sounds great until you actually
|
||||
# implement it. I now think the following concept sucks. Hard.
|
||||
# On the off chance you disagree with me, leave it in. :]
|
||||
|
||||
# Complain if the user wants a specific number of all messages.
|
||||
|
||||
if ($msg_params =~ /\d+/ && $msg_params =~ /all/i) {
|
||||
&msg($who, "Oh come now. Don't give me a number AND 'all'.");
|
||||
return 'NOREPLY';
|
||||
}
|
||||
|
||||
# Many thanks to crimson for the following join incantation.
|
||||
# This is basically join() with a limit of $msg_limit items. Neat.
|
||||
# I've uglified it by putting spaces in it and thus making it human
|
||||
# readable. ;) The solution used lower to truncate the array to
|
||||
# the message limit is somewhat more elegant, but I'm leaving this
|
||||
# in comments because it's neat.
|
||||
|
||||
# &msg($who, join("; ",(@results[0..(@results < $msg_limit ? @results - $msg_limit : $msg_limit - 1)]))) and return unless $msg_params;
|
||||
|
||||
$msg_limit = $1 if $msg_params =~ /(\d+)/;
|
||||
my $max_lines = getparam('purldoc_max_lines');
|
||||
|
||||
if ($msgType =~ /public/) {
|
||||
my $max_public = getparam('purldoc_max_public');
|
||||
$msg_limit = $max_public if $max_public < $max_lines;
|
||||
}
|
||||
|
||||
# moved this down -- kl
|
||||
|
||||
if (getparam('purldoc') eq 'verbose') {
|
||||
&msg($who, "There are " . (scalar @results - $msg_limit) . " more matches for your query. /msg me with the query to see more.");
|
||||
}
|
||||
|
||||
# Okay, so it turns out that 'all' is a bit of a lie. It's
|
||||
# more like 'all, unless X'. 30 will tie the bot up long enough,
|
||||
# and people need to learn to limit their matches to some degree
|
||||
# anyway. PATCHES ARE WELCOME. Yes, I'm aware the clumping code
|
||||
# is total baby-talk. See earlier 'patches' comment.
|
||||
|
||||
# clump limit is hardcoded.
|
||||
|
||||
# Look what happens when you try to crossbreed style rules!
|
||||
# ;] Hey, for that matter, check out the low-quality "let's pass
|
||||
# the -w test" kludge! Did I mention that this whole subroutine
|
||||
# was written over four days, spending no more than 10 minutes at
|
||||
# a time per sitting? I'll rewrite this, but for now I just want
|
||||
# to get the output working. Besides, I've got a couple of hours
|
||||
# before the next code release....
|
||||
|
||||
# Come to think of it, we're not using -w at all. I am
|
||||
# DEFINITELY going to rewrite this, so please stop laughing
|
||||
# at this code now. The other subroutine is reasonably well
|
||||
# written, go read that one instead.
|
||||
|
||||
# Thanks, lucs! $#results = $msg_limit -1 is neato. :]
|
||||
$#results = $msg_limit - 1 if @results > $msg_limit;
|
||||
|
||||
if (defined $msg_params && $msg_params =~ /clump/i) {
|
||||
my $clump;
|
||||
for (0..$#results) {
|
||||
$clump .= "$results[$_]; ";
|
||||
if ($_ == $#results) {
|
||||
$clump =~ s/; $//;
|
||||
return $clump;
|
||||
}
|
||||
unless (($_ + 1) % 4) {
|
||||
$clump =~ s/; $/.../;
|
||||
$clump .= " \n";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
my $res = '';
|
||||
for (0..$#results) {
|
||||
$res .= " \n" if $res;
|
||||
$res .= $results[$_];
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
}
|
||||
|
||||
# End sub purldoc()
|
||||
|
||||
# I probably don't need to pass the array to the subroutine, but
|
||||
# it looks more impressive when the subroutine is all pr0totyped,
|
||||
# etc., and perhaps I can distract you, the noble reader, from
|
||||
# noticing the other less impressive bits of this code by putting
|
||||
# in overly complicated code. We pass the array because we're only
|
||||
# using return values if the sub blows up. Lame? Yes. Stupid?
|
||||
# Perhaps. Intentional? Sure! This is perl, it's supposed to
|
||||
# be fun. ;)
|
||||
|
||||
sub purldoc_lookup (\$\@) {
|
||||
|
||||
my $regex = shift;
|
||||
my $original_regex = $regex;
|
||||
my $target_filename = getparam('purldoc_override') || 'pod/perlfaq.pod';
|
||||
my @search_dirs = @INC;
|
||||
my $results = shift;
|
||||
|
||||
# There is most likely a much more elegant way to do this search, however
|
||||
# this works, and it's 2am, so you're welcome to comment all you like either
|
||||
# to /dev/null or to masque@pound.perl.com. Patches welcome. :]
|
||||
|
||||
unless (getparam('purldoc_override')) {
|
||||
for (@search_dirs) {
|
||||
$target_filename = "$_/$target_filename" and last if -e "$_/$target_filename";
|
||||
}
|
||||
}
|
||||
|
||||
# We don't do -f. -f would be crazy-long to return. It'd be easy
|
||||
# enough to do, but it should only reply via /msg if implemented.
|
||||
# Hmm...perhaps it should also be usable as
|
||||
# 'tell $who about purldoc -f $function', though that has the
|
||||
# potential for abuse. Perhaps purl should respond '$who wants
|
||||
# you to ask me about purldoc -f $function,' but that is really
|
||||
# pretty lame (and likely to be ignored.) Ah well. Reserved for
|
||||
# future use.
|
||||
|
||||
return "No -f for you! NEXT!" if $regex =~ /^\s*-t?f/i;
|
||||
|
||||
# Sanity check on $regex. We don't want people searching for 'I', etc.
|
||||
# It was most tempting to add 'HTML' and 'CGI' to the first regex, but
|
||||
# I overcame the temptation...for now. ;)
|
||||
|
||||
$regex =~ s/(?:^|\b|\s)(?:\-t?qt?|I|do|how|my|what|which|who|can)\b/ /gi;
|
||||
|
||||
# I'm not proud of using the fearsome '.*?' here, but that leading and
|
||||
# trailing whitespace MUST GO! IT ALL MUST GO! WE'LL MAKE ANY DEAL!
|
||||
# IT'S CRAAAAAAAAAAAAAAAAAAZY MASQUE'S USED REGEX EMPORIUM! COME ON
|
||||
# DOWN! WE'LL CLUB A SEAL TO MAKE A BETTER DEAL! (Weird Al, UHF)++
|
||||
|
||||
$regex =~ s/^\s*(.*?)\s*$/$1/;
|
||||
|
||||
# We're pretty picky about the regex. Currently there are no helpful
|
||||
# two-letter strings in perlfaq (with the possible exception of 'do',
|
||||
# which is being filtered for other reasons) so we require the length
|
||||
# to be above that, and also we only want letters of the alphabet,
|
||||
# thanks.
|
||||
|
||||
return "\'$original_regex\' isn't a good purldoc search string." unless $regex =~ /^[A-Za-z ]+$/ and length $regex > 2;
|
||||
|
||||
open PURLDOC, "<$target_filename" or return "Sorry, guys. I can't open perlfaq right now.";
|
||||
|
||||
# ACHTUNG! THE FOLLOWING CODE IS WILDLY INEFFICIENT! HAVE A CAPS LOCKY DAY.
|
||||
|
||||
my $chapter;
|
||||
my $versecount;
|
||||
|
||||
while (<PURLDOC>) {
|
||||
last if /^=head1 Credits/;
|
||||
$chapter = $1 and $versecount = 0 if /^=item L<(\w+\d)/;
|
||||
if (s/=item \* //) {
|
||||
chomp;
|
||||
$versecount++;
|
||||
push(@$results, "$chapter, question $versecount: $_") if /$regex/i;
|
||||
}
|
||||
}
|
||||
return "No matches for keyphrase '$regex' found." unless scalar @$results;
|
||||
}
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
purldoc.pl - Interface to the Perl FAQ.
|
||||
|
||||
=head1 PREREQUISITES
|
||||
|
||||
Nothing.
|
||||
|
||||
=head1 PARAMETERS
|
||||
|
||||
=over 4
|
||||
|
||||
=item purldoc
|
||||
|
||||
Turns the facility on and off
|
||||
|
||||
=item purldoc_triggers
|
||||
|
||||
Regexp used to match a call to the FAQ. Should be something like
|
||||
`purldoc' or `perldoc'.
|
||||
|
||||
=back
|
||||
|
||||
=head1 PUBLIC INTERFACE
|
||||
|
||||
(Depends on your triggers, but generally:)
|
||||
|
||||
purldoc <topic>
|
||||
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This looks up the given words as parts of a question in the Perl FAQ,
|
||||
and returns the top three matching questions.
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
Masque <masque@pound.perl.org>
|
@ -0,0 +1,77 @@
|
||||
use strict;
|
||||
|
||||
my $no_quote;
|
||||
|
||||
BEGIN {
|
||||
eval qq{
|
||||
use LWP::UserAgent;
|
||||
use HTTP::Request::Common qw(GET);
|
||||
};
|
||||
|
||||
$no_quote++ if($@);
|
||||
}
|
||||
|
||||
sub get_quote {
|
||||
my ($symbol) = @_;
|
||||
|
||||
if ($no_quote) {
|
||||
return "error: stock quotes require LWP::UserAgent and HTTP::Request... sorry.";
|
||||
}
|
||||
|
||||
if ($symbol) {
|
||||
&status ("getting stock quote for $symbol");
|
||||
|
||||
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://quote.yahoo.com/d/quotes/csv?s=$symbol&f=sl1d1t1c1ohgv&e=.csv");
|
||||
my $result = $ua->request ($request);
|
||||
|
||||
if ($result->is_success) {
|
||||
my $str = $result->content;
|
||||
# strip quotes and extra whitespace
|
||||
$str =~ s/["\s]//g;
|
||||
chomp ($str);
|
||||
my ($name, $current, $date, $time, $change) = split (/,/, $str);
|
||||
|
||||
if ($current eq "N/A") {
|
||||
return "No match for $name";
|
||||
}
|
||||
return "At $time GMT-4, $name traded at $current ($change)";
|
||||
} else {
|
||||
return "error: there was a problem getting the quote from Yahoo\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
quote.pl - Get stock quote from yahoo
|
||||
|
||||
=head1 PREREQUISITES
|
||||
|
||||
LWP::UserAgent
|
||||
HTTP::Request::Common
|
||||
|
||||
=head1 PARAMETERS
|
||||
|
||||
quote
|
||||
|
||||
=head1 PUBLIC INTERFACE
|
||||
|
||||
purl, quote <4-LETTER-TICKERNAME>
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This allows you to get a stock quote for a symbol from yahoo's stock
|
||||
service.
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
LotR <martijn@earthling.net> based on quote.pl from
|
||||
Xachbot (http://www.xach.com/xachbot/quote.pl)
|
@ -0,0 +1,108 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
# infobot -- copyright kevin lenzo (c) 1997-infinity
|
||||
|
||||
# no warrantee expressed or implied. terms as the
|
||||
# license for X11R6 when needed.
|
||||
|
||||
BEGIN {
|
||||
$VER_MAJ = 0;
|
||||
$VER_MIN = 45;
|
||||
$VER_MOD = 3;
|
||||
|
||||
$version = "infobot $VER_MAJ\.$VER_MIN\.$VER_MOD [Wurm]";
|
||||
}
|
||||
|
||||
BEGIN {
|
||||
$filesep = '/';
|
||||
|
||||
# set this to the absolute path if you need it; especially
|
||||
# if . is not in your path
|
||||
|
||||
$param{'basedir'} = ($0 =~ /(.*)$filesep/) ? $1 : '.';
|
||||
# $infobot_base_dir = '/usr/local/lib/infobot';
|
||||
|
||||
# change this next line if you run a local instance of
|
||||
# an infobot and use the code from the main location.
|
||||
# the 'files' directory contains infobot.config and
|
||||
# infobot.users, among other things.
|
||||
|
||||
$param{'confdir'} = "$param{basedir}${filesep}conf";
|
||||
|
||||
# everything is loaded, then the variables that
|
||||
# you want to set will override the defaults; this
|
||||
# is why all these requires are here.
|
||||
|
||||
$param{'srcdir'} = $param{'basedir'}.$filesep."src";
|
||||
|
||||
opendir DIR, $param{'srcdir'}
|
||||
or die "can't open source directory $param{srcdir}: $!";
|
||||
|
||||
while ($file = readdir DIR) {
|
||||
next unless $file =~ /\.pl$/;
|
||||
require "$param{srcdir}$filesep$file";
|
||||
}
|
||||
closedir DIR;
|
||||
|
||||
$param{'extradir'} = $param{'basedir'}.$filesep."extras";
|
||||
|
||||
opendir DIR, $param{'extradir'}
|
||||
or die "can't open extras directory $param{extradir}: $!";
|
||||
|
||||
while ($file = readdir DIR) {
|
||||
next unless $file =~ /\.pl$/;
|
||||
require "$param{extradir}$filesep$file";
|
||||
}
|
||||
closedir DIR;
|
||||
}
|
||||
|
||||
# get the command line arguments
|
||||
&getArgs();
|
||||
|
||||
# initialize everything
|
||||
&setup();
|
||||
|
||||
# launch the irc event loop
|
||||
&irc();
|
||||
|
||||
exit 0; # just so you don't look farther down in this file :)
|
||||
|
||||
|
||||
# --- support routines
|
||||
|
||||
sub usage {
|
||||
print "\n";
|
||||
print " usage: $0 [-h] [<paramfile1> [<pf2> ...]]\n";
|
||||
print "\n";
|
||||
print " -h this message\n";
|
||||
print "\n";
|
||||
}
|
||||
|
||||
sub getArgs {
|
||||
if (@ARGV) {
|
||||
while (@ARGV) {
|
||||
my $arg = shift @ARGV;
|
||||
if ($arg =~ s/^-//) {
|
||||
# switchies
|
||||
if ($arg eq 'i') {
|
||||
# go into irc mode despite db setting
|
||||
$overrideMode = 'IRC';
|
||||
} else {
|
||||
# -h is in here by default
|
||||
&usage;
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
# no switchie. currently assumed to be
|
||||
# a paramfile by default
|
||||
push @paramfiles, $arg;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@paramfiles = ();
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
|
@ -0,0 +1,36 @@
|
||||
|
||||
update_db [-m <module>] <filename> <dbname>
|
||||
|
||||
adds items in the file <filename> to the db with
|
||||
the basename <dbname>. if -m <module> is specified that
|
||||
module is used rather than AnyDBM_File.
|
||||
|
||||
file is of the form provided in ../files/infobot-is.txt
|
||||
which is to say
|
||||
|
||||
<key> => <value>
|
||||
|
||||
one per line, and <dbname> is something like infobot-is
|
||||
|
||||
if the db doesn't exist, it will be created. if it does
|
||||
exists, the entries will be added, potentially overwriting
|
||||
entries that exists with the same key.
|
||||
|
||||
NOTE: skips lines that do not contain a => ... you can
|
||||
add comments this way.
|
||||
|
||||
dump_db [-m <module>] <dbname>
|
||||
|
||||
turns the db into a flat ascii file of the form above.
|
||||
try e.g.
|
||||
|
||||
dump_db infobot-is
|
||||
dump_db -m DB_File infobot-is.db
|
||||
|
||||
run_infobots.pl
|
||||
|
||||
you'll need to edit this script to give the right home
|
||||
directory, but this is for crontabbing the infobot. it
|
||||
will run it if it's not already running. this is not
|
||||
highly tested! YMMV.
|
||||
|
@ -0,0 +1,71 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
$dbmdir = "/home/infobot/";
|
||||
$dbmpref = "infobot";
|
||||
|
||||
&opendbs;
|
||||
|
||||
if (@ARGV) {
|
||||
$query = join(" ", @ARGV);
|
||||
&respond($query);
|
||||
} else {
|
||||
print "> ";
|
||||
while (<>) {
|
||||
last if /^\/?quit/i;
|
||||
chomp;
|
||||
if (/s^\/eval\s+/) {
|
||||
$x = eval($_);
|
||||
print $x;
|
||||
} else {
|
||||
&respond($_);
|
||||
}
|
||||
print "> ";
|
||||
}
|
||||
}
|
||||
|
||||
sub opendbs {
|
||||
my $dp = "$dbmdir/$dbmpref";
|
||||
dbmopen(%is, "$dbmdir/$dbmpref-is", undef)
|
||||
|| die "can't open $dbmdir/$dbmpref-is -- please set path";
|
||||
dbmopen(%are, "$dbmdir/$dbmpref-are", undef)
|
||||
|| die "can't open $dbmdir/$dbmpref-are";
|
||||
}
|
||||
|
||||
sub checkdbs {
|
||||
my @reply;
|
||||
foreach $k (@_) {
|
||||
push @reply, $is{$k} if $is{$k};
|
||||
push @reply, $are{$k} if $are{$k};
|
||||
}
|
||||
return @reply;
|
||||
}
|
||||
|
||||
sub respond {
|
||||
my $query = $_[0];
|
||||
my @r;
|
||||
|
||||
$query =~ tr/A-Z/a-z/;
|
||||
$query =~ s/wh\S+\s+(is|are)\s+//;
|
||||
$query =~ s/\s*\?\s*$//;
|
||||
|
||||
if ($query =~ /\s+(are|is)\s+/i) {
|
||||
$lhs = $`; $verb = $1; $rhs = $';
|
||||
chomp $rhs;
|
||||
$$verb{$lhs} = $rhs;
|
||||
} else {
|
||||
if (@r = &checkdbs($query)) {
|
||||
foreach (@r) {
|
||||
chomp;
|
||||
print "$_\n";
|
||||
}
|
||||
} else {
|
||||
print "undefined: $query\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub dump {
|
||||
foreach (keys %is) {
|
||||
print "$_ => $is{$_}\n";
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
use Fcntl qw(/^O_/);
|
||||
|
||||
(my $Me = $0) =~ s-.*/--;
|
||||
|
||||
# XXX This should read your config file and default to the database type
|
||||
# you specified there. The library should be extended to support this.
|
||||
|
||||
my $module = my $def_module = 'AnyDBM_File';
|
||||
|
||||
if (@ARGV && $ARGV[0] =~ s/^-m//) {
|
||||
$module = shift;
|
||||
if ($module eq '') {
|
||||
@ARGV or die "$Me: no arg for -m specified\n";
|
||||
$module = shift;
|
||||
}
|
||||
}
|
||||
|
||||
if (!@ARGV || grep /^-/, @ARGV) {
|
||||
print "\n";
|
||||
print " usage: $Me [-m <dbm module>] <dbname>\n";
|
||||
print "\n";
|
||||
print " prints out an ascii flat file of the\n";
|
||||
print " database <dbname>. <dbname> should be\n";
|
||||
print " the basename of the db, e.g.\n";
|
||||
print "\n";
|
||||
print " $Me infobot-is\n";
|
||||
print "\n";
|
||||
print " <dbm module> is an alternate for $def_module,\n";
|
||||
print " eg DB_File\n";
|
||||
print "\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
eval "require $module"; die if $@;
|
||||
$| = 1;
|
||||
|
||||
foreach $dbname (@ARGV) {
|
||||
tie(%db, $module, $dbname, O_RDONLY, undef)
|
||||
|| die "Couldn't open \"$dbname\" with $module: $!";
|
||||
|
||||
my ($key, $val);
|
||||
while (($key, $val) = each %db) {
|
||||
chomp $val;
|
||||
print "$key => $val\n";
|
||||
}
|
||||
|
||||
untie(%db) || die "untie() on $dbname failed: $!";
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
#!/usr/bin/perl -w
|
||||
use strict;
|
||||
|
||||
# $Id: flock-test,v 1.1 2000/11/01 22:41:34 lenzo Exp $
|
||||
|
||||
#use sigtrap qw(die normal-signals);
|
||||
|
||||
use Fcntl ':flock';
|
||||
use POSIX 'EWOULDBLOCK';
|
||||
|
||||
(my $Me = $0) =~ s-.*/--;
|
||||
|
||||
$| = 1;
|
||||
|
||||
@ARGV == 2 or die "usage: $Me file <sh|ex|nbsh|nbex>";
|
||||
my ($file, $type) = @ARGV;
|
||||
|
||||
my $no_block = $type =~ s/^nb//;
|
||||
my $bits = $type eq 'sh' ? LOCK_SH
|
||||
: $type eq 'ex' ? LOCK_EX
|
||||
: die "$Me: unknown lock type $type\n";
|
||||
$type = 'LOCK_' . uc $type;
|
||||
|
||||
open FH, "+<$file" or die "$Me: can't read $file: $!\n";
|
||||
|
||||
if (flock FH, $bits | LOCK_NB) {
|
||||
print "Locked $file with type $type, sleeping...";
|
||||
}
|
||||
else {
|
||||
$! == EWOULDBLOCK
|
||||
or die "$Me: can't flock($file, $type | LOCK_NB): $!\n";
|
||||
$no_block and die "$Me: can't immediately lock $file with type $type\n";
|
||||
print "Blocking waiting for $type lock on $file...";
|
||||
flock FH, $bits
|
||||
or die "$Me: can't flock($file, $type): $!\n";
|
||||
print "locked, sleeping...";
|
||||
}
|
||||
|
||||
sleep;
|
||||
|
||||
#END {
|
||||
# if ($locked) {
|
||||
# flock FH, LOCK_UN or die "$Me: can't unlock $file: $!\n";
|
||||
# }
|
||||
#}
|
@ -0,0 +1,18 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
# kevin lenzo
|
||||
|
||||
# run infobot.track through here to get the
|
||||
# enters and updates in order. Adding these
|
||||
# in order should give you the db as it was.
|
||||
|
||||
while (<>) {
|
||||
next unless s/.*: (enter|update): //;
|
||||
next if /FAILED/;
|
||||
chomp;
|
||||
s/\'; was .*//;
|
||||
s/\'\s*$//;
|
||||
s/.*?\'//;
|
||||
|
||||
print "$_\n";
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
$| = 1;
|
||||
|
||||
print "plaintext> ";
|
||||
while (<>) {
|
||||
chomp;
|
||||
$result = &mkpasswd($_);
|
||||
print "\t$result\n";
|
||||
print "plaintext> ";
|
||||
}
|
||||
|
||||
sub mkpasswd {
|
||||
my $what = $_[0];
|
||||
my $salt = chr(65+rand(27)).chr(65+rand(27));
|
||||
$salt =~ s/\W/x/g;
|
||||
|
||||
return crypt($what, $salt);
|
||||
}
|
||||
|
@ -0,0 +1,31 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
|
||||
localtime(time);
|
||||
$year = 1900 + $year;
|
||||
my $snapdir = sprintf "snap-%04d%02d%02d-%02d:%02d:%02d",
|
||||
$year, $month, $mday, $hour, $min, $sec;
|
||||
mkdir $snapdir, 0744 or die "$snapdir: $!";
|
||||
$| = 1;
|
||||
|
||||
foreach $dbname (<*.db>) {
|
||||
$dbname =~ s/\.db$//;
|
||||
my $target = "$snapdir/$dbname.txt";
|
||||
print "Flattening db $dbname into $target\n";
|
||||
|
||||
dbmopen(%db, $dbname, undef) || die "Couldn't dbmopen \"$dbname\"";
|
||||
open OUT, ">$target" or die "$target: $!";
|
||||
print OUT "# $dbname at ",localtime(time),"\n";
|
||||
|
||||
my $key;
|
||||
foreach $key (keys %db) {
|
||||
my $val = $db{$key};
|
||||
chomp $val;
|
||||
print OUT "$key => $val\n";
|
||||
}
|
||||
|
||||
dbmclose(%db);
|
||||
close OUT;
|
||||
sleep 1;
|
||||
}
|
||||
|
@ -0,0 +1,45 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
$snapdir = $ARGV[0];
|
||||
|
||||
opendir DIR, $snapdir or die "$snapdir: $!";
|
||||
@files = grep /.txt$/, readdir DIR;
|
||||
closedir DIR;
|
||||
$| = 1;
|
||||
|
||||
for $sourcefile (@files) {
|
||||
$sourcefile = "$snapdir/$sourcefile";
|
||||
open(IN, $sourcefile)
|
||||
|| die "can\'t open $sourcefile as source\n";
|
||||
my $dbname = <IN>;
|
||||
chomp $dbname;
|
||||
die "Bad file: $sourcefile" unless $dbname =~ s/^\# (\S+) .*/$1/;
|
||||
|
||||
print "Restoring $sourcefile into $dbname\n";
|
||||
dbmopen(%db, $dbname, 0644) || die "Couldn't dbmopen \"$dbname\"";
|
||||
|
||||
while (<IN>) {
|
||||
chomp;
|
||||
next if /^\s*$/;
|
||||
|
||||
if (!/=>/) {
|
||||
print "skipping: $_";
|
||||
next;
|
||||
}
|
||||
my ($left, $right) = split(/\s*=>\s*/, $_, 2);
|
||||
if ($left =~ /^\s*$/) {
|
||||
warn "Empty key, ignored: ($left => $right)\n";
|
||||
next;
|
||||
}
|
||||
$left =~ s/^\s*//;
|
||||
$left =~ tr/A-Z/a-z/;
|
||||
$right =~ s/\s+$//;
|
||||
|
||||
$db{$left} = $right;
|
||||
# print $left ." => ". $right ."\n" if (!(++$dcount % 100));
|
||||
}
|
||||
|
||||
close(IN);
|
||||
dbmclose(%db);
|
||||
}
|
||||
|
@ -0,0 +1,20 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
# you will probably need to change $homedir
|
||||
# and possibly the path to perl above
|
||||
|
||||
my $homedir = '/usr/home/infobot/infobot0.34';
|
||||
my @ps = `ps auxw`;
|
||||
|
||||
@result = grep !/grep/, @ps;
|
||||
@result = grep /infobot/, @ps;
|
||||
|
||||
if (!@result) {
|
||||
print "trying to run new process\n";
|
||||
chdir($homedir) || die "can't chdir to $homedir";
|
||||
system("nohup $homedir/infobot -i $homedir/files/irc.params > /dev/null &");
|
||||
} else {
|
||||
print "already running: \n";
|
||||
print " @result\n";
|
||||
}
|
||||
|
@ -0,0 +1,42 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
if (@ARGV != 1) {
|
||||
print "\n";
|
||||
print " Usage: $0 <file.track>";
|
||||
print "\n";
|
||||
print " generates text files for update_db from\n";
|
||||
print " the tracking file log.\n";
|
||||
print "\n";
|
||||
print " creates <file.track>-is.txt and \n";
|
||||
print " <file.track>-are.txt\n";
|
||||
print "\n";
|
||||
}
|
||||
|
||||
foreach $file (@ARGV) {
|
||||
if (!open IN, $file) {
|
||||
print "can't open $file: $!\n";
|
||||
next;
|
||||
}
|
||||
|
||||
open IS, ">$file-is.txt";
|
||||
open ARE, ">$file-are.txt";
|
||||
|
||||
while (<IN>) {
|
||||
chomp;
|
||||
if (s/.*?enter: \S+ said \'(.*)\'/$1/
|
||||
or s/.*?update: \'(.*?)\'; was .*/$1/) {
|
||||
next if /FAILED/;
|
||||
if (/^(.*?) is (.*)/) {
|
||||
print IS "$1 => $2\n";
|
||||
} elsif (/^(.*?) are (.*)/) {
|
||||
print ARE "$1 => $2\n";
|
||||
}
|
||||
} else {
|
||||
# do nothing
|
||||
}
|
||||
}
|
||||
|
||||
close IN;
|
||||
close IS;
|
||||
close ARE;
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
if ((scalar(@ARGV) != 3) || (grep /^-/, @ARGV)) {
|
||||
print "\n";
|
||||
print " usage: $0 <logfile> <nickname> <dbmstem>\n";
|
||||
print "\n";
|
||||
print " undo the updates entered by nickname that appear\n";
|
||||
print " in an infobot log file\n";
|
||||
print "\n";
|
||||
print " <logfile> is an infobot text log file\n";
|
||||
print "\n";
|
||||
print " <nickname> is the nickname whose effects you\n";
|
||||
print " want to undo (without the brackets, of course)\n";
|
||||
print "\n";
|
||||
print " <dbmstem> the the basename of the dbm db\n";
|
||||
print " (e.g. 'infobot-')\n";
|
||||
print "\n";
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
($logfile, $nickname, $dbmstem) = @ARGV;
|
||||
|
||||
open(IN, $logfile)
|
||||
|| die "can\'t open $logfile as source\n";
|
||||
|
||||
if (not $test = 0) {
|
||||
dbmopen(%dbis, "$dbmstem-is", 0755)
|
||||
|| die "Couldn't dbmopen \"$dbmstem-is\"";
|
||||
dbmopen(%dbare, "$dbmstem-are", 0755)
|
||||
|| die "Couldn't dbmopen \"$dbmstem-are\"";
|
||||
}
|
||||
|
||||
$| = 1;
|
||||
|
||||
while (<IN>) {
|
||||
chomp;
|
||||
|
||||
next unless s/^(\d+) \[(\d+)\] (\S+): <(\S+)> //;
|
||||
@attr{qw/time entry type nick/} = ($1, $2, $3, $4);
|
||||
next unless $attr{'nick'} =~ /^$nickname/i;
|
||||
|
||||
if ($attr{'type'} eq 'update') {
|
||||
@attr{qw(X verb corrupted Y)} = /^\'(.*?) =(is|are)=> (.*?)\'; was \'(.*)\'$/;
|
||||
|
||||
$attr{X} =~ s/^\s*//;
|
||||
$attr{X} =~ tr/A-Z/a-z/;
|
||||
$attr{Y} =~ s/\s+$//;
|
||||
|
||||
if ($attr{verb} eq 'is') {
|
||||
$dbis{$attr{X}} = $attr{Y};
|
||||
} else {
|
||||
$dbare{$attr{X}} = $attr{Y};
|
||||
}
|
||||
|
||||
push @undo, "enter: $attr{X} =$attr{verb}=> $attr{Y}";
|
||||
|
||||
} elsif ($attr{'type'} eq 'forget') {
|
||||
$attr{X} = $_;
|
||||
warn "* can't handle 'forget' easily until 0.43.5: forget $_\n";
|
||||
} elsif ($attr{'type'} eq 'enter') {
|
||||
$attr{qw/X verb Y/} = /^(.*?) =(is|are)=> (.*)$/;
|
||||
push @undo, "delete: $1 =$2=> $3";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
close(IN);
|
||||
|
||||
while ($act = pop @undo) {
|
||||
($type, $X, $verb, $Y) = $act =~ /^(\S+): (.*?) =(\S+)=> (.*)$/;
|
||||
if ($type eq 'enter') {
|
||||
print "ENTER $X <=$verb= $Y\n";
|
||||
if ($verb eq "is") {
|
||||
$dbis{$X} = $Y;
|
||||
} else {
|
||||
$dbare{$X} = $Y;
|
||||
}
|
||||
} elsif ($type eq 'delete') {
|
||||
print "DELETE $X <=$verb= $Y\n";
|
||||
if ($verb eq "is") {
|
||||
delete $dbis{$X};
|
||||
} else {
|
||||
delete $dbare{$X};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dbmclose(%dbis);
|
||||
dbmclose(%dbare);
|
||||
exit;
|
@ -0,0 +1,69 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
use Fcntl qw(/^O_/);
|
||||
|
||||
(my $Me = $0) =~ s-.*/--;
|
||||
|
||||
# XXX This should read your config file and default to the database type
|
||||
# you specified there. The library should be extended to support this.
|
||||
|
||||
my $module = my $def_module = 'AnyDBM_File';
|
||||
if (@ARGV && $ARGV[0] =~ s/^-m//) {
|
||||
$module = shift;
|
||||
if ($module eq '') {
|
||||
@ARGV or die "$Me: no arg for -m specified\n";
|
||||
$module = shift;
|
||||
}
|
||||
}
|
||||
|
||||
if (@ARGV != 2 || (grep /^-/, @ARGV)) {
|
||||
print "\n";
|
||||
print " usage: $Me [-m <dbm module>] <sourcefile> <dbmname>\n";
|
||||
print "\n";
|
||||
print " adds elements in <sourcefile> to dbm <dbmname>\n";
|
||||
print "\n";
|
||||
print " <sourcefile> is a text file of one-per-line\n";
|
||||
print " <key> => <value>\n";
|
||||
print " pairs, \n";
|
||||
print "\n";
|
||||
print " <dbmname> the the basename of the dbm db\n";
|
||||
print " (e.g. 'infobot-is')\n";
|
||||
print "\n";
|
||||
print " <dbm module> is an alternate for $def_module,\n";
|
||||
print " eg DB_File\n";
|
||||
print "\n";
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
eval "require $module"; die if $@;
|
||||
$sourcefile = $ARGV[0];
|
||||
$dbname = $ARGV[1];
|
||||
|
||||
open(IN, $sourcefile)
|
||||
|| die "can\'t open $sourcefile as source\n";
|
||||
|
||||
tie(%db, $module, $dbname, O_RDWR | O_CREAT, 0666)
|
||||
|| die "Couldn't open \"$dbname\" with $module: $!";
|
||||
$| = 1;
|
||||
|
||||
while (<IN>) {
|
||||
chomp;
|
||||
next if /^\s*$/;
|
||||
|
||||
if (!/=>/) {
|
||||
print "skipping: $_";
|
||||
next;
|
||||
}
|
||||
my ($left, $right) = split(/\s*=>\s*/, $_, 2);
|
||||
|
||||
$left =~ s/^\s*//;
|
||||
$left =~ tr/A-Z/a-z/;
|
||||
$right =~ s/\s+$//;
|
||||
|
||||
$db{$left} = $right;
|
||||
print $left ." => ". $right ."\n" if (!(++$dcount % 100));
|
||||
}
|
||||
|
||||
close(IN);
|
||||
untie(%db) || die "untie() on $dbname failed: $!";
|
@ -0,0 +1,27 @@
|
||||
# infobot (c) 1997 Lenzo
|
||||
|
||||
sub parsectcp {
|
||||
my ($nick, $user, $host, $type, $dest) = @_;
|
||||
&status("CTCP $type $dest request from $nick");
|
||||
if ($type =~ /^version/i) {
|
||||
ctcpreply($nick, "VERSION", $version);
|
||||
} elsif ($type =~ /^(echo|ping) ?(.*)/i) {
|
||||
rawout("NOTICE $nick :\001PING $2\001");
|
||||
# ctcpreply($nick, uc($1)." $2");
|
||||
} elsif ($type =~ /^DCC /) {
|
||||
&status("DCC attempt from $who (not supported, ignored)");
|
||||
}
|
||||
}
|
||||
|
||||
sub ctcpReplyParse {
|
||||
my ($nick, $user, $host, $type, $reply) = @_;
|
||||
&status("CTCP $type reply from $nick: $reply");
|
||||
}
|
||||
|
||||
|
||||
sub ctcpreply {
|
||||
my ($rnick, $type, $reply) = @_;
|
||||
rawout("NOTICE $rnick :\001$type $reply\001");
|
||||
}
|
||||
|
||||
1;
|
@ -0,0 +1,42 @@
|
||||
# Channel specific data, based heavily on User.pl
|
||||
#
|
||||
# Simon Cozens, for infobot (C) Kevin Lenzo 1997
|
||||
#
|
||||
|
||||
sub parseChannelfile {
|
||||
$file = $param{'confdir'}.$filesep.$param{'channelList'};
|
||||
%chanopts = ();
|
||||
|
||||
open(FH, $file) or return; # Oz, you didn't check a retval. :P
|
||||
while (<FH>) {
|
||||
next unless (!/^#/ && defined $_);
|
||||
if (/^ChannelEntry\s+(.+?)\s/) {
|
||||
$workname = $1;
|
||||
if (/\s*\{\s*/) {
|
||||
while (<FH>) {
|
||||
if (/^\s*(\w+)\s+(.+);$/) {
|
||||
$opt = $1; $val = $2;
|
||||
$val =~ s/\"//g;
|
||||
$opt =~ tr/A-Z/a-z/;
|
||||
$chanopts{$workname}->{$opt} = $val;
|
||||
} elsif (/^\s*\}\s*$/) {
|
||||
last;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
status("parse error: Channel Entry $workname without right brace");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub getparam {
|
||||
my $optname = shift;
|
||||
my $chan = channel();
|
||||
return $param{$optname} if ($msgType =~ /private/);
|
||||
return $chanopts{$chan}->{$optname}
|
||||
if defined $chanopts{$chan}->{$optname};
|
||||
return $param{$optname};
|
||||
}
|
||||
|
||||
"false";
|
@ -0,0 +1,743 @@
|
||||
# $Id: DBM.pl,v 1.7 2000/12/09 22:58:27 lenzo Exp $
|
||||
#
|
||||
# infobot :: Kevin Lenzo (c) 1997
|
||||
|
||||
use strict;
|
||||
|
||||
package Infobot::DBM;
|
||||
|
||||
=head1 NAME
|
||||
|
||||
DBM.pl - infobot's interface to on-disk databases
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
openDBMx 'mydb', fatal => 1; # more switches listed below
|
||||
|
||||
$val = get 'mydb', $key; # get value
|
||||
|
||||
set 'mydb', $key, $val; # set value
|
||||
$prev_val = postInc 'mydb', $key; # increment, return old value
|
||||
$prev_val = postDec 'mydb', $key; # decrement, return old value
|
||||
|
||||
@keys = getDBMKeys 'mydb'; # get all keys
|
||||
clear 'mydb', $key; # delete key
|
||||
clearAll 'mydb'; # delete all keys
|
||||
insertFile 'mydb', $filename; # load space-separated fields
|
||||
closeDBM 'mydb'; # close this db
|
||||
closeDBMAll; # close all dbs
|
||||
syncDBM 'mydb'; # flush changes to disk
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
These functions provide B<infobot>'s interface to on-disk databases.
|
||||
|
||||
=cut
|
||||
|
||||
BEGIN { push @INC, 'src' } # baad, bad juju here
|
||||
|
||||
use vars qw(%DBMS $Debug $Init_done $Old_warnings);
|
||||
|
||||
use Fcntl qw(
|
||||
:flock
|
||||
O_CREAT
|
||||
O_RDWR
|
||||
);
|
||||
|
||||
use Symbol qw(
|
||||
gensym
|
||||
);
|
||||
|
||||
use Util qw(
|
||||
export_to_main
|
||||
import_from_main
|
||||
process_args
|
||||
);
|
||||
|
||||
BEGIN {
|
||||
if (!$Init_done) {
|
||||
$Old_warnings = $^W;
|
||||
$^W = 1;
|
||||
}
|
||||
}
|
||||
|
||||
my @Import;
|
||||
my @Export;
|
||||
|
||||
BEGIN {
|
||||
@Import = qw(
|
||||
$filesep
|
||||
%param
|
||||
status
|
||||
);
|
||||
|
||||
@Export = qw(
|
||||
clear
|
||||
clearAll
|
||||
closeDBM
|
||||
closeDBMAll
|
||||
forget
|
||||
get
|
||||
getDBMKeys
|
||||
insertFile
|
||||
openDBM
|
||||
openDBMx
|
||||
postDec
|
||||
postInc
|
||||
set
|
||||
showdb
|
||||
syncDBM
|
||||
whatdbs
|
||||
);
|
||||
|
||||
export_to_main @Export;
|
||||
import_from_main @Import;
|
||||
}
|
||||
|
||||
use subs grep /^\w/, @Export;
|
||||
use vars grep /^\W/, @Import, @Export;
|
||||
|
||||
use subs qw(_open);
|
||||
|
||||
# %DBMS maps from the user's database name to an array of data about each
|
||||
# db. The referenced array is indexed by the following constant subs.
|
||||
|
||||
%DBMS = () unless $Init_done;
|
||||
|
||||
sub F_DBNAME () { 0 } # %DBMS key
|
||||
sub F_HASH () { 1 } # reference to the tied hash
|
||||
sub F_FILE () { 2 } # name of file opened
|
||||
sub F_LOCKING () { 3 } # true if locking is enabled for this db
|
||||
sub F_LOCK_FH () { 4 } # filehandle used for locking
|
||||
sub F_LOCK_STAT () { 5 } # current LOCK_* status
|
||||
sub F_MODULE () { 6 } # database module used
|
||||
sub F_SYNC_SUB () { 7 } # cached sync() method
|
||||
sub F_INITFILE () { 8 } # initial contents when creating
|
||||
sub F_UPDATE_COUNT () { 9 } # number of updates since last sync
|
||||
|
||||
$Debug = 0 unless $Init_done;
|
||||
|
||||
=head1 CONFIGURATION SETTINGS
|
||||
|
||||
=over 4
|
||||
|
||||
=item DBMModule
|
||||
|
||||
Setting C<DBMModule> lets you explicitly specify the DBM backend which
|
||||
you'd like to use. Standard values for this are C<NDBM_File>, C<DB_File>,
|
||||
C<GDBM_File>, C<SDBM_File>, and C<ODBM_File>, but anything which provides
|
||||
a tied hash interface should work. If you don't specify this the default
|
||||
will generally be the first of these which is present on your system.
|
||||
|
||||
Eg:
|
||||
|
||||
DBMModule DB_File
|
||||
|
||||
=item DBMExt
|
||||
|
||||
This is appened to the file names passed to DBM open. This can be
|
||||
useful for DBM modules which don't modify the file name passed to them,
|
||||
such as DB_File and GDBM_File. For example,
|
||||
|
||||
DBMExt .db
|
||||
|
||||
will provide traditional naming for DB_File databases.
|
||||
|
||||
=item sharedDBMs
|
||||
|
||||
This provides support for sharing database files among multiple B<infobot>s
|
||||
on the same machine by using locking. NB: Using any sharedDBMs currently
|
||||
requires that you set C<DBMModule> to C<DB_File>, as none of the other DBM
|
||||
modules provides the required support.
|
||||
|
||||
Eg, if you said
|
||||
|
||||
sharedDBMs is are plusplus
|
||||
|
||||
your infobot would use locking when accessing the main factoid databases
|
||||
and the C<karma> database, but not, say, the C<seen> database. You can
|
||||
have multiple infobots accessing the same databases for which they all
|
||||
use locking. It's up to you to make sure that all the bots which access
|
||||
a particular file use locking for it, if you screw that up the rogue
|
||||
will end up corrupting your database.
|
||||
|
||||
There are two special values:
|
||||
|
||||
sharedDBMs /all
|
||||
sharedDBMs /all-but-ignore
|
||||
|
||||
These set up locking for everything, and for everything but the
|
||||
C<ignore> database (which is used more than any other, so perhaps
|
||||
it's a good candidate for such special treatment).
|
||||
|
||||
=item commitDBM
|
||||
|
||||
This setting controls how often changes to the database are flushed to
|
||||
disk. Normally this isn't done manually, so it will depend on how the
|
||||
DBM module you're using behaves. If you set C<commitDBM> to a number,
|
||||
changes will be forced to disk every that many updates (so use 1 to
|
||||
force a sync after every update).
|
||||
|
||||
=back
|
||||
|
||||
=cut
|
||||
|
||||
unless ($Init_done) {
|
||||
$param{DBMModule} = 'AnyDBM_File';
|
||||
$param{DBMExt} = '';
|
||||
$param{sharedDBMs} = '';
|
||||
$param{commitDBM} = 0;
|
||||
}
|
||||
|
||||
=head1 INTERFACE FUNCTIONS
|
||||
|
||||
=over 4
|
||||
|
||||
=item opemDBMx I<dbname>, [I<arg> => I<val>]...
|
||||
|
||||
This function opens up a database. The I<dbname> is the name you'll use
|
||||
to refer to it with all the other functions. The normal practice is to
|
||||
supply only the I<dbname>, most of the other arguments have reasonable
|
||||
(preferred, even) defaults. openDBMx() returns true if the database was
|
||||
opened successfully, false otherwise, unless you've set C<fatal> to a
|
||||
true value.
|
||||
|
||||
Arguments are:
|
||||
|
||||
fatal => $boolean
|
||||
|
||||
This boolean, which is off by default, tells openDBMx() to
|
||||
die() rather than returning false if the database can't be
|
||||
successfully opened.
|
||||
|
||||
tag => $tag
|
||||
|
||||
This defaults to the I<dbname> you gave. That's normally what
|
||||
you want, it'd be unusual to specify the tag manually. The tag
|
||||
is what's actually used to look up the other values in %param.
|
||||
|
||||
file => $filename
|
||||
|
||||
This allows you to override the name of database file (though
|
||||
the user's C<DBMExt> is still appended). Normally you wouldn't
|
||||
specify this, and the value the user specifies in $param{$tag}
|
||||
is used.
|
||||
|
||||
initfile => $filename
|
||||
|
||||
When a database is created the code uses insertFile() to load a
|
||||
file called F<$misc_dir/infobot-$tag.txt> into it. You can
|
||||
override the name of the file used by specifying it with this
|
||||
argument.
|
||||
|
||||
locking => $boolean
|
||||
|
||||
This boolean tells the code whether to use locking or not.
|
||||
Normally you wouldn't specify it and the user's C<sharedDBMs>
|
||||
setting would dictate that.
|
||||
|
||||
module => $db_module
|
||||
|
||||
This allows you to override the user's C<DBMModule> for this database.
|
||||
|
||||
=cut
|
||||
|
||||
sub openDBMx {
|
||||
my ($dbname, @arg) = @_;
|
||||
my ($fatal, $file, $initfile, $tag, $locking, $module);
|
||||
|
||||
my $fail = sub {
|
||||
my $s = join '', @_;
|
||||
status $s;
|
||||
die $s if $fatal;
|
||||
return 0;
|
||||
};
|
||||
|
||||
process_args \@arg,
|
||||
fatal => \$fatal,
|
||||
file => \$file,
|
||||
locking => \$locking,
|
||||
initfile => \$initfile,
|
||||
module => \$module,
|
||||
tag => \$tag
|
||||
or return;
|
||||
|
||||
$tag ||= $dbname;
|
||||
|
||||
if (!defined $file) {
|
||||
my $base = $param{$tag};
|
||||
if (!defined $base) {
|
||||
return $fail->("$tag not specified in config file"
|
||||
. " and no default supplied");
|
||||
}
|
||||
$file = $param{basedir} . $filesep . $base;
|
||||
}
|
||||
$file .= $param{DBMExt};
|
||||
|
||||
$initfile = $param{confdir} . $filesep . "infobot-$tag.txt"
|
||||
if !defined $initfile;
|
||||
$locking = $param{sharedDBMs} eq '/all'
|
||||
|| ($tag ne 'ignore'
|
||||
&& $param{sharedDBMs} eq '/all-but-ignore')
|
||||
|| grep { $_ eq $tag } split ' ', $param{sharedDBMs}
|
||||
if !defined $locking;
|
||||
$module = $param{DBMModule} if !defined $module;
|
||||
|
||||
if ($locking) {
|
||||
if ($module ne 'DB_File') {
|
||||
die "Locking is specified for the $tag database, but ",
|
||||
"DBMModule isn't DB_File (it's $module)";
|
||||
}
|
||||
}
|
||||
|
||||
eval "require $module";
|
||||
if ($@) {
|
||||
chomp $@;
|
||||
die "Invalid DBMModule setting `$module' ($@)\n";
|
||||
}
|
||||
|
||||
if ($DBMS{$dbname}) {
|
||||
status "$file replaces $DBMS{$dbname}[F_FILE]"
|
||||
unless $file eq $DBMS{$dbname}[F_FILE];
|
||||
}
|
||||
|
||||
my $rdb = $DBMS{$dbname} ||= [];
|
||||
$rdb->[F_DBNAME] = $dbname;
|
||||
$rdb->[F_FILE] = $file;
|
||||
$rdb->[F_LOCKING] = $locking;
|
||||
$rdb->[F_MODULE] = $module;
|
||||
$rdb->[F_INITFILE] = $initfile;
|
||||
|
||||
_open $rdb
|
||||
or return $fail->($@);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Perform the actual open on the given db record. Return true is
|
||||
# successful, else false and set $@ to an explanation.
|
||||
|
||||
sub _open {
|
||||
my ($rdb) = @_;
|
||||
my ($created);
|
||||
|
||||
my $dbname = $rdb->[F_DBNAME];
|
||||
my $file = $rdb->[F_FILE];
|
||||
my $locking = $rdb->[F_LOCKING];
|
||||
my $module = $rdb->[F_MODULE];
|
||||
|
||||
my $with_locking = $locking ? ' (with locking)' : '';
|
||||
if (tie %{ $rdb->[F_HASH] }, $module, $file, O_RDWR, 0) {
|
||||
status "opened $dbname -> $file$with_locking";
|
||||
} elsif (tie %{ $rdb->[F_HASH] }, $module, $file, O_CREAT | O_RDWR, 0666) {
|
||||
status "created new db $dbname -> $file$with_locking";
|
||||
$created = 1;
|
||||
} else {
|
||||
$@ = "failed to open $dbname -> $file";
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ($locking) {
|
||||
my $fh = $rdb->[F_LOCK_FH] = gensym;
|
||||
my $fd = tied(%{ $rdb->[F_HASH] })->fd;
|
||||
if (!open $fh, "+<&=$fd") {
|
||||
delete $DBMS{$dbname};
|
||||
$@ = "can't fdopen fd $fd to provide locking for $dbname";
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
$rdb->[F_LOCK_STAT] = LOCK_UN;
|
||||
$rdb->[F_UPDATE_COUNT] = 0;
|
||||
|
||||
# Wait until after the locking FH is set up to do the inserts.
|
||||
insertFile $dbname, $rdb->[F_INITFILE]
|
||||
if $created;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub _close_open {
|
||||
my ($dbname) = @_;
|
||||
my ($fail_reason);
|
||||
|
||||
closeDBM '_no_delete', $dbname;
|
||||
|
||||
# The old (commented-out) code for this would sleep and retry if the
|
||||
# reopen failed. It seems bogus to me, but I don't want to piss
|
||||
# anybody off by removing it.
|
||||
|
||||
for (1..10) {
|
||||
return 1 if _open $DBMS{$dbname};
|
||||
} continue {
|
||||
status "Error re-opening $dbname ($@), sleeping";
|
||||
sleep 1;
|
||||
}
|
||||
status "Error re-opening $dbname ($@), giving up";
|
||||
return 0;
|
||||
}
|
||||
|
||||
=item openDBM $dbname => $file, ...
|
||||
|
||||
This is the old interface to opening databases. It's equivalent to
|
||||
running
|
||||
|
||||
openDBMx $dbname, file => $file;
|
||||
|
||||
for each pair of arguments. The return value is true if all the opens
|
||||
succeeded.
|
||||
|
||||
=cut
|
||||
|
||||
sub openDBM {
|
||||
my %arg = @_;
|
||||
my ($dbname, $file, $fail);
|
||||
|
||||
while (($dbname, $file) = each %arg) {
|
||||
next unless $dbname =~ /\S/;
|
||||
openDBMx $dbname, file => $file
|
||||
or $fail = 1;
|
||||
}
|
||||
|
||||
return !$fail;
|
||||
}
|
||||
|
||||
=item syncDBM $dbname
|
||||
|
||||
Flush to disk any unwritten changes to the database.
|
||||
|
||||
=cut
|
||||
|
||||
sub syncDBM {
|
||||
my ($dbname) = @_;
|
||||
my $rdb = $DBMS{$dbname};
|
||||
|
||||
print "sync $rdb->[F_DBNAME]\n" if $Debug;
|
||||
$rdb->[F_UPDATE_COUNT] = 0;
|
||||
&{ $rdb->[F_SYNC_SUB] ||= do {
|
||||
if (tied(%{ $rdb->[F_HASH] })->can('sync')) {
|
||||
print "syncDBM: $dbname using ->sync\n" if $Debug;
|
||||
sub { tied(%{ $rdb->[F_HASH] })->sync }
|
||||
}
|
||||
else {
|
||||
print "syncDBM: $dbname using reopen\n" if $Debug;
|
||||
sub { _close_open $dbname }
|
||||
}
|
||||
}
|
||||
}();
|
||||
}
|
||||
|
||||
sub lock {
|
||||
my ($rdb, $bits) = @_;
|
||||
|
||||
my $have = $rdb->[F_LOCK_STAT];
|
||||
my $want = $bits - ($bits & LOCK_NB);
|
||||
|
||||
printf "lock db %-8s fd %2s have $have want $want bits $bits\n",
|
||||
$rdb->[F_DBNAME],
|
||||
$rdb->[F_LOCKING] ? fileno $rdb->[F_LOCK_FH] : '-',
|
||||
if $Debug;
|
||||
|
||||
return if $have == $want;
|
||||
|
||||
# Possibly flush when unlocking (or downgrading LOCK_EX to LOCK_SH).
|
||||
if ($have == LOCK_EX) {
|
||||
$rdb->[F_UPDATE_COUNT]++;
|
||||
if ($rdb->[F_LOCKING]
|
||||
|| $param{commitDBM} eq 'ALWAYS' # grandfather
|
||||
|| ($param{commitDBM} > 0 &&
|
||||
$rdb->[F_UPDATE_COUNT] >= $param{commitDBM})) {
|
||||
syncDBM $rdb->[F_DBNAME];
|
||||
}
|
||||
}
|
||||
|
||||
flock $rdb->[F_LOCK_FH], $bits or die "Can't lock $rdb->[F_FILE]: $!\n"
|
||||
if $rdb->[F_LOCKING];
|
||||
$rdb->[F_LOCK_STAT] = $want;
|
||||
}
|
||||
|
||||
=item insertFile $dbname, $filename
|
||||
|
||||
This loads the given file into the database. Input lines look like
|
||||
|
||||
key => value
|
||||
|
||||
(spaces around the C<=E<gt>> are optional).
|
||||
|
||||
=cut
|
||||
|
||||
sub insertFile {
|
||||
my ($dbname, $factfile) = @_;
|
||||
my $rdb = $DBMS{$dbname};
|
||||
|
||||
if (open(IN, $factfile)) {
|
||||
my ($good, $total);
|
||||
|
||||
lock $rdb, LOCK_EX;
|
||||
while(<IN>) {
|
||||
chomp;
|
||||
my ($k, $v) = split(/\s*=>\s*/, $_, 2);
|
||||
if ($k and $v) {
|
||||
$rdb->[F_HASH]{$k} = $v;
|
||||
$good++;
|
||||
}
|
||||
$total++;
|
||||
}
|
||||
lock $rdb, LOCK_UN;
|
||||
close(IN);
|
||||
status "loaded $factfile into $dbname ($good/$total good items)";
|
||||
} else {
|
||||
status "FAILED to load $factfile into $dbname";
|
||||
}
|
||||
}
|
||||
|
||||
=item closeDBM $dbname
|
||||
|
||||
Close the database.
|
||||
|
||||
=cut
|
||||
|
||||
sub closeDBM {
|
||||
if (@_) {
|
||||
my ($dbname, $rdb, $no_delete);
|
||||
$no_delete = shift if $_[0] eq '_no_delete';
|
||||
foreach $dbname (@_) {
|
||||
my $rdb = $DBMS{$dbname};
|
||||
delete $DBMS{$dbname} unless $no_delete;
|
||||
status untie(%{ $rdb->[F_HASH] })
|
||||
? "closed db $dbname"
|
||||
: "Error closing db $dbname ($!)";
|
||||
}
|
||||
} else {
|
||||
status "No dbs specified; none closed";
|
||||
}
|
||||
}
|
||||
|
||||
=item closeDBMAll
|
||||
|
||||
Close all databases.
|
||||
|
||||
=cut
|
||||
|
||||
sub closeDBMAll {
|
||||
closeDBM keys %DBMS;
|
||||
}
|
||||
|
||||
=item set $dbname, $key, $val
|
||||
|
||||
Set a key/value pair in the database.
|
||||
|
||||
=cut
|
||||
|
||||
sub set {
|
||||
my ($dbname, $key, $val, $no_locking) = @_;
|
||||
|
||||
if (!$key) {
|
||||
($dbname, $key, $val) = split(/\s+/, $dbname);
|
||||
}
|
||||
|
||||
# this is a hack to keep set param consistant.. overloaded
|
||||
if ($dbname eq 'param') {
|
||||
my $was = $param{$key};
|
||||
$param{$key} = $val;
|
||||
return $was;
|
||||
}
|
||||
|
||||
if (!$key) {
|
||||
return 'NULLKEY';
|
||||
}
|
||||
|
||||
my $rdb = $DBMS{$dbname};
|
||||
my $rhash = $rdb->[F_HASH];
|
||||
lock $rdb, LOCK_EX unless $no_locking;
|
||||
my $was = $rhash->{$key};
|
||||
$rhash->{$key} = $val;
|
||||
lock $rdb, LOCK_UN unless $no_locking;
|
||||
|
||||
return $was;
|
||||
}
|
||||
|
||||
=item get $dbname, $key
|
||||
|
||||
Return the value corresponding to the $key in the database.
|
||||
|
||||
=cut
|
||||
|
||||
sub get {
|
||||
my ($dbname, $key, $no_locking) =@_;
|
||||
|
||||
if (!$key) {
|
||||
($dbname, $key) = split(/\s+/, $dbname);
|
||||
}
|
||||
|
||||
my $rdb = $DBMS{$dbname};
|
||||
lock $rdb, LOCK_SH unless $no_locking;
|
||||
my $val = $rdb->[F_HASH]{$key};
|
||||
lock $rdb, LOCK_UN unless $no_locking;
|
||||
return $val;
|
||||
}
|
||||
|
||||
=item postInc $dbname, $key
|
||||
|
||||
Increment the value of $key in the database, return the old value.
|
||||
|
||||
=cut
|
||||
|
||||
sub postInc {
|
||||
my ($dbname, $key) = @_;
|
||||
|
||||
my $rdb = $DBMS{$dbname};
|
||||
lock $rdb, LOCK_EX;
|
||||
set $dbname, $key, 1 + get($dbname, $key, 1), 1;
|
||||
lock $rdb, LOCK_UN;
|
||||
}
|
||||
|
||||
=item postDec $dbname, $key
|
||||
|
||||
Decrement the value of $key in the database, return the old value.
|
||||
|
||||
=cut
|
||||
|
||||
sub postDec {
|
||||
my ($dbname, $key) = @_;
|
||||
|
||||
my $rdb = $DBMS{$dbname};
|
||||
lock $rdb, LOCK_EX;
|
||||
set $dbname, $key, -1 + get($dbname, $key, 1), 1;
|
||||
lock $rdb, LOCK_UN;
|
||||
}
|
||||
|
||||
sub whatdbs {
|
||||
my @result;
|
||||
foreach (keys %DBMS) {
|
||||
push @result, "$_ => $DBMS{$_}[F_FILE]";
|
||||
}
|
||||
return @result;
|
||||
}
|
||||
|
||||
sub showdb {
|
||||
my ($dbname, $regex) = @_;
|
||||
my @result;
|
||||
|
||||
if (!$regex) {
|
||||
($dbname, $regex) = split(/\s+/, $dbname, 2);
|
||||
}
|
||||
|
||||
my @whichdbs;
|
||||
|
||||
if (!$dbname) {
|
||||
status "no db given";
|
||||
status "try showdb <db> <regex>";
|
||||
# @whichdbs = (keys %DBMS);
|
||||
} else {
|
||||
@whichdbs = ($dbname);
|
||||
}
|
||||
|
||||
foreach $dbname (@whichdbs) {
|
||||
my $rdb = $DBMS{$dbname};
|
||||
if (!$rdb) {
|
||||
status "the database $dbname is not open.";
|
||||
status "try showdb <db> <regex>";
|
||||
return();
|
||||
}
|
||||
lock $rdb, LOCK_SH;
|
||||
my $rhash = $rdb->[F_HASH];
|
||||
my ($key, $val);
|
||||
if (!$regex) {
|
||||
status "showing all of $dbname";
|
||||
while (($key, $val) = each %$rhash) {
|
||||
push @result, "$key => $val";
|
||||
}
|
||||
} else {
|
||||
status "searching $dbname for /$regex/";
|
||||
while (($key, $val) = each %$rhash) {
|
||||
push @result, "$key => $val"
|
||||
if $key =~ /$regex/ || $val =~ /$regex/;
|
||||
}
|
||||
}
|
||||
lock $rdb, LOCK_UN;
|
||||
}
|
||||
|
||||
return @result;
|
||||
}
|
||||
|
||||
sub forget {
|
||||
clear @_;
|
||||
return '';
|
||||
}
|
||||
|
||||
=item clear $dbname, $key
|
||||
|
||||
Delete a key from the database.
|
||||
|
||||
=cut
|
||||
|
||||
sub clear {
|
||||
my ($dbname, $key) =@_;
|
||||
|
||||
if (!$key) {
|
||||
($dbname, $key) = split(/\s+/, $dbname);
|
||||
}
|
||||
|
||||
my $rdb = $DBMS{$dbname};
|
||||
lock $rdb, LOCK_EX;
|
||||
my $was = get $dbname, $key, 1;
|
||||
|
||||
print "DELETING $dbname $key\n";
|
||||
delete $DBMS{$dbname}[F_HASH]{$key};
|
||||
print "DELETED\n";
|
||||
|
||||
lock $rdb, LOCK_UN;
|
||||
return $was;
|
||||
}
|
||||
|
||||
=item clearAll $dbname
|
||||
|
||||
Empty the database.
|
||||
|
||||
=cut
|
||||
|
||||
sub clearAll {
|
||||
my ($dbname) = @_;
|
||||
|
||||
my $rdb = $DBMS{$dbname};
|
||||
lock $rdb, LOCK_EX;
|
||||
%{ $rdb->[F_HASH] } = ();
|
||||
lock $rdb, LOCK_UN;
|
||||
}
|
||||
|
||||
=item getDBMKeys $dbname
|
||||
|
||||
Return all the keys in the database.
|
||||
|
||||
=cut
|
||||
|
||||
sub getDBMKeys {
|
||||
my ($dbname) = @_;
|
||||
|
||||
my $rdb = $DBMS{$dbname};
|
||||
lock $rdb, LOCK_SH;
|
||||
my @k = keys %{ $rdb->[F_HASH] };
|
||||
lock $rdb, LOCK_UN;
|
||||
return @k;
|
||||
}
|
||||
|
||||
if (!$Init_done) {
|
||||
$^W = $Old_warnings;
|
||||
$Init_done = 1;
|
||||
}
|
||||
|
||||
1
|
||||
|
||||
__END__
|
||||
|
||||
=back
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Kevin Lenzo, expanded by Roderick Schertler <F<roderick@argon.org>>
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
infobot(1), perl(1).
|
||||
|
||||
=cut
|
@ -0,0 +1,60 @@
|
||||
|
||||
# infobot :: Kevin Lenzo (c) 1997
|
||||
|
||||
sub setup_help {
|
||||
$filesep ||= '/';
|
||||
if (!exists $param{'helpfile'}) {
|
||||
$param{'helpfile'} = "$infobot.help"; # murrayb++
|
||||
}
|
||||
|
||||
if (open (HELP, "$param{confdir}/$param{helpfile}")) {
|
||||
undef %help;
|
||||
while ($help = <HELP>) {
|
||||
$help =~ s/\#.*//;
|
||||
chomp $help;
|
||||
next unless $help;
|
||||
($key, $val) = split(/:/, $help, 2);
|
||||
if (!$help{$key}) {
|
||||
$helptopics .= "$key ";
|
||||
}
|
||||
if ($help{$key}) {
|
||||
$help{$key} .= $val."\n";
|
||||
} else {
|
||||
$help{$key} = $val."\n";
|
||||
}
|
||||
}
|
||||
$helptopics =~ s/\s+$//;
|
||||
&status("Loaded help file $param{helpfile}");
|
||||
} else {
|
||||
$help{"main"} = "couldn't find the help file";
|
||||
&status("No help file $param{helpfile}");
|
||||
}
|
||||
}
|
||||
|
||||
sub help {
|
||||
my $topic = $_[0];
|
||||
|
||||
if ($topic =~ /^\s*$/) {
|
||||
$topic = "main";
|
||||
}
|
||||
|
||||
$topic =~ s/^\s*//;
|
||||
$topic =~ s/\s*$//;
|
||||
$topic =~ s/\s+/ /;
|
||||
$topic =~ tr/A-Z/a-z/;
|
||||
|
||||
if ($help{$topic}) {
|
||||
foreach (split(/\n/, $help{$topic})) {
|
||||
&msg($who,$_);
|
||||
}
|
||||
} else {
|
||||
&msg($who, "no help on $topic");
|
||||
}
|
||||
|
||||
&msg($who, 'topics: '.$helptopics.". use 'help <topic>'.");
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
|
||||
1;
|
@ -0,0 +1,475 @@
|
||||
# infobot :: Kevin Lenzo & Patrick Cole (c) 1997
|
||||
|
||||
use Socket;
|
||||
|
||||
sub srvConnect {
|
||||
my ($server, $port) = @_;
|
||||
my ($iaddr, $paddr, $proto);
|
||||
select(STDOUT);
|
||||
$| = 1;
|
||||
|
||||
$iaddr = inet_aton($server);
|
||||
$ip_num = inet_ntoa($iaddr);
|
||||
if (not $ip_num) {
|
||||
die "can't get the address of $server ($ip_num)!\n";
|
||||
}
|
||||
&status("Connecting to port $port of server $server ($ip_num)...");
|
||||
$paddr = sockaddr_in($port, $iaddr);
|
||||
$proto = getprotobyname('tcp');
|
||||
socket(SOCK, PF_INET, SOCK_STREAM, $proto) or die "socket failed: $!";
|
||||
$sockaddr = 'S n a4 x8';
|
||||
if ($param{'vhost_name'}) {
|
||||
my $hostname = $param{'vhost_name'};
|
||||
$this = pack($sockaddr, AF_INET, 0, inet_aton($hostname));
|
||||
&status("trying to bind as $hostname");
|
||||
bind(SOCK, $this) || die "bind: $!";
|
||||
}
|
||||
connect(SOCK, $paddr) or die "connect failed: $!";
|
||||
|
||||
&status(" connected.");
|
||||
}
|
||||
|
||||
sub procservmode {
|
||||
my ($server, $e, $f) = @_;
|
||||
my @parts = split (/ /, $f);
|
||||
$cnt=0;
|
||||
my $mode="";
|
||||
my $chan="";
|
||||
foreach (@parts) {
|
||||
if ($cnt == 0) {
|
||||
$chan = $_;
|
||||
} else {
|
||||
$mode .= $_;
|
||||
$mode .= " ";
|
||||
}
|
||||
++$cnt;
|
||||
}
|
||||
chop $mode;
|
||||
$mode=~s/://;
|
||||
|
||||
if ($server eq $chan) {
|
||||
if ($params{ansi_control}) {
|
||||
&status(">>> $b$server$ob sets user mode: $b$mode$ob");
|
||||
} else {
|
||||
&status(">>> $server sets mode: $mode");
|
||||
}
|
||||
|
||||
} else {
|
||||
if ($params{ansi_control}) {
|
||||
&status(">>> $b$server$ob/$b$chan$ob sets server mode: $b$mode$ob");
|
||||
} else {
|
||||
&status(">>> $server/$chan sets mode: $mode");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
### added by the xk.
|
||||
# Usage: &nickServ(text);
|
||||
sub nickServ {
|
||||
my $text = shift;
|
||||
return if !defined $param{'nickServ_pass'};
|
||||
|
||||
&status("NickServ: <= '$text'");
|
||||
|
||||
if ($text =~ /Password incorrect/i) {
|
||||
&status("NickServ: ** identify failed.");
|
||||
return;
|
||||
}
|
||||
|
||||
if ($text =~ /Password accepted/i) {
|
||||
&status("NickServ: ** identify success.");
|
||||
return;
|
||||
}
|
||||
|
||||
if ($nickserv_try) { return; }
|
||||
|
||||
&status("NickServ: => Identifying to NickServ.");
|
||||
rawout("PRIVMSG NickServ :IDENTIFY $param{'nickServ_pass'}");
|
||||
$nickserv_try++;
|
||||
}
|
||||
|
||||
###
|
||||
# Usage: &chanServ(text);
|
||||
sub chanServ {
|
||||
my $text = shift;
|
||||
# return if !defined $param{'chanServ_ops'};
|
||||
&status("chanServ_ops => '$param{'chanServ_ops'}'.");
|
||||
|
||||
&status("ChanServ: <= '$text'");
|
||||
|
||||
# to be continued...
|
||||
return;
|
||||
}
|
||||
# end of xk functions.
|
||||
|
||||
sub procmode {
|
||||
my ($nick, $user, $host, $e, $f) = @_;
|
||||
my @parts = split (/ /, $f);
|
||||
$cnt=0;
|
||||
my $mode="";
|
||||
my $chan="";
|
||||
foreach (@parts) {
|
||||
if ($cnt == 0) {
|
||||
$chan = $_;
|
||||
} else {
|
||||
$mode .= $_;
|
||||
$mode .= " ";
|
||||
}
|
||||
++$cnt;
|
||||
}
|
||||
$mode =~ s/\s$//;
|
||||
|
||||
|
||||
if ($param{ansi_control}) {
|
||||
&status(">>> mode/$b$chan$ob [$b$mode$ob] by $b$nick$ob");
|
||||
} else {
|
||||
&status(">>> mode/$chan [$mode] by $nick");
|
||||
}
|
||||
|
||||
if ($chan =~ /^[\#\&]/) {
|
||||
my ($modes, $targets) = ($mode =~ /^(\S+)\s+(.*)/);
|
||||
my @m = ($modes =~ /([+-]*\w)/g);
|
||||
my @t = split /\s+/, $targets;
|
||||
if (@m != @t) {
|
||||
&status("number of modes does not match number of targets: @m / @t");
|
||||
} else {
|
||||
my $parity = 0;
|
||||
foreach (0..$#m) {
|
||||
if ($m[$_] =~ s/^([-+])//) {
|
||||
$sign = $1;
|
||||
if ($sign eq '-') {
|
||||
$parity = -1;
|
||||
} else {
|
||||
$parity = 1;
|
||||
}
|
||||
}
|
||||
if ($parity == 0) {
|
||||
&status("zero parity mode change... ignored");
|
||||
} else {
|
||||
if ($parity > 0) {
|
||||
$channels{$chan}{$m}{$t} = '+';
|
||||
} else {
|
||||
delete $channels{$chan}{$mode}{$t};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub entryEvt {
|
||||
my ($nick, $user, $host, $type, $chan) = @_;
|
||||
if ($type=~/PART/) {
|
||||
if ($param{ansi_control}) {
|
||||
&status(">>> $nick ($user\@$host) has left $chan");
|
||||
} else {
|
||||
&status(">>> $nick ($user\@$host) has left $chan");
|
||||
}
|
||||
} elsif ($type=~/JOIN/) {
|
||||
if ($netsplit) {
|
||||
foreach (keys(%snick)) {
|
||||
if ($nick eq $snick{$_}) {
|
||||
@be = split (/ /);
|
||||
if ($param{ansi_control}) {
|
||||
&status(">>> ${b}Netjoined$ob: $be[0] $be[1]");
|
||||
} else {
|
||||
&status(">>> ${b}Netjoined$ob: $be[0] $be[1]");
|
||||
}
|
||||
$netsplit--;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($param{ansi_control}) {
|
||||
&status(">>> $nick ($user\@$host) has joined $chan");
|
||||
} else {
|
||||
&status(">>> $nick ($user\@$host) has joined $chan");
|
||||
}
|
||||
} elsif ($type=~/QUIT/) {
|
||||
$chan=~s/\r//;
|
||||
if ($chan=~/^([\d\w\_\-\/]+\.[\.\d\w\_\-\/]+)\s([\d\w\_\-\/]+\.[\.\d\w\_\-\/]+)$/) {
|
||||
$i=0;
|
||||
while (0 and ($i < $netsplit || !$netsplit)) {
|
||||
# while ($i < $netsplit || !$netsplit) {
|
||||
$i++;
|
||||
if (($prevsplit1{$i} ne $2) && ($prevsplit2{$i} ne $1)) {
|
||||
&status("Netsplit: $2 split from $1");
|
||||
$netsplit++;
|
||||
$prevsplit1{$netsplit} = $2;
|
||||
$prevsplit2{$netsplit} = $1;
|
||||
$snick{"$2 $1"}=$nick;
|
||||
$schan{"$2 $1"}=$chan;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ($param{ansi_control}) {
|
||||
&status(">>> $b$nick$ob has signed off IRC ($b$chan$ob)");
|
||||
} else {
|
||||
&status(">>> $b$nick$ob has signed off IRC ($b$chan$ob)");
|
||||
}
|
||||
}
|
||||
} elsif ($type=~/NICK/) {
|
||||
if ($param{ansi_control}) {
|
||||
&status(">>> ".c($nick,'bold green').
|
||||
" materializes into ".c($chan,'bold green'));
|
||||
} else {
|
||||
&status(">>> $b$nick$ob materializes into $b$chan$ob");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub procevent {
|
||||
my ($nick, $user, $host, $type, $chan, $msg) = @_;
|
||||
|
||||
# support global $nuh, $who
|
||||
$nuh = "$nick!$user\@$host";
|
||||
|
||||
if ($type=~/PRIVMSG/) {
|
||||
if ($chan =~ /^$ischan/) {
|
||||
## It's a public message on the channel##
|
||||
$chan =~ tr/A-Z/a-z/;
|
||||
|
||||
if ($msg =~ /\001(.*)\001/ && $msg !~ /ACTION/) {
|
||||
#### Client To Client Protocol ####
|
||||
parsectcp($nick, $user, $host, $1, $chan);
|
||||
} elsif ($msg !~ /ACTION\s(.+)/) {
|
||||
#### Public Channel Message ####
|
||||
&IrcMsgHook('public', $chan, $nick, $msg);
|
||||
} else {
|
||||
#### Public Action ####
|
||||
&IrcActionHook($nick, $chan, $1);
|
||||
}
|
||||
} else {
|
||||
## Is Private ##
|
||||
if ($msg=~/\001(.*)\001/) {
|
||||
#### Client To Client Protocol ####
|
||||
parsectcp($nick, $user, $host, $1, $chan);
|
||||
} else {
|
||||
#### Is a Private Message ##
|
||||
&IrcMsgHook('private', $chan, $nick, $msg);
|
||||
}
|
||||
}
|
||||
} elsif ($type=~/NOTICE/) {
|
||||
if ($chan =~ /^$ischan/) {
|
||||
$chan =~ tr/A-Z/a-z/;
|
||||
if ($msg !~ /ACTION (.*)/) {
|
||||
&status("-$nick/$chan- $msg");
|
||||
} else {
|
||||
&status("* $nick/$chan $1");
|
||||
}
|
||||
} else {
|
||||
if ($msg=~/\001([A-Z]*)\s(.*)\001/) {
|
||||
ctcpReplyParse($nick, $user, $host, $1, $2);
|
||||
} else {
|
||||
&status("-$nick($user\@$host)- $msg");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub servmsg {
|
||||
my $msg=$_[0];
|
||||
my ($ucount, $uc) = (0, 0);
|
||||
if ($msg=~/^001/) {
|
||||
# joinChan(split/\s+/, $param{'join_channels'});
|
||||
# Line in infobot.config:
|
||||
# join_channels #chan,key #chan_with_no_key
|
||||
#
|
||||
# since , is not allowed in channels, we'll use it to specify keys
|
||||
# without breaking current join_channels format
|
||||
for (split /\s+/, $param{'join_channels'}) {
|
||||
# if it's a keyed chan, replace the comma with a space so it'll
|
||||
# work as per the RFC (i.e. JOIN #chan key)
|
||||
s/,/ /;
|
||||
joinChan ($_);
|
||||
}
|
||||
$nicktries=0;
|
||||
} elsif ($msg=~/^NOTICE ($ident) :(.*)/) {
|
||||
serverNotice($1,$2);
|
||||
} elsif ($msg=~/^332 $ident ($ischan) :(.*)/) {
|
||||
if ($param{ansi_control}) {
|
||||
&status(">>> topic for $b$1$ob: $2");
|
||||
} else {
|
||||
&status(">>> topic for $1: $2");
|
||||
}
|
||||
} elsif ($msg=~/^333 $ident $ischan (.*) (.*)$/) {
|
||||
if ($param{ansi_control}) {
|
||||
&status(">>> set by $b$1$ob at $b$2$ob");
|
||||
} else {
|
||||
&status(">>> set by $1 at $2");
|
||||
}
|
||||
} elsif ($msg=~/^433/) {
|
||||
++$nicktries;
|
||||
if (length($param{wantNick}) > 9) {
|
||||
$ident = chop $param{wantNick};
|
||||
$ident .= $nicktries;
|
||||
} else {
|
||||
$ident = $param{wantNick}.$nicktries;
|
||||
}
|
||||
if ($param{'opername'}) {
|
||||
&rawout("OPER $param{opername} $param{operpass}");
|
||||
}
|
||||
$param{nick} = $ident;
|
||||
&status("*** Nickname $param{wantNick} in use, trying $ident");
|
||||
rawout("NICK $ident");
|
||||
|
||||
} elsif ($msg=~/[0-9]+ $ident . ($ischan) :(.*)/) {
|
||||
my ($chan, $users) = ($1, $2);
|
||||
&status("NAMES $chan: $users");
|
||||
my $u;
|
||||
foreach $u (split /\s+/, $users) {
|
||||
if (s/\@//) {
|
||||
$channels{$chan}{o}{$u}++;
|
||||
}
|
||||
if (s/\+//) {
|
||||
$channels{$chan}{v}{$u}++;
|
||||
}
|
||||
}
|
||||
} elsif ($msg=~/[0-9]{3} $ident(\s$ischan)*?\s:(.*)/) {
|
||||
&status("$2");
|
||||
}
|
||||
}
|
||||
|
||||
sub serverNotice {
|
||||
($type, $msg) = @_;
|
||||
if ($type=~/AUTH/) {
|
||||
&status("!$param{server}! $msg");
|
||||
} else {
|
||||
$msg =~ s/\*\*\* Notice -- //;
|
||||
&status("-!$param{server}!- $msg");
|
||||
}
|
||||
}
|
||||
|
||||
sub OperWall {
|
||||
my ($nick, $msg) = @_;
|
||||
$msg=~s/\*\*\* Notice -- //;
|
||||
&status("[wallop($nick)] $msg");
|
||||
}
|
||||
|
||||
sub prockick {
|
||||
my ($kicker, $chan, $knick, $why) = @_;
|
||||
|
||||
if ($param{ansi_control}) {
|
||||
&status(">>> $b$knick$ob was kicked off $b$chan$ob by $b$kicker$ob ($b$why$ob)");
|
||||
} else {
|
||||
&status(">>> $b$knick$ob was kicked off $b$chan$ob by $b$kicker$ob ($b$why$ob)");
|
||||
}
|
||||
if ($knick eq $ident) {
|
||||
&status("SELF attempting to rejoin lost channel $chan");
|
||||
&joinChan($chan);
|
||||
}
|
||||
}
|
||||
|
||||
sub prockill {
|
||||
my ($killer, $knick, $kserv, $killnick, $why) = @_;
|
||||
if ($knick eq $ident) {
|
||||
&status("KILLED by $killnick ($why)");
|
||||
} else {
|
||||
&status("KILL $knick by $killnick ($why)");
|
||||
}
|
||||
}
|
||||
|
||||
sub fhbits {
|
||||
local (@fhlist) = split(' ',$_[0]);
|
||||
local ($bits);
|
||||
for (@fhlist) {
|
||||
vec($bits,fileno($_),1) = 1;
|
||||
}
|
||||
$bits;
|
||||
}
|
||||
|
||||
sub irc {
|
||||
local ($rin, $rout);
|
||||
local ($buf, $line);
|
||||
|
||||
$nicktries=0;
|
||||
$connected=1;
|
||||
while ($connected) {
|
||||
srvConnect($param{server}, $param{port});
|
||||
|
||||
if ($param{server_pass}) { # ksiero++
|
||||
rawout("PASS $param{server_pass}");
|
||||
}
|
||||
|
||||
rawout("NICK $param{wantNick}");
|
||||
rawout("USER $param{ircuser} $param{ident} $param{server} :$param{realname}");
|
||||
if ($param{operator}) {
|
||||
rawout("OPER $param{operName} $param{operPass}\n");
|
||||
}
|
||||
$param{nick} = $param{wantNick};
|
||||
$ident = $param{wantNick};
|
||||
|
||||
$/ = "\015" if $^O eq "MacOS";
|
||||
|
||||
$rin = fhbits('SOCK');
|
||||
while (1) {
|
||||
($nfound,$timeleft) = select($rout=$rin, undef, undef, 0);
|
||||
if ($rout & SOCK) {
|
||||
if (sysread(SOCK,$buf,1) <= 0) {
|
||||
last;
|
||||
}
|
||||
if ($buf=~/\n/) {
|
||||
$line.=$buf;
|
||||
sparse($line);
|
||||
undef $line;
|
||||
} else {
|
||||
$line.=$buf;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#Corion++
|
||||
# Fixed baaaad backdor in server parsing (regexes are a bitch :( )
|
||||
# /msg infobot :a@b.c PRIVMSG #channel seen <nick>
|
||||
# can be used to flood a channel witout getting ever caught !
|
||||
|
||||
# Affected lines were
|
||||
# PRIVMSG / NOTICE / TOPIC / KICK
|
||||
|
||||
sub sparse {
|
||||
$_ = $_[0];
|
||||
s/\r//;
|
||||
|
||||
if (/^PING :(\S+)/) { # Pings are important
|
||||
rawout("PONG :$1");
|
||||
&status("SELF replied to server PING") if $param{VERBOSITY} > 2;
|
||||
} elsif (/^:\S+ ([\d]{3} .*)/) {
|
||||
servmsg($1);
|
||||
} elsif (/^:([\d\w\_\-\/]+\.[\.\d\w\_\-\/]+) NOTICE ($ident) :(.*)/) {
|
||||
&status("\-\[$1\]- $3");
|
||||
} elsif (/^NOTICE (.*) :(.*)/) {
|
||||
serverNotice($1, $2);
|
||||
} elsif (/^:NickServ!s\@NickServ NOTICE \S+ :(.*)/i) {
|
||||
&nickServ($1); # added by the xk.
|
||||
} elsif (/^:ChanServ!s\@ChanServ NOTICE \S+ :(.*)/i) {
|
||||
&chanServ($1); # added by the xk.
|
||||
} elsif (/^:(\S+)!(\S+)@(\S+)\s(PRIVMSG|NOTICE)\s([\#\&]?\S+)\s:(.*)/) {
|
||||
procevent($1,$2,$3,$4,$5,$6);
|
||||
} elsif (/^:(\S+)!(\S+)@(\S+)\s(PART|JOIN|NICK|QUIT)\s:?(.*)/) {
|
||||
entryEvt($1,$2,$3,$4,$5);
|
||||
} elsif (/^:(.*) WALLOPS :(.*)/) {
|
||||
OperWall($1,$2);
|
||||
} elsif (/^:(.*)!(.*)@(.*) (MODE) (.*)/) {
|
||||
procmode($1,$2,$3,$4,$5);
|
||||
} elsif (/^:(.*) (MODE) (.*)/) {
|
||||
procservmode($1,$2,$3);
|
||||
} elsif (/^:(\S+)!(?:\S+)@(?:\S+) KICK ((\#|&).+) (.*) :(.*)/) {
|
||||
prockick($1,$2,$4,$5);
|
||||
} elsif (/^ERROR :(.*)/) {
|
||||
&status("ERROR $1");
|
||||
} elsif (/^:([^! ]+)!\S+@\S+ TOPIC (\#.+) :(.*)/) {
|
||||
if ($param{ansi_control}) {
|
||||
&status(">>> $1$b\[$ob$2$b\]$ob set the topic: $3");
|
||||
} else {
|
||||
&status(">>> $1\[$2\] set the topic: $3");
|
||||
}
|
||||
} elsif (/^:(\S+)!\S+@\S+ KILL (.*) :(.*)!(.*) \((.*)\)/) {
|
||||
prockill($1,$2,$3,$4,$5);
|
||||
} else {
|
||||
&status("UNKNOWN $_");
|
||||
}
|
||||
#Corion--
|
||||
}
|
||||
|
||||
1;
|
@ -0,0 +1,83 @@
|
||||
|
||||
# infobot :: Kevin Lenzo (c) 1997
|
||||
|
||||
# Tidied up ?
|
||||
|
||||
sub IrcActionHook {
|
||||
my ($who, $channel, $message) = @_;
|
||||
|
||||
&channel($channel);
|
||||
&process($who, 'public action', $message);
|
||||
|
||||
if ($msgType =~ /public/) {
|
||||
&status("<$who/$channel> $origMessage");
|
||||
} else {
|
||||
&status("[$who] $origMessage");
|
||||
}
|
||||
}
|
||||
|
||||
sub IrcMsgHook {
|
||||
my ($type, $channel, $who, $message) = @_;
|
||||
|
||||
if ($type =~ /public/i) {
|
||||
&channel($channel);
|
||||
&process($who, $type, $message);
|
||||
&status("<$who/$channel> $origMessage");
|
||||
}
|
||||
|
||||
if ($type =~ /private/i) {
|
||||
if (($params{'mode'} eq 'IRC') && ($who eq $prevwho)) {
|
||||
$delay = time() - $prevtime;
|
||||
$prevcount++;
|
||||
|
||||
if (0 and $delay < 1) {
|
||||
# this is where to put people on ignore if they flood you
|
||||
if (IsFlag("o") ne "o") {
|
||||
&msg($who, "You will be ignored -- flood detected.");
|
||||
&postInc(ignore => $who);
|
||||
&log_line("ignoring ".$who);
|
||||
return;
|
||||
}
|
||||
}
|
||||
return if (($message eq $prevmsg) && ($delay < 10));
|
||||
} else {
|
||||
$prevcount = 0;
|
||||
$firsttime = time;
|
||||
}
|
||||
|
||||
$prevtime = time unless ($message eq $prevmsg);
|
||||
$prevmsg = $message;
|
||||
$prevwho = $who;
|
||||
&process($who, $type, $message);
|
||||
&status("[$who] $origMessage");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
sub hook_dcc_request {
|
||||
my($type, $text) = @_;
|
||||
if ($type =~ /chat/i) {
|
||||
&status("received dcc chat request from $who : $text");
|
||||
my($locWho) = $who;
|
||||
$locWho =~ tr/A-Z/a-z/;
|
||||
$locWho =~ s/\W//;
|
||||
&docommand("dcc chat ".$who);
|
||||
&msg('='.$who, "Hello, ".$who);
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
sub hook_dcc_chat {
|
||||
my($locWho, $message)=@_;
|
||||
$msgType = "dcc_chat";
|
||||
my($saveWho) = $who;
|
||||
|
||||
$who = "=".$who;
|
||||
&process($who, $msgType, $message);
|
||||
$who = $saveWho;
|
||||
return '';
|
||||
|
||||
}
|
||||
|
||||
1;
|
@ -0,0 +1,99 @@
|
||||
# infobot :: Kevin Lenzo (c) 1997
|
||||
|
||||
sub normquery {
|
||||
my ($in) = @_;
|
||||
|
||||
$in = " $in ";
|
||||
|
||||
# where blah is -> where is blah
|
||||
$in =~ s/ (where|what|who)\s+(\S+)\s+(is|are) / $1 $3 $2 /i;
|
||||
|
||||
# where blah is -> where is blah
|
||||
$in =~ s/ (where|what|who)\s+(.*)\s+(is|are) / $1 $3 $2 /i;
|
||||
|
||||
$in =~ s/^\s*(.*?)\s*/$1/;
|
||||
|
||||
$in =~ s/be tellin\'?g?/tell/i;
|
||||
$in =~ s/ \'?bout/ about/i;
|
||||
|
||||
$in =~ s/,? any(hoo?w?|ways?)/ /ig;
|
||||
$in =~ s/,?\s*(pretty )*please\??\s*$/\?/i;
|
||||
|
||||
|
||||
# what country is ...
|
||||
if ($in =~
|
||||
s/wh(at|ich)\s+(add?res?s|country|place|net (suffix|domain))/wh$1 /ig) {
|
||||
if ((length($in) == 2) && ($in !~ /^\./)) {
|
||||
$in = '.'.$in;
|
||||
}
|
||||
$in .= '?';
|
||||
}
|
||||
|
||||
# profanity filters. just delete it
|
||||
$in =~ s/th(e|at|is) (((m(o|u)th(a|er) ?)?fuck(in\'?g?)?|hell|heck|(god-?)?damn?(ed)?) ?)+//ig;
|
||||
$in =~ s/wtf/where/gi;
|
||||
$in =~ s/this (.*) thingy?/ $1/gi;
|
||||
$in =~ s/this thingy? (called )?//gi;
|
||||
$in =~ s/ha(s|ve) (an?y?|some|ne) (idea|clue|guess|seen) /know /ig;
|
||||
$in =~ s/does (any|ne|some) ?(1|one|body) know //ig;
|
||||
$in =~ s/do you know //ig;
|
||||
$in =~ s/can (you|u|((any|ne|some) ?(1|one|body)))( please)? tell (me|us|him|her)//ig;
|
||||
$in =~ s/where (\S+) can \S+ (a|an|the)?//ig;
|
||||
$in =~ s/(can|do) (i|you|one|we|he|she) (find|get)( this)?/is/i; # where can i find
|
||||
$in =~ s/(i|one|we|he|she) can (find|get)/is/gi; # where i can find
|
||||
$in =~ s/(the )?(address|url) (for|to) //i; # this should be more specific
|
||||
$in =~ s/(where is )+/where is /ig;
|
||||
$in =~ s/\s+/ /g;
|
||||
$in =~ s/^\s+//;
|
||||
if ($in =~ s/\s*[\/?!]*\?+\s*$//) {
|
||||
$finalQMark = 1;
|
||||
}
|
||||
|
||||
# $in =~ s/\b(the|an?)\s+/ /i; # handle first article in query
|
||||
$in =~ s/\s+/ /g;
|
||||
|
||||
$in =~ s/^\s*(.*?)\s*$/$1/;
|
||||
|
||||
$in;
|
||||
}
|
||||
|
||||
# for be-verbs
|
||||
sub switchPerson {
|
||||
my($in) = @_;
|
||||
|
||||
my $safeWho;
|
||||
if ($target) {
|
||||
$safeWho = &purifyNick($target);
|
||||
} else {
|
||||
$safeWho = &purifyNick($who);
|
||||
}
|
||||
|
||||
# $safeWho will cause trouble in nicks with deleted \W's
|
||||
$in =~ s/(^|\W)${safeWho}s\s+/$1${who}\'s /ig; # fix genitives
|
||||
$in =~ s/(^|\W)${safeWho}s$/$1${who}\'s/ig; # fix genitives
|
||||
$in =~ s/(^|\W)${safeWho}\'(\s|$)/$1${who}\'s$2/ig; # fix genitives
|
||||
$in =~ s/(^|\s)i\'m(\W|$)/$1$who is$2/ig;
|
||||
$in =~ s/(^|\s)i\'ve(\W|$)/$1$who has$2/ig;
|
||||
$in =~ s/(^|\s)i have(\W|$)/$1$who has$2/ig;
|
||||
$in =~ s/(^|\s)i haven\'?t(\W|$)/$1$who has not$2/ig;
|
||||
$in =~ s/(^|\s)i(\W|$)/$1$who$2/ig;
|
||||
$in =~ s/ am\b/ is/i;
|
||||
$in =~ s/\bam /is/i;
|
||||
$in =~ s/yourself/$param{'ident'}/i if ($addressed);
|
||||
$in =~ s/(^|\s)(me|myself)(\W|$)/$1$who$3/ig;
|
||||
$in =~ s/(^|\s)my(\W|$)/$1${who}\'s$2/ig; # turn 'my' into name's
|
||||
$in =~ s/(^|\W)you\'?re(\W|$)/$1you are$2/ig;
|
||||
|
||||
if ($addressed > 0) {
|
||||
$in =~ s/(^|\W)are you(\W|$)/$1is $param{'nick'}$2/ig;
|
||||
$in =~ s/(^|\W)you are(\W|$)/$1$param{'nick'} is$2/ig;
|
||||
$in =~ s/(^|\W)you(\W|$)/$1$param{'nick'}$2/ig;
|
||||
$in =~ s/(^|\W)your(\W|$)/$1$param{'nick'}\'s$2/ig;
|
||||
}
|
||||
|
||||
$in;
|
||||
}
|
||||
|
||||
# ---
|
||||
|
||||
1;
|
@ -0,0 +1,68 @@
|
||||
|
||||
# infobot :: Kevin Lenzo (c) 1997
|
||||
|
||||
if (!$filesep) {
|
||||
$filesep = '/';
|
||||
};
|
||||
|
||||
sub loadParamFiles {
|
||||
my (@files) = @_;
|
||||
my @result;
|
||||
my $p;
|
||||
|
||||
if (!@files) {
|
||||
# &status("no param files to load");
|
||||
return '';
|
||||
}
|
||||
|
||||
foreach $p (@files) {
|
||||
if ($p !~ /\S/) {
|
||||
&status("warning: param file name is null");
|
||||
return '';
|
||||
}
|
||||
|
||||
if (open(PARAM, $p)) {
|
||||
my $count;
|
||||
while (<PARAM>) {
|
||||
chomp;
|
||||
next if /^\s*\#/;
|
||||
next unless /\S/;
|
||||
my ($key, $val) = split(/\s+/, $_, 2);
|
||||
$val =~ s/\s+$//;
|
||||
|
||||
# perform variable interpolation
|
||||
|
||||
$val =~ s/(\$(\w+))/$param{$2}/g;
|
||||
&status("setting $key => $val")
|
||||
if (exists $param{VERBOSITY} and $param{VERBOSITY} > 2);
|
||||
|
||||
$param{$key} = $val;
|
||||
|
||||
++$count;
|
||||
}
|
||||
&status("loaded param file $p ($count items)");
|
||||
close(PARAM);
|
||||
} else {
|
||||
&status("failed to load param file $p");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub writeParamFile {
|
||||
my ($filename) = $_[0];
|
||||
# write the current parameter set to $filename.
|
||||
# returns 1 if successful
|
||||
|
||||
if (open POUT, ">$filename") {
|
||||
foreach (sort keys %param) {
|
||||
print POUT "$_ $param{$_}\n";
|
||||
}
|
||||
close POUT;
|
||||
return 1;
|
||||
} else {
|
||||
# couldn't write the file
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
@ -0,0 +1,431 @@
|
||||
# infobot :: Kevin Lenzo 1997-1999
|
||||
|
||||
# process the incoming message
|
||||
|
||||
$SIG{'ALRM'} = 'TimerAlarm';
|
||||
|
||||
sub process {
|
||||
($who, $msgType, $message) = @_;
|
||||
my ($result, $caughtBy);
|
||||
|
||||
$origMessage = $message; # intentionally global
|
||||
|
||||
return 'SELF' if (lc($who) eq lc($param{'nick'}));
|
||||
|
||||
$message =~ s/[\cA-\c_]//ig; # strip control characters
|
||||
$msgFilter = "NOFILTER"; # 26Jun19100 - Masque
|
||||
# $msgFilter = $1 if $message =~ s/\s+(?:=~)\s?\/\(\?:(.*?)\)\/i?\s*//;
|
||||
# STILL doesn't match '=~ /(?:(toot!))/'! Grah. Could make this simpler, but this is fun. 29Jun2K - Masque.
|
||||
# FIXME
|
||||
$msgFilter = ($1 || $2) if $message =~ s!\s+(?:=~)?\s?/(?:\((?:\?:)?([^)]*)\)|([^()]*))/i?\s*$!!;
|
||||
|
||||
|
||||
$addressed = 0;
|
||||
$karma = 0; # 12Apr2k - Masque
|
||||
|
||||
return 'ANTIHELP' if $instance =~ /antihelp/;
|
||||
|
||||
my ($n, $uh) = ($nuh =~ /^([^!]+)!(.*)/);
|
||||
if ($param{'VERBOSITY'} > 3) { # murrayb++
|
||||
&status("Splitting incoming address into $n and $uh");
|
||||
}
|
||||
|
||||
if ($msgType =~ /private/ and $message =~ /^hey, what is/) {
|
||||
$infobots{$nuh} = $who;
|
||||
&msg($who, "inter-infobot communication now requires version 0.43 or higher.");
|
||||
return 'INTERBOT';
|
||||
}
|
||||
|
||||
return 'INTERBOT' if $message =~ /^...but/;
|
||||
return 'INTERBOT' if $message =~ /^.* already had it that way/;
|
||||
return 'INTERBOT' if $message =~ /^told /; # reply from friendly infobot
|
||||
return 'INTERBOT' if $message =~ /^told /; # reply from friendly infobot
|
||||
return 'INTERBOT' if ($message =~ /^[!\*]/);
|
||||
return 'INTERBOT' if ($message =~ /^gotcha/i);
|
||||
|
||||
# this assumes that the ignore list will be fairly small, as we
|
||||
# loop through each key rather than doing a straight lookup
|
||||
# -- this should be moved and made more efficient -- kl
|
||||
if (&get(ignore => $uh) or &get(ignore => $who)) {
|
||||
&status("IGNORE <$who> $message");
|
||||
return 'IGNORE';
|
||||
}
|
||||
foreach (&getDBMKeys('ignore')) {
|
||||
my $ignoreRE = $_;
|
||||
my @parts = split /\*/, "a${ignoreRE}a";
|
||||
my $recast = join '\S*', map quotemeta($_), @parts;
|
||||
$recast =~ s/^a(.*)a$/$1/;
|
||||
if ($nuh =~ /^$recast$/) {
|
||||
&status("IGNORE <$who> $message");
|
||||
return 'IGNORE';
|
||||
}
|
||||
}
|
||||
# -- --
|
||||
|
||||
if ($msgType =~ /private/ and $message =~ s/^:INFOBOT://) {
|
||||
&status("infobot <$nuh> identified") unless $infobots{$nuh};
|
||||
$infobots{$nuh} = $who;
|
||||
}
|
||||
|
||||
if ($infobots{$nuh}) {
|
||||
if ($msgType =~ /private/) {
|
||||
if ($message =~ /^QUERY (<.*?>) (.*)/) {
|
||||
my $r;
|
||||
my $target = $1;
|
||||
my $item = $2;
|
||||
$item =~ s/[.\?]$//;
|
||||
|
||||
&status(":INFOBOT:QUERY $who: $message");
|
||||
|
||||
if ($r = &get("is", $item)) {
|
||||
&msg($who, ":INFOBOT:REPLY $target $item =is=> $r");
|
||||
}
|
||||
if ($r = &get("are", $item)) {
|
||||
&msg($who, ":INFOBOT:REPLY $target $item =are=> $r");
|
||||
}
|
||||
|
||||
} elsif ($message =~ /^REPLY <(.*?)> (.*)/) {
|
||||
my $r;
|
||||
my $target = $1;
|
||||
my $item = $2;
|
||||
|
||||
|
||||
&status(":INFOBOT:REPLY $who: $message");
|
||||
|
||||
my ($X, $V, $Y) = $item =~ /^(.*?) =(.*?)=> (.*)/;
|
||||
if ((getparam('acceptUrl') !~ /REQUIRE/) or ($Y =~ /(http|ftp|mailto|telnet|file):/)) {
|
||||
&set($V, $X, $Y);
|
||||
&msg($target, "$who knew: $X $V $Y");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return 'INFOBOT';
|
||||
}
|
||||
|
||||
$VerifWho = &verifyUser($nuh);
|
||||
|
||||
if ($VerifWho) {
|
||||
if (IsFlag("i") eq "i") {
|
||||
&status("Ignoring $who: $VerifWho");
|
||||
return 'IGNORED';
|
||||
}
|
||||
|
||||
if ($msgType =~ /private/) {
|
||||
# it's a private message
|
||||
my ($potentialPass) = $message =~ /^\s*(\S+)/;
|
||||
|
||||
if (exists($verified{$VerifWho})) {
|
||||
# aging. you need to keep talking to it re-verify
|
||||
if (time() - $verified{$VerifWho} < 60*60) { # 1 hour decay
|
||||
$verified{$VerifWho} = $now;
|
||||
} else {
|
||||
&status("verification for $VerifWho expired");
|
||||
delete $verified{$VerifWho};
|
||||
}
|
||||
}
|
||||
|
||||
if ($uPasswd eq "NONE_NEEDED") {
|
||||
&status("no password needed for $VerifWho");
|
||||
$verified{$VerifWho} = $now;
|
||||
}
|
||||
|
||||
if (&ckpasswd($potentialPass, $uPasswd)) {
|
||||
$message =~ s/^\s*\S+\s*//;
|
||||
$origMessage =~ s/^\s*\S+\s*/<PASSWORD> /;
|
||||
&status("password verified for $VerifWho");
|
||||
$verified{$VerifWho} = $now;
|
||||
if ($message =~ /^\s*$/) {
|
||||
&msg($who, "i recognize you there");
|
||||
return 'PASSWD';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# see User.pl for the "special" user commands
|
||||
return 'NOREPLY' if &userProcessing() eq 'NOREPLY';
|
||||
|
||||
if ($msgType !~ /public/) { $addressed = 1; }
|
||||
|
||||
if (($message =~ s/^(no,?\s+$param{'nick'},?\s*)//i)
|
||||
or ($addressed and $message =~ s/^(no,?\s+)//i)) {
|
||||
# clear initial negative
|
||||
# an initial negative may signify a correction
|
||||
$correction_plausible = 1;
|
||||
&status("correction is plausible, initial negative and nick deleted ($1)") if ($param{VERBOSITY} > 2);
|
||||
} else {
|
||||
$correction_plausible = 0;
|
||||
}
|
||||
|
||||
if ($message =~ /^\s*$param{'nick'}\s*\?*$/i) {
|
||||
&status("feedback addressing from $who");
|
||||
$addressed = 1;
|
||||
$blocked = 0;
|
||||
if ($msgType =~ /public/) {
|
||||
if (rand() > 0.5) {
|
||||
&performSay("yes, $who?");
|
||||
} else {
|
||||
&performSay("$who?");
|
||||
}
|
||||
} else {
|
||||
&msg($who, "yes?");
|
||||
}
|
||||
|
||||
$lastaddressedby = $who;
|
||||
$lastaddressedtime = time();
|
||||
return "FEEDBACK";
|
||||
}
|
||||
|
||||
if (($message =~ /^\s*$param{'nick'}\s*([\,\:\> ]+) */i)
|
||||
or ($message =~ /^\s*$param{'nick'}\s*-+ *\??/i)) {
|
||||
# i have been addressed!
|
||||
my($it) = $&;
|
||||
|
||||
if ($' !~ /^\s*is/i) {
|
||||
$message = $';
|
||||
$addressed = 1;
|
||||
$blocked = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ($message =~ /, ?$param{nick}(\W+)?$/i) { # i have been addressed!
|
||||
my($it) = $&;
|
||||
if ($` !~ /^\s*i?s\s*$/i) {
|
||||
$xxx = quotemeta($it);
|
||||
$message =~ s/$xxx//;
|
||||
$addressed = 1;
|
||||
$blocked = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ($addressed) {
|
||||
&status("$who is addressing me");
|
||||
$lastaddressedby = $who;
|
||||
$lastaddressedtime = time();
|
||||
|
||||
if ($message =~ /^showmode/i ) {
|
||||
if ($msgType =~ /public/) {
|
||||
if ((getparam('addressing') ne 'REQUIRE') or $addressed) {
|
||||
&performSay ($who.", addressing is currently ".getparam('addressing'));
|
||||
}
|
||||
} else {
|
||||
&msg($who, "addressing is currently ".getparam('addressing'));
|
||||
}
|
||||
return "SHOWMODE";
|
||||
}
|
||||
|
||||
my $channel = &channel();
|
||||
$continuity = 0;
|
||||
|
||||
} else { # apparently not addressed
|
||||
my ($now, $diff);
|
||||
|
||||
if (getparam('continuity') and $who eq $lastaddressedby) {
|
||||
$now = time();
|
||||
$diff = $now - $lastaddressedtime;
|
||||
|
||||
if ($diff < getparam('continuity')) {
|
||||
# assume we're talking to the same person even if we're
|
||||
# not addressed, if we've been addressed in x seconds
|
||||
&status("assuming continuity of address by $who ($diff seconds elapsed)");
|
||||
$continuity = 1;
|
||||
}
|
||||
} else {
|
||||
$continuity = 0;
|
||||
}
|
||||
}
|
||||
|
||||
$skipReply = 0;
|
||||
$message_input_length = length($message);
|
||||
|
||||
# this was here to help stop bots from just triggering
|
||||
# "confused" messages to each other, but should be done
|
||||
# more systematically. took it out to cut overhead. --kl
|
||||
# $confusedRE = join '|', map quotemeta($_), @confused unless defined $confusedRE;
|
||||
# return 'CONFUSED' if $message =~ /$confusedRE/;
|
||||
|
||||
return if ($who eq $param{'nick'});
|
||||
|
||||
$message =~ s/^\s+//; # strip any dodgey spaces off
|
||||
|
||||
# Half finished thought here - "^Pudge - it's there" looks like math but is
|
||||
# often nick completion or similar.
|
||||
# if (($message =~ s/^\S+\s*:\s+//) or ($message =~ s/^\S+\s+--?\s+[.\d]//)) {
|
||||
if (($message =~ s/^\S+\s*:\s+//) or ($message =~ s/^\S+\s+--+\s+//)) {
|
||||
# stripped the addressee ("^Pudge: it's there")
|
||||
$reallyTalkingTo = $1;
|
||||
} else {
|
||||
$reallyTalkingTo = '';
|
||||
if ($addressed) {
|
||||
$reallyTalkingTo = $param{'nick'};
|
||||
}
|
||||
}
|
||||
|
||||
$message =~ s/^\s*hey,*\s+where/where/i;
|
||||
$message =~ s/whois/who is/ig;
|
||||
$message =~ s/where can i find/where is/i;
|
||||
$message =~ s/how about/where is/i;
|
||||
$message =~ s/^(gee|boy|golly|gosh),? //i;
|
||||
$message =~ s/^(well|and|but|or|yes),? //i;
|
||||
$message =~ s/^(does )?(any|ne)(1|one|body) know //i;
|
||||
$message =~ s/ da / the /ig;
|
||||
$message =~ s/^heya*,*( folks)?,*\.* *//i; # clear initial filled pauses & stuff
|
||||
$message =~ s/^[uh]+m*[,\.]* +//i;
|
||||
$message =~ s/^o+[hk]+(a+y+)?,*\.* +//i;
|
||||
$message =~ s/^g(eez|osh|olly)+,*\.* +(.+)/$2/i;
|
||||
$message =~ s/^w(ow|hee|o+ho+)+,*\.* +(.+)/$2/i;
|
||||
$message =~ s/^still,* +//i;
|
||||
$message =~ s/^well,* +//i;
|
||||
$message =~ s/^\s*(stupid )?q(uestion)?:\s+//i;
|
||||
|
||||
my $holdMessage = $message;
|
||||
|
||||
# the thing to tell someone about ($tell_obj). Yes i know these are evil globals. --kl
|
||||
($tell_obj, $target) = (undef,undef,undef);
|
||||
|
||||
# i'm telling!
|
||||
if (getparam('allowTelling')) {
|
||||
# this one catches most of them
|
||||
if ($message =~ /^tell\s+(\S+)\s+about\s+(.*)/i) {
|
||||
($target, $tell_obj) = ($1, $2);
|
||||
} elsif ($message =~ /tell\s+(\S+)\s+where\s+(\S+)\s+can\s+(\S+)\s+(.*)/i) {
|
||||
# i'm sure this could all be nicely collapsed
|
||||
($target, $tell_obj) = ($1, $4);
|
||||
} elsif ($message =~ /tell\s+(\S+)\s+(what|where)\s+(.*?)\s+(is|are)[.?!]*$/i) {
|
||||
($target, $qWord, $tell_obj, $verb) = ($1, $2, $3, $4);
|
||||
$tell_obj = "$qWord $verb $tell_obj";
|
||||
}
|
||||
|
||||
if (($target =~/^\s*[\&\#]/) or ($target =~ /\,/)) {
|
||||
$result = "No, ".$who.", i won\'t";
|
||||
$target = $who;
|
||||
$caughtBy = "tell";
|
||||
}
|
||||
|
||||
if ($target eq $param{'nick'}) {
|
||||
$result = "Isn\'t that a bit silly, ".$who."?";
|
||||
$target = $who;
|
||||
$caughtBy = "tell";
|
||||
}
|
||||
|
||||
$tell_obj =~ s/[\.\?!]+$// if defined $tell_obj;
|
||||
}
|
||||
|
||||
if (not defined $result) {
|
||||
$target = $who unless defined $target;
|
||||
$target = $who if $target eq 'me';
|
||||
$target = undef if $target eq 'us';
|
||||
|
||||
# here's where the external routines get called.
|
||||
# if they return anything but null, that's the "answer".
|
||||
|
||||
$message = $tell_obj if $tell_obj;
|
||||
|
||||
if ($continuity or $addressed or
|
||||
(getparam('addressing') ne "REQUIRE")) {
|
||||
|
||||
if (defined ($result = &myRoutines())) {
|
||||
$caughtBy = "myRoutines";
|
||||
} elsif (defined($result = &Extras())) {
|
||||
$caughtBy = "Extras";
|
||||
# BEEP BEEP - TODO ALERT: Change the karma lookup to do a doQuestion
|
||||
# before returning a karma query to catch factoids that should return
|
||||
# instead of reporting karma. Assigned to boojum at the moment.
|
||||
} elsif (defined($result = &doQuestion($msgType, $message, $msgFilter))) {
|
||||
$caughtBy = "Question";
|
||||
}
|
||||
|
||||
if (($result eq 'NOREPLY') or ($who eq 'NOREPLY')) {
|
||||
return '';
|
||||
}
|
||||
# This fixes the problem of short karma strings (masque++ for
|
||||
# example) being ignored. -- Masque, 12Apr2K
|
||||
if ($message =~ /(?:\+\+|--)/) { $karma = 1; }
|
||||
|
||||
if (!$finalQMark and !$addressed and !$tell_obj and
|
||||
!$karma and
|
||||
($input_message_length < getparam('minVolunteerLength'))) {
|
||||
$in = '';
|
||||
return 'NOREPLY';
|
||||
}
|
||||
}
|
||||
|
||||
if ($caughtBy) {
|
||||
if ($tell_obj) {
|
||||
$message = $tell_obj;
|
||||
&status("$caughtBy: <$who>->$target< [$message] -> $result");
|
||||
} else {
|
||||
&status("$caughtBy: <$who> $message");
|
||||
}
|
||||
|
||||
$questionCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (defined $result) {
|
||||
if ($msgType =~ /public/) {
|
||||
if ($target eq $who) {
|
||||
&performSay($result) if ($result and not $blocked);
|
||||
} else {
|
||||
my $r = "$who wants you to know: $result";
|
||||
&msg($target, $r);
|
||||
if ($who ne $target) {
|
||||
&msg($who, "told $target about $tell_obj ($r)");
|
||||
}
|
||||
return 'NOREPLY';
|
||||
}
|
||||
} else { # not public
|
||||
if ($who eq $target) { # to self
|
||||
&msg($who, $result);
|
||||
} else { # to someone else
|
||||
my $r;
|
||||
|
||||
if (lc($who) eq lc($target)) {
|
||||
&msg($target, $result);
|
||||
} else {
|
||||
$r = "$who wants you to know: $result";
|
||||
&msg($target, $r);
|
||||
&msg($who, "told $target about $tell_obj ($r)");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { # not $caughtBy
|
||||
|
||||
return "No authorization to teach" unless (IsFlag("t") eq "t");
|
||||
|
||||
if (!getparam('allowUpdate')) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$result = &doStatement($msgType, $holdMessage);
|
||||
|
||||
if (($who eq 'NOREPLY')||($result eq 'NOREPLY')) { return ''; };
|
||||
|
||||
return 'NOREPLY' if grep $_ eq $who, split /\s+/, $param{friendlyBots};
|
||||
|
||||
if (defined $result) {
|
||||
$caughtBy = "Statement";
|
||||
if ($msgType =~ /public/) {
|
||||
&say("OK, $who.") if $addressed;
|
||||
} else {
|
||||
&msg($who, "gotcha.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ($addressed and not $caughtBy) {
|
||||
# &status("unparseable: $message");
|
||||
|
||||
if ($msgType =~ /public/) {
|
||||
&say("$who: ".$confused[int(rand(@confused))]) if $addressed;
|
||||
} else {
|
||||
&msg($who, $confused[int(rand(@confused))]);
|
||||
}
|
||||
return "NOPARSE";
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
|
@ -0,0 +1,134 @@
|
||||
# infobot :: Kevin Lenzo (c) 1997
|
||||
|
||||
##
|
||||
## doQuestion --
|
||||
##
|
||||
## decide if $in is a query, and if so, return its value.
|
||||
## otherwise return null.
|
||||
##
|
||||
|
||||
sub doQuestion {
|
||||
local ($msgType, $qmsg, $msgFilter) = @_;
|
||||
chomp $qmsg;
|
||||
|
||||
$finalQMark = $qmsg =~ s/\?+\s*$//;
|
||||
|
||||
$questionWord = ""; # this is shared for a reason
|
||||
$input_message_length = length($qmsg);
|
||||
|
||||
my($locWho) = $who;
|
||||
|
||||
$locWho =~ tr/A-Z/a-z/;
|
||||
$locWho =~ s/^=//;
|
||||
|
||||
my ($origIn) = $qmsg;
|
||||
$finalQMark += $qmsg =~ s/\?\s*$//;
|
||||
|
||||
# convert to canonical reference form
|
||||
$qmsg = &normquery($qmsg);
|
||||
$qmsg = &switchPerson($qmsg);
|
||||
|
||||
# where is x at?
|
||||
$qmsg =~ s/\s+at\s*(\?*)$/$1/;
|
||||
|
||||
$qmsg = " $qmsg ";
|
||||
|
||||
my $qregex = join '|', @qWord;
|
||||
|
||||
# what's whats => what is; who'?s => who is, etc
|
||||
$qmsg =~ s/ ($qregex)\'?s / $1 is /i;
|
||||
if ($qmsg =~ s/\s+($qregex)\s+//i) { # check for question word
|
||||
$questionWord = lc($1);
|
||||
}
|
||||
|
||||
$qmsg =~ s/^\s+//;
|
||||
$qmsg =~ s/\s+$//;
|
||||
|
||||
if (($questionWord eq "") && ($finalQMark > 0)
|
||||
&& ($addressed or $continuity)) {
|
||||
$questionWord = "where";
|
||||
}
|
||||
|
||||
# ok, here's where we try to actually get it
|
||||
$answer = &getReply($msgType, $qmsg, $msgFilter);
|
||||
|
||||
return 'NOREPLY' if ($answer eq 'NOREPLY');
|
||||
|
||||
if (($param{'addressing'} eq 'REQUIRE') && not ($addressed or $continuity)) {
|
||||
return 'NOREPLY';
|
||||
}
|
||||
|
||||
if (not defined $answer) {
|
||||
$answer = &math($qmsg); # clean up the argument syntax for this later
|
||||
}
|
||||
|
||||
if ($questionWord ne "" or $finalQMark) {
|
||||
# if it has not been explicitly marked as a question
|
||||
if ($addressed && (not defined $answer)) {
|
||||
# and we're addressed and so far the result is null
|
||||
&status("notfound: <$who> $origIn :: $qmsg");
|
||||
|
||||
return 'NOREPLY' if $infobots{$nuh};
|
||||
my $reply;
|
||||
|
||||
# generate some random i-don't-know reply.
|
||||
if ($target ne $who and $target ne $talkchannel) {
|
||||
$target = $who; # set the target back to the originator
|
||||
$reply = "I don't know about '$qmsg'";
|
||||
} else {
|
||||
$reply = $dunno[int(rand(@dunno))];
|
||||
}
|
||||
|
||||
if (rand() > 0.5) {
|
||||
$reply = "$locWho: $reply";
|
||||
} else {
|
||||
$reply = "$reply, $locWho";
|
||||
}
|
||||
|
||||
&askFriendlyBots($qmsg);
|
||||
|
||||
# and set the result
|
||||
$answer = $reply;
|
||||
} else {
|
||||
# the item was found
|
||||
if ($answer ne "") {
|
||||
&status("match: $qmsg => $answer");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $answer;
|
||||
}
|
||||
|
||||
sub timeToString {
|
||||
my $upTime = $_[0];
|
||||
$upTime = (time()-$startTime);
|
||||
my $upDays = int($upTime / (60*60*24));
|
||||
my $upString = "";
|
||||
if ($upDays > 0) {
|
||||
$upString .= $upDays." day";
|
||||
$upString .= "s" if ($upDays > 1);
|
||||
$upString .=", ";
|
||||
}
|
||||
$upTime -= $upDays * 60*60*24;
|
||||
my $upHours = int($upTime / (60*60));
|
||||
if ($upHours > 0) {
|
||||
$upString .= $upHours." hour";
|
||||
$upString .= "s" if ($upHours > 1);
|
||||
$upString .=", ";
|
||||
}
|
||||
$upTime -= $upHours *60*60;
|
||||
my $upMinutes = int($upTime / 60);
|
||||
if ($upMinutes > 0) {
|
||||
$upString .= $upMinutes." minute";
|
||||
$upString .= "s" if ($upMinutes > 1);
|
||||
$upString .=", ";
|
||||
}
|
||||
$upTime -= $upMinutes * 60;
|
||||
my $upSeconds = $upTime;
|
||||
$upString .= $upSeconds." second";
|
||||
$upString .= "s" if ($upSeconds != 1);
|
||||
$upString;
|
||||
}
|
||||
|
||||
1;
|
@ -0,0 +1,336 @@
|
||||
# infobot :: Kevin Lenzo (c) 1997
|
||||
|
||||
sub getReply {
|
||||
my($msgType, $message, $msgFilter) = @_;
|
||||
my($theMsg) = "";
|
||||
my($locMsg) = $message;
|
||||
|
||||
# x is y
|
||||
|
||||
# x is the lhs (left hand side)
|
||||
# 'is' is the mhs ("middle hand side".. the "head", or verb)
|
||||
# y is the Y (right hand side)
|
||||
|
||||
my($X, $V, $Y, $result);
|
||||
my ($theVerb, $orig_Y);
|
||||
|
||||
$locMsg =~ tr/A-Z/a-z/;
|
||||
|
||||
my $literal = ($locMsg =~ s/^literal //);
|
||||
|
||||
if (getparam('rss') and $message =~ m/^perlfaq\'\s+(.*?)\?*$/) {
|
||||
# specially defined type. get and process an RSS (RDF Site Summary)
|
||||
eval "use URI::Escape";
|
||||
not ($@) and do {
|
||||
my $q = uri_escape($1, '\W');
|
||||
my $result = &get_headlines("http://www.perlfaq.com/cgi-bin/rss/kw?q=$q");
|
||||
if ($result =~ s/^error: //) {
|
||||
return "$who: couldn't get the perlfaq: $result";
|
||||
} else {
|
||||
return "$who: $result";
|
||||
}
|
||||
}
|
||||
} elsif ($result = get("is", $locMsg)) {
|
||||
# &status("exact: $message =is=> $result");
|
||||
$theVerb = "is";
|
||||
$X = $message;
|
||||
$V = $theVerb;
|
||||
$Y = $result;
|
||||
$orig_Y = $X;
|
||||
|
||||
} elsif ($result = get("are", $locMsg)) {
|
||||
# &status("exact: $message =is=> $result");
|
||||
$theVerb = "are";
|
||||
$X = $message;
|
||||
$V = $theVerb;
|
||||
$Y = $result;
|
||||
$orig_Y = $X;
|
||||
|
||||
} else { # no verb
|
||||
$y_determiner = '';
|
||||
$verbs = join '|', @verb;
|
||||
|
||||
$message = " $message ";
|
||||
|
||||
if ($message =~ / ($verbs) /i) {
|
||||
$X = $`;
|
||||
$V = $1;
|
||||
$Y = $';
|
||||
|
||||
$X =~ s/^\s*(.*?)\s*$/$1/;
|
||||
$Y =~ s/^\s*(.*?)\s*$/$1/;
|
||||
$orig_Y = $Y;
|
||||
$Y =~ tr/A-Z/a-z/;
|
||||
|
||||
$V =~ s/^\s*(.*?)\s*$/$1/;
|
||||
|
||||
if ($Y =~ s/^(an?|the)\s+//) {
|
||||
$y_determiner = $1;
|
||||
} else {
|
||||
$y_determiner = '';
|
||||
}
|
||||
|
||||
if ($questionWord !~ /^\s*$/) {
|
||||
if ($V eq "is") {
|
||||
$result = &get("is", $Y);
|
||||
} else {
|
||||
if ($V eq "are") {
|
||||
$result = &get("are", $Y);
|
||||
}
|
||||
}
|
||||
}
|
||||
$theVerb = $V;
|
||||
}
|
||||
|
||||
if ($param{'VERBOSITY'} > 1) {
|
||||
my $debugstring = "\tmsgType:\t$msgType\n";
|
||||
$debugstring .= "\tquestionWord:\t$questionWord\n";
|
||||
$debugstring .= "\taddressed:\t$addressed\n";
|
||||
$debugstring .= "\tfinalQMark:\t$finalQMark\n";
|
||||
$debugstring .= "\tX[$X] verb[$theVerb] det[$y_determiner] Y[$Y]\n";
|
||||
$debugstring .= "\tresult:\t$result\n";
|
||||
&status($debugstring);
|
||||
}
|
||||
|
||||
if ($y_determiner) {
|
||||
# put the det back on
|
||||
$Y = "$y_determiner $Y";
|
||||
}
|
||||
|
||||
# check "is" tables anyway for lhs alone
|
||||
|
||||
if (!defined($V)) { # no explicit head had been found
|
||||
my $det;
|
||||
if ($locMsg =~ s/^\s*(an?|the)\s+//) {
|
||||
$det = $1;
|
||||
}
|
||||
$locMsg =~ s/[.!?]+\s*$//;
|
||||
|
||||
my($check) = "";
|
||||
|
||||
$check = &get("is", $locMsg);
|
||||
|
||||
if ($check ne "") {
|
||||
$result = $check;
|
||||
$orig_Y = $locMsg;
|
||||
$theVerb = "is";
|
||||
$V = "is"; # artificially set the head to is
|
||||
} else {
|
||||
$check = &get("are", $locMsg);
|
||||
if ($check ne "") {
|
||||
$result = $check;
|
||||
$V = "are"; # artificially set the head to are
|
||||
$orig_Y = $locMsg;
|
||||
$theVerb = "are";
|
||||
}
|
||||
}
|
||||
if ($det) {
|
||||
$orig_Y = "$det $orig_Y";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($V ne "") { # if there was a head...
|
||||
if (not $literal) { # Changed to cope with $msgFilter - 26Jun19100, Masque
|
||||
my(@poss) = split(/(?<!\\)\|/, $result);
|
||||
$poss[0] =~ s/^\s//;
|
||||
$poss[$#poss] =~ s/\s$//;
|
||||
my @filtered = grep /\Q$msgFilter\E/, @poss unless $msgFilter eq "NOFILTER";
|
||||
|
||||
if (@filtered) {
|
||||
$theMsg = $filtered[int(rand(@filtered))];
|
||||
$theMsg =~ s/^\s*//;
|
||||
} elsif (@poss > 1 && $msgFilter eq "NOFILTER") {
|
||||
$theMsg = $poss[int(rand(@poss))];
|
||||
$theMsg =~ s/^\s*//;
|
||||
} else {
|
||||
if ($msgFilter eq "NOFILTER" || $result =~ /\Q$msgFilter\E/) {
|
||||
$theMsg = $result;
|
||||
} else {
|
||||
$theMsg = q!<reply>Hmm. No matches for that, $who.!;
|
||||
}
|
||||
}
|
||||
$theMsg =~ s/\\\|/\|/g;
|
||||
} else {
|
||||
$theMsg = $result;
|
||||
}
|
||||
}
|
||||
|
||||
$skipReply = 0;
|
||||
|
||||
if ($theMsg ne "") {
|
||||
if ($msgType =~ /public/) {
|
||||
my $interval = time() - $prevTime;
|
||||
if ( ($param{'mode'} eq 'IRC' )
|
||||
&& getparam('repeatIgnoreInterval')
|
||||
&& ($theMsg eq $prevMsg)
|
||||
&& ((time()-$prevTime) < getparam('repeatIgnoreInterval'))) {
|
||||
&status("repeat ignored ($interval secs < ".getparam('repeatIgnoreInterval').")");
|
||||
$skipReply = 1;
|
||||
$theMsg = "NOREPLY";
|
||||
$prevTime = time();
|
||||
} else {
|
||||
$skipReply = 0;
|
||||
$prevTime = time() unless ($theMsg eq $prevMsg);
|
||||
$prevMsg = $theMsg;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# by now $theMsg should contain the result, or null
|
||||
|
||||
# this global is nto a great idea
|
||||
$shortReply = 0;
|
||||
$noReply = 0;
|
||||
|
||||
if (0 and $theMsg =~ s/^\s*<noreply>\s*//i) {
|
||||
# specially defined type. No reply. Experimental.
|
||||
$noReply = 1;
|
||||
return 'NOREPLY';
|
||||
}
|
||||
|
||||
if (!$msgType) {
|
||||
$msgType = 'private';
|
||||
&status("NO MSG TYPE / set to private\n");
|
||||
}
|
||||
|
||||
if ($literal) {
|
||||
$orig_Y =~ s/^literal //;
|
||||
$theMsg = "$who: $orig_Y =$theVerb= $theMsg";
|
||||
return $theMsg;
|
||||
}
|
||||
|
||||
if ($msgType !~ /private/ and $theMsg =~ s/^\s*<reply>\s*//i) {
|
||||
# specially defined type. only remove '<reply>'
|
||||
$shortReply = 1;
|
||||
} elsif (getparam('rss') and $theMsg =~ m/(<(?:rss|rdf)\s*=\s*(\S+)>)/i) {
|
||||
# specially defined type. get and process an RSS (RDF Site Summary)
|
||||
my ($replace, $rdf_loc) = ($1,$2);
|
||||
$shortReply = 1;
|
||||
$rdf_loc =~ s/^\"+//;
|
||||
$rdf_loc =~ s/\"+$//;
|
||||
|
||||
if ($rdf_loc !~ /^(ht|f)tp:/) {
|
||||
&msg($who, "$orig_Y: bad RSS [$rdf_loc] (not an HTTP or FTP location)");
|
||||
} else {
|
||||
my $result = &get_headlines($rdf_loc);
|
||||
if ($result =~ s/^error: //) {
|
||||
$theMsg = "couldn't get the headlines: $result";
|
||||
} else {
|
||||
$theMsg =~ s/\Q$replace\E/$result/;
|
||||
$theMsg = "$who: $theMsg";
|
||||
}
|
||||
}
|
||||
} elsif ($msgType !~ /private/ and
|
||||
$theMsg =~ s/^\s*<action>\s*(.*)/\cAACTION $1\cA/i) {
|
||||
# specially defined type. only remove '<action>' and make it an action
|
||||
$shortReply = 1;
|
||||
} else { # not a short reply
|
||||
if (!$infobots{$nuh} and $theVerb =~ /is/) {
|
||||
my($x) = int(rand(16));
|
||||
# oh this could be done much better
|
||||
if ($x <= 5) {
|
||||
$theMsg= "$orig_Y is $theMsg";
|
||||
}
|
||||
if ($x == 6) {
|
||||
$theMsg= "i think $orig_Y is $theMsg";
|
||||
}
|
||||
if ($x == 7) {
|
||||
$theMsg= "hmmm... $orig_Y is $theMsg";
|
||||
}
|
||||
if ($x == 8) {
|
||||
$theMsg= "it has been said that $orig_Y is $theMsg";
|
||||
}
|
||||
if ($x == 9) {
|
||||
$theMsg= "$orig_Y is probably $theMsg";
|
||||
}
|
||||
if ($x == 10) {
|
||||
$theMsg =~ s/[.!?]+$//;
|
||||
$theMsg= "rumour has it $orig_Y is $theMsg";
|
||||
# $theMsg .= " dumbass";
|
||||
}
|
||||
if ($x == 11) {
|
||||
$theMsg= "i heard $orig_Y was $theMsg";
|
||||
}
|
||||
if ($x == 12) {
|
||||
$theMsg= "somebody said $orig_Y was $theMsg";
|
||||
}
|
||||
if ($x == 13) {
|
||||
$theMsg= "i guess $orig_Y is $theMsg";
|
||||
}
|
||||
if ($x == 14) {
|
||||
$theMsg= "well, $orig_Y is $theMsg";
|
||||
}
|
||||
if ($x == 15) {
|
||||
$theMsg =~ s/[.!?]+$//;
|
||||
$theMsg= "$orig_Y is, like, $theMsg";
|
||||
}
|
||||
} else {
|
||||
$theMsg = "$orig_Y $theVerb $theMsg" if ($theMsg !~ /^\s*$/);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
my $safeWho = &purifyNick($who);
|
||||
|
||||
if (!$shortReply) {
|
||||
# shouldn't this be in switchPerson?
|
||||
# this is fixing the person for going back out
|
||||
|
||||
# /^onz!lenzo@lenzo.pc.cs.cmu.edu privmsg rurl :*** noctcp: omega42 is/: nested *?+ in regexp at /usr/users/infobot/infobot-current/src/Reply.pl line 266, <FH> chunk 176.
|
||||
|
||||
if ($theMsg =~ s/^$safeWho is/you are/i) { # fix the person
|
||||
} else {
|
||||
$theMsg =~ s/^$param{'nick'} is /i am /ig;
|
||||
$theMsg =~ s/ $param{'nick'} is / i am /ig;
|
||||
$theMsg =~ s/^$param{'nick'} was /i was /ig;
|
||||
$theMsg =~ s/ $param{'nick'} was / i was /ig;
|
||||
|
||||
if ($addressed) {
|
||||
$theMsg =~ s/^you are (\.*)/i am $1/ig;
|
||||
$theMsg =~ s/ you are (\.*)/ i am $1/ig;
|
||||
} else {
|
||||
if ($theMsg =~ /^you are / or $theMsg =~ / you are /) {
|
||||
$theMsg = 'NOREPLY';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$theMsg =~ s/ $param{'ident'}\'?s / my /ig;
|
||||
$theMsg =~ s/^$safeWho\'?s /$safeWho, your /i;
|
||||
$theMsg =~ s/ $safeWho\'?s / your /ig;
|
||||
}
|
||||
|
||||
|
||||
if (1) { # $date, $time
|
||||
$curDate = scalar(localtime());
|
||||
chomp $curDate;
|
||||
$curDate =~ s/\:\d+(\s+\w+)\s+\d+$/$1/;
|
||||
$theMsg =~ s/\$date/$curDate/gi;
|
||||
$curDate =~ s/\w+\s+\w+\s+\d+\s+//;
|
||||
$theMsg =~ s/\$time/$curDate/gi;
|
||||
}
|
||||
|
||||
$theMsg =~ s/\$who/$who/gi;
|
||||
|
||||
if (1) { # variables. like $me or \me
|
||||
$theMsg =~ s/(\\){1,}([^\s\\]+)/$1/g;
|
||||
}
|
||||
|
||||
$theMsg =~ s/^\s*//;
|
||||
$theMsg =~ s/\s+$//;
|
||||
|
||||
if (getparam('filter')) {
|
||||
require "src/filter.pl";
|
||||
$theMsg = &filter($theMsg);
|
||||
}
|
||||
|
||||
if ($theMsg =~ /\S/) {
|
||||
return $theMsg;
|
||||
} else {
|
||||
return undef;
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
|
@ -0,0 +1,89 @@
|
||||
# infobot copyright kevin lenzo 1997-1999
|
||||
|
||||
sub search {
|
||||
return '' unless $addressed;
|
||||
|
||||
my $pattern = shift ;
|
||||
$pattern =~ s/^\s*(search|scan)(\s+for)?\s+//i;
|
||||
my $type = lc($1);
|
||||
|
||||
my $bail_thresh = 5;
|
||||
|
||||
if ($pattern =~ s/^\d+ //) {
|
||||
$bail_thresh = $&;
|
||||
} else {
|
||||
if ($type eq 'scan') {
|
||||
$bail_thresh = 1;
|
||||
}
|
||||
}
|
||||
|
||||
$pattern =~ s/\?+\s*$//; # final ? marks
|
||||
|
||||
return '' if ($pattern =~ /^\s*$/);
|
||||
|
||||
my $minlength = 3;
|
||||
|
||||
return "that pattern's too short. try something with at least $minlength characters."
|
||||
if (length($pattern) < $minlength);
|
||||
|
||||
&msg($who,"Looking for $pattern:");
|
||||
|
||||
my (@response);
|
||||
|
||||
my (@myIsKeys) = getDBMKeys("is");
|
||||
|
||||
my $t = time();
|
||||
my $count = 0;
|
||||
|
||||
foreach (@myIsKeys) {
|
||||
if (/$pattern/) {
|
||||
$r = &get("is", $_);
|
||||
} else {
|
||||
next ;
|
||||
}
|
||||
my $t1 = time();
|
||||
if ($t1-$t < 2) {
|
||||
sleep 2;
|
||||
}
|
||||
&msg($who, "$_ is $r");
|
||||
$t = $t1;
|
||||
last if ++$count >= $bail_thresh;
|
||||
}
|
||||
|
||||
my $last;
|
||||
if ($count < $bail_thresh) {
|
||||
my (@myAreKeys) = getDBMKeys("are");
|
||||
foreach (@myAreKeys) {
|
||||
if (/$pattern/) {
|
||||
$r = &get("are", $_);
|
||||
} else {
|
||||
next ;
|
||||
}
|
||||
my $t1 = time();
|
||||
if ($t1-$t < 2) {
|
||||
sleep 2;
|
||||
}
|
||||
$t = $t1;
|
||||
&msg($who, "$_ are $r");
|
||||
last if ++$count >= $bail_thresh;
|
||||
}
|
||||
$last = 1;
|
||||
}
|
||||
|
||||
if (!$count) {
|
||||
&msg($who, "nothing found for $pattern");
|
||||
} else {
|
||||
my $reply = " ...showing $count hits";
|
||||
if ($last) {
|
||||
$reply .= " (all shown).";
|
||||
} else {
|
||||
$reply .= " (more may exist).";
|
||||
}
|
||||
|
||||
&msg($who, $reply);
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
1;
|
@ -0,0 +1,159 @@
|
||||
|
||||
# infobot :: Kevin Lenzo (c) 1997-2000
|
||||
|
||||
sub setup {
|
||||
# param setup should stay after most of the requires
|
||||
# so that it overrides anything they might set.
|
||||
¶mSetup();
|
||||
|
||||
if ($param{VERBOSITY} > 1) {
|
||||
my $params = "Parameters are:\n";
|
||||
foreach (sort keys %param) {
|
||||
$params .= " $_ -> $param{$_}\n";
|
||||
}
|
||||
&status($params);
|
||||
}
|
||||
|
||||
die "dbname is null" if (!$param{'dbname'});
|
||||
|
||||
%dbs = ("is" => "$param{basedir}/$param{dbname}-is",
|
||||
"are" => "$param{basedir}/$param{dbname}-are");
|
||||
srand();
|
||||
|
||||
$setup_time = scalar(localtime());
|
||||
$setup_time =~ s/\n//g;
|
||||
|
||||
$startTime = time();
|
||||
|
||||
&setup_help;
|
||||
&openDBM(%dbs);
|
||||
|
||||
$qCount = &get("is", "the qCount");
|
||||
$qEpochTime = &get("is", "the qEpochTime");
|
||||
|
||||
# things to say when people thank me
|
||||
@welcomes = ('no problem', 'my pleasure', 'sure thing',
|
||||
'no worries', 'de nada', 'de rien', 'bitte', 'pas de quoi');
|
||||
|
||||
# when i'm cofused and I have to reply
|
||||
@confused = ("huh?",
|
||||
"what?",
|
||||
"sorry...",
|
||||
"i\'m not following you...",
|
||||
"excuse me?");
|
||||
|
||||
# when i recognize a query but can't answer it
|
||||
@dunno = ('i don\'t know',
|
||||
'wish i knew',
|
||||
'i haven\'t a clue',
|
||||
'no idea',
|
||||
'bugger all, i dunno');
|
||||
|
||||
|
||||
|
||||
# check the ignore parameter for a filename containing the
|
||||
# ignore list
|
||||
|
||||
if ($param{ignore}) {
|
||||
&openDBMx('ignore');
|
||||
}
|
||||
|
||||
if ($param{sanePrefix}) {
|
||||
for $d (qw/is are/) {
|
||||
my $dbname = $DBprefix.$d;
|
||||
my $sane = "$param{confdir}/$param{sanePrefix}";
|
||||
$sane .= "-$d.txt";
|
||||
if (-e $sane) {
|
||||
&status("loading sane defines $sane");
|
||||
&insertFile($dbname, $sane);
|
||||
} else {
|
||||
&status("can't fine sane file $sane");
|
||||
}
|
||||
}
|
||||
|
||||
if (! open IGNORE, "$param{'confdir'}/$param{sanePrefix}-ignore.txt") {
|
||||
&status("No fallback ignore file $param{'confdir'}/$param{sanePrefix}-ignore.txt");
|
||||
} else {
|
||||
while (<IGNORE>) {
|
||||
s/^\s+//;
|
||||
s/\s+\#.*//;
|
||||
chomp;
|
||||
/\S/ && do {
|
||||
&postInc(ignore => $_);
|
||||
if ($param{'VERBOSITY'} > 0) {
|
||||
&status("Adding $_ to ignore list (from sane).");
|
||||
}
|
||||
};
|
||||
}
|
||||
close IGNORE;
|
||||
}
|
||||
}
|
||||
|
||||
if ($param{'plusplus'}) {
|
||||
&openDBMx('plusplus');
|
||||
}
|
||||
|
||||
if ($param{'seen'}) {
|
||||
&openDBMx('seen');
|
||||
}
|
||||
|
||||
# set up the users and ops
|
||||
&status("Parsing User File");
|
||||
&parseUserfile();
|
||||
|
||||
&status("Parsing Channel File");
|
||||
# set up the channel file
|
||||
&parseChannelfile();
|
||||
|
||||
# ways to say hello
|
||||
@hello = ('hello',
|
||||
'hi',
|
||||
'hey',
|
||||
'niihau',
|
||||
'bonjour',
|
||||
'hola',
|
||||
'salut',
|
||||
'que tal',
|
||||
'privet',
|
||||
"what's up");
|
||||
|
||||
$param{'maxKeySize'} ||= 30; # maximum LHS length
|
||||
$param{'maxDataSize'} ||= 200; # maximum total length
|
||||
|
||||
if (!(@verb)) {
|
||||
@verb = split(" ", "is are");
|
||||
# am was were does has can wants needs feels
|
||||
# handle s-v agreement for non-being verbs later
|
||||
}
|
||||
|
||||
if (!(@qWord)) {
|
||||
@qWord = split(" ", "what where who"); # why how when
|
||||
}
|
||||
|
||||
# do this ONCE per startup to amortize. Still too much mem.
|
||||
#&getAllKeys;
|
||||
$isCount = &getDBMKeys('is');
|
||||
$areCount = &getDBMKeys('are');
|
||||
$factoidCount = $isCount + $areCount;
|
||||
|
||||
&status("setup: $factoidCount factoids; $isCount IS; $areCount ARE");
|
||||
}
|
||||
|
||||
|
||||
sub paramSetup {
|
||||
my $initdebug = 1;
|
||||
$param{'DEBUG'} = $initdebug;
|
||||
|
||||
if (!@paramfiles) {
|
||||
# if there is no list of param files, just go for the default
|
||||
# (usually ./files/infobot.config)
|
||||
|
||||
@paramfiles = ("$param{confdir}/infobot.config");
|
||||
}
|
||||
|
||||
# now read in the parameter files
|
||||
&loadParamFiles(@paramfiles);
|
||||
}
|
||||
|
||||
|
||||
1;
|
@ -0,0 +1,218 @@
|
||||
|
||||
# infobot :: Kevin Lenzo (c) 1997
|
||||
|
||||
##
|
||||
## doStatement --
|
||||
##
|
||||
## decide if $in is a statement, and if so,
|
||||
## - update the dbm
|
||||
## - return feedback statement
|
||||
##
|
||||
## otherwise return null.
|
||||
##
|
||||
|
||||
sub doStatement {
|
||||
return '' if (lc($who) eq lc($param{'nick'}));
|
||||
|
||||
my($msgType, $in) = @_;
|
||||
|
||||
$in =~ s/\\(\S+)/\#$1\#/g;
|
||||
|
||||
# switch person
|
||||
|
||||
$in =~ s/(^|\s)i am /$1$who is /i;
|
||||
$in =~ s/(^|\s)my /$1$who\'s /ig;
|
||||
$in =~ s/(^|\s)your /$1$param{'ident'}\'s /ig;
|
||||
|
||||
if ($addressed) {
|
||||
$in =~ s/(^|\s)you are /$1$param{'ident'} is /i;
|
||||
}
|
||||
|
||||
$in =~ s/^no,\s+//i; # don't want to complain if it's new but negative
|
||||
|
||||
|
||||
if (getparam('plusplus')) {
|
||||
$in =~ s/\W(--|\+\+)(\(.*?\)|[^(++)(--)\s]+)/$2$1/;
|
||||
|
||||
# Hacked to allow multiple karma per line and to fix
|
||||
# related issues. foo++foo++ no longer becomes
|
||||
# foofoo++++. - Masque, 12Apr2K
|
||||
# ...and to allow only one karma point per item
|
||||
# per line. - Masque, 13Apr2K
|
||||
|
||||
my %k_limit;
|
||||
|
||||
while ($in =~ s/(\(.*?\)|[^(++)(--)\s]+)(\+\+|--)//) {
|
||||
my($term,$inc) = ($1,$2);
|
||||
$term = lc($term);
|
||||
next if exists $k_limit{$term};
|
||||
$k_limit{$term} = 1;
|
||||
|
||||
# try to normalize phrases
|
||||
$term =~ s/^\((.*)\)$/$1/;
|
||||
$term =~ s/\s+/ /g;
|
||||
|
||||
if ($msgType !~ /public/i) {
|
||||
&msg($who, "karma must be done in public!");
|
||||
return "NOREPLY";
|
||||
}
|
||||
|
||||
if (lc($term) eq lc($who)) {
|
||||
&msg($who, "please don't karma yourself");
|
||||
return 'NOREPLY';
|
||||
}
|
||||
|
||||
# Whoops! Better make sure that we're adding karma to something existant.
|
||||
next if $term eq "";
|
||||
|
||||
if ($inc eq '++') {
|
||||
&postInc(plusplus => $term);
|
||||
} elsif ($inc eq '--') {
|
||||
&postDec(plusplus => $term);
|
||||
}
|
||||
}
|
||||
return 'NOREPLY' if $karma;
|
||||
}
|
||||
|
||||
my($theType);
|
||||
my($lhs, $mhs, $rhs); # left hand side, uh.. middlehand side...
|
||||
|
||||
# the unignore hack...
|
||||
# if we see this word, unignore all
|
||||
my $magicword=getparam('unignoreWord');
|
||||
if ($in =~ /$magicword/i) {
|
||||
&clearAll('ignore');
|
||||
&status("unignoring all ($who said the word)");
|
||||
}
|
||||
|
||||
# check if we need to be addressed and if we are
|
||||
if ((getparam('addressing') eq 'REQUIRE') && !$addressed) {
|
||||
return 'NOREPLY';
|
||||
}
|
||||
|
||||
# prefix www with http:// and ftp with ftp://
|
||||
$in =~ s/ www\./ http:\/\/www\./ig;
|
||||
$in =~ s/ ftp\./ ftp:\/\/ftp\./ig;
|
||||
|
||||
# look for a "type nugget". this should be externalized.
|
||||
$theType = "";
|
||||
$theType = "mailto" if ($in =~ /\bmailto:.+\@.+\..{2,}/i);
|
||||
$theType = "mailto" if ($in =~ s/\b(\S+\@\S+\.\S{2,})/mailto:$1/gi);
|
||||
$in =~ s/(mailto:)+/mailto:/g;
|
||||
|
||||
$theType = "about" if ($in =~ /\babout:/i);
|
||||
$theType = 'afp' if ($in =~ /\bafp:/);
|
||||
$theType = 'file' if ($in =~ /\bfile:/);
|
||||
$theType = 'palace' if ($in =~ /\bpalace:/);
|
||||
$theType = 'phoneto' if ($in =~ /\bphone(to)?:/);
|
||||
if ($in =~ /\b(news|http|ftp|gopher|telnet):\s*\/\/[\-\w]+(\.[\-\w]+)+/) {
|
||||
$theType = $1;
|
||||
}
|
||||
|
||||
# here's where you set the behaviour.
|
||||
if ((getparam('acceptUrl') =~ /\d+/) && $addressed
|
||||
&& (getparam('acceptUrl') < $theUserLevel)) {
|
||||
} else {
|
||||
if (getparam('acceptUrl') eq 'REQUIRE') {
|
||||
# require url type.
|
||||
# &status("REJECTED non-URL entry") if ($param{VERBOSITY});
|
||||
return 'NOREPLY' if ($theType eq "");
|
||||
} elsif (getparam('acceptUrl') eq 'REJECT') {
|
||||
&status("REJECTED URL entry") if ($param{VERBOSITY});
|
||||
return 'NOREPLY' unless ($theType eq "");
|
||||
} else {
|
||||
# OPTIONAL
|
||||
# you could put another filter here
|
||||
}
|
||||
}
|
||||
|
||||
# report status somewhere is we're doing that
|
||||
&status("type $theType: $in") if $theType;
|
||||
|
||||
foreach $item (@verb) { # check for verb
|
||||
if ($in =~ /(^|\s)$item(\s|$)/i) {
|
||||
($lhs, $mhs, $rhs) = ($`, $&, $');
|
||||
$lhs =~ tr/A-Z/a-z/;
|
||||
$lhs =~ s/^\s*(the|da|an?)\s+//i; # discard article
|
||||
$lhs =~ s/^\s*(.*?)\s*$/$1/;
|
||||
$mhs =~ s/^\s*(.*?)\s*$/$1/;
|
||||
$rhs =~ s/^\s*(.*?)\s*$/$1/;
|
||||
|
||||
# note : prevent access to globals in the eval
|
||||
return '' unless ($lhs and $rhs);
|
||||
|
||||
my $maxkey = getparam("maxKeySize");
|
||||
return "The key is too long (> $maxkey chars)."
|
||||
if (length($lhs) > $maxkey);
|
||||
|
||||
if (length($message) > getparam('maxDataSize')) {
|
||||
if ($msgType =~ /public/) {
|
||||
if ($addressed) {
|
||||
if (rand() > 0.5) {
|
||||
&performSay("that entry is too long, ".$who);
|
||||
} else {
|
||||
&performSay("i'm sorry, but that entry is too long, $who");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
&msg($who, "The text is too long");
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
return 'NOREPLY' if ($lhs eq 'NOREPLY');
|
||||
|
||||
my $failed = 0;
|
||||
$lhs =~ /^(who|what|when|where|why|how)$/ and $failed++;
|
||||
|
||||
if (!$failed and !$addressed) {
|
||||
# the arsenal of things to ignore if we aren't addressed directly
|
||||
|
||||
$lhs =~ /^(who|what|when|where|why|how|it) /i and $failed++;
|
||||
$lhs =~ /^(this|that|these|those|they|you) /i and $failed++;
|
||||
$lhs =~ /^(every(one|body)|we) /i and $failed++;
|
||||
|
||||
$lhs =~ /^\s*\*/ and $failed++; # server message
|
||||
$lhs =~ /^\s*<+[-=]+/ and $failed++; # <--- arrows
|
||||
$lhs =~ /^[\[<\(]\w+[\]>\)]/ and $failed++; # [nick] from bots
|
||||
$lhs =~ /^heya?,? / and $failed++; # greetings
|
||||
$lhs =~ /^\s*th(is|at|ere|ese|ose|ey)/i and $failed++; # contextless
|
||||
$lhs =~ /^\s*it\'?s?\W/i and $failed++; # contextless clitic
|
||||
$lhs =~ /^\s*if /i and $failed++; # hypothetical
|
||||
$lhs =~ /^\s*how\W/i and $failed++; # too much trouble for now
|
||||
$lhs =~ /^\s*why\W/i and $failed++; # too much trouble for now
|
||||
$lhs =~ /^\s*h(is|er) /i and $failed++; # her name is
|
||||
$lhs =~ /^\s*\D[\d\w]*\.{2,}/ and $failed++; # x...
|
||||
$lhs =~ /^\s*so is/i and $failed++; # so is (no referent)
|
||||
$lhs =~ /^\s*s+o+r+[ye]+\b/i and $failed++; # sorry
|
||||
$lhs =~ /^\s*supposedly/i and $failed++;
|
||||
$lhs =~ /^all / and $failed++; # all you have to do, all you guys...
|
||||
} elsif (!$failed and $addressed) {
|
||||
# things to skip if we ARE addressed
|
||||
}
|
||||
|
||||
if ($failed) {
|
||||
&status("statement: IGNORED <$who> $message");
|
||||
return 'NOREPLY';
|
||||
}
|
||||
|
||||
&status("statement: <$who> $message");
|
||||
|
||||
$lhs =~ s/\#(\S+)\#/$1/g;
|
||||
# Avi++
|
||||
$rhs =~ s/\#\|\#/\\\|/g;
|
||||
$rhs =~ s/\#(\S+)\#/$1/g;
|
||||
|
||||
$lhs =~ s/\?+\s*$//; # strip the ? off the key
|
||||
$lhs = &update($lhs, $mhs, $rhs);
|
||||
|
||||
return 'NOREPLY' if ($lhs eq 'NOREPLY');
|
||||
|
||||
last;
|
||||
}
|
||||
}
|
||||
|
||||
$lhs;
|
||||
}
|
||||
|
||||
1;
|
@ -0,0 +1,179 @@
|
||||
|
||||
# infobot :: Kevin Lenzo (c) 1997
|
||||
|
||||
sub update {
|
||||
my($lhs, $verb, $rhs) = @_;
|
||||
my($reply) = $lhs;
|
||||
|
||||
$lhs =~ s/^\s*=?//; # handle dcc =oznoid and stuff
|
||||
$lhs =~ s/^i (heard|think) //i;
|
||||
$lhs =~ s/^some(one|1|body) said //i;
|
||||
$lhs =~ s/ +/ /g;
|
||||
|
||||
# this really needs cleaning up
|
||||
if ($verb eq "is") {
|
||||
$also = ($rhs =~ s/^also //i);
|
||||
|
||||
my $also_or = ($also and $rhs =~ s/\s*\|\s*//);
|
||||
|
||||
if ($exists = &get("is", $lhs)) {
|
||||
chomp $exists;
|
||||
|
||||
if ($exists eq $rhs and not $main::googling) {
|
||||
if ($msgType =~ /public/) {
|
||||
&performSay("i already had it that way, $who.");
|
||||
} else {
|
||||
&msg($who, "it already was $rhs");
|
||||
}
|
||||
return 'NOREPLY';
|
||||
}
|
||||
|
||||
$skipReply = 0;
|
||||
if ($also) {
|
||||
if ($also_or) {
|
||||
$rhs = $exists . '|'.$rhs;
|
||||
} else {
|
||||
if ($exists ne $rhs) {
|
||||
$rhs = $exists .' or '.$rhs;
|
||||
}
|
||||
}
|
||||
if (length($rhs) > getparam('maxDataSize')) {
|
||||
if ($msgType =~ /public/) {
|
||||
if ($addressed) {
|
||||
if (rand() > 0.5) {
|
||||
&performSay("that is too long, ".$who);
|
||||
} else {
|
||||
&performSay("i'm sorry, but that's too long, $who");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
&msg($who, "The text is too long");
|
||||
}
|
||||
return 'NOREPLY';
|
||||
}
|
||||
if ($msgType =~ /public/) {
|
||||
&performSay("okay, $who.");
|
||||
} else {
|
||||
&msg($who, "okay.");
|
||||
}
|
||||
|
||||
$updateCount++;
|
||||
&status("update: <$who> \'$lhs =is=> $rhs\'; was \'$exists\'");
|
||||
&set("is", $lhs, $rhs);
|
||||
} else { # not "also"
|
||||
if (($correction_plausible == 0) && ($exists ne $rhs)) {
|
||||
if ($addressed) {
|
||||
if (not $main::googling) {
|
||||
if ($msgType =~ /public/) {
|
||||
&performSay("...but $lhs is $exists...");
|
||||
} else {
|
||||
&msg($who, "...but $lhs is $exists..");
|
||||
}
|
||||
&status("FAILED update: <$who> \'$lhs =$verb=> $rhs\'");
|
||||
}
|
||||
} else {
|
||||
&status("FAILED update: <$who> \'$lhs =$verb=> $rhs\' (not addressed, no reply)");
|
||||
# we were not addressed, so just
|
||||
# ignore it.
|
||||
return 'NOREPLY';
|
||||
}
|
||||
} else {
|
||||
if (IsFlag("m") ne "m") {
|
||||
performReply("You have no access to change factoids");
|
||||
return 'NOREPLY';
|
||||
}
|
||||
if ($msgType =~ /public/) {
|
||||
&performSay("okay, $who.");
|
||||
} else {
|
||||
&msg($who, "okay.");
|
||||
}
|
||||
$updateCount++;
|
||||
&status("update: <$who> '$lhs =is=> $rhs\'; was \'$exists\'");
|
||||
&set("is", $lhs, $rhs);
|
||||
}
|
||||
}
|
||||
$reply = 'NOREPLY';
|
||||
|
||||
} else {
|
||||
&status("enter: <$who> $lhs =$verb=> $rhs");
|
||||
$updateCount++; $factoidCount++;
|
||||
if ($factoidCount == 31337) { # particular count
|
||||
$mySaveChannel = &channel();
|
||||
&say("That would be factoid $factoidCount given on $mySaveChannel by $who.");
|
||||
&status("FACTOID NUMBER $factoidCount on channel $mySaveChannel by $who.");
|
||||
&say("woohoo!");
|
||||
&channel($mySaveChannel);
|
||||
}
|
||||
&set("is", $lhs, $rhs);
|
||||
$is{"theCount"}++;
|
||||
}
|
||||
|
||||
} else { # 'is' failed
|
||||
if ($verb eq "are") {
|
||||
$also = ($rhs =~ s/^also //i);
|
||||
if ($exists = &get("are", $lhs)) {
|
||||
if ($also) {
|
||||
if ($exists ne $rhs) {
|
||||
$rhs = $exists .' or '.$rhs;
|
||||
}
|
||||
if ($msgType =~ /public/) {
|
||||
&performSay("okay, $who.") unless $rhs eq $exists;
|
||||
} else {
|
||||
&msg($who, "okay.");
|
||||
}
|
||||
$updateCount++;
|
||||
&status("update: <$who> \'$lhs =are=> $rhs\'; was \'$exists\'");
|
||||
&set("are", $lhs, $rhs);
|
||||
} else { # not 'also'
|
||||
if (($correction_plausible == 0) && ($exists ne $rhs)) {
|
||||
if ($addressed) {
|
||||
&status("FAILED update: \'$lhs =$verb=> $rhs\'");
|
||||
if ($msgType =~ /public/) {
|
||||
&performSay("...but $lhs is $exists...");
|
||||
} else {
|
||||
&msg($who, "...but $lhs is $exists..");
|
||||
}
|
||||
} else {
|
||||
&status("FAILED update: $lhs $verb $rhs (not addressed, no reply)");
|
||||
# we were not addressed, so just
|
||||
# ignore it.
|
||||
return 'NOREPLY';
|
||||
}
|
||||
if ($msgType =~ /public/) {
|
||||
&performSay("...but $lhs are $exists...");
|
||||
} else {
|
||||
&msg($who, "...but $lhs are $exists...");
|
||||
}
|
||||
} else {
|
||||
if ($msgType =~ /public/) {
|
||||
&performSay("okay, $who.") unless $rhs eq $exists;
|
||||
} else {
|
||||
&msg($who, "okay.")
|
||||
unless grep $_ eq $who, split /\s+/, $param{friendlyBots};
|
||||
}
|
||||
$updateCount++;
|
||||
&status("update: <$who> \'$lhs =are=> $rhs\'; was \'$exists\'");
|
||||
&set("are", $lhs, $rhs);
|
||||
}
|
||||
$reply = 'NOREPLY';
|
||||
}
|
||||
} else {
|
||||
&status("enter: <$who> $lhs =are=> $rhs");
|
||||
$updateCount++;
|
||||
&set("are", $lhs, $rhs);
|
||||
$are{"theCount"}++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$lhs .= " $verb $rhs";
|
||||
if ($reply ne 'NOREPLY') {
|
||||
$reply = $lhs;
|
||||
}
|
||||
|
||||
return $reply;
|
||||
}
|
||||
|
||||
# ---
|
||||
|
||||
1;
|
@ -0,0 +1,428 @@
|
||||
# all the user stuff
|
||||
#
|
||||
# kevin lenzo
|
||||
#
|
||||
|
||||
sub parseUserfile {
|
||||
$file = $param{'confdir'}.$filesep.$param{'userList'};
|
||||
%user = ();
|
||||
@userList = ();
|
||||
|
||||
open(FH, $file);
|
||||
while (<FH>) {
|
||||
if (!/^#/ && defined $_) {
|
||||
if (/^UserEntry\s+(.+?)\s/) {
|
||||
push @userList, $1;
|
||||
$workname = $1;
|
||||
if (/\s*\{\s*/) {
|
||||
while (<FH>) {
|
||||
if (/^\s*(\w+)\s+(.+);$/) {
|
||||
$opt = $1; $val = $2;
|
||||
$val =~ s/\"//g;
|
||||
if ($opt =~ /^mask$/i) {
|
||||
push @{$workname."masks"}, $val;
|
||||
} elsif ($opt =~ /^flags$/i) {
|
||||
$val =~ s/\+//;
|
||||
$user{$workname."flags"} = $val;
|
||||
} else {
|
||||
$opt =~ tr/A-Z/a-z/;
|
||||
$user{$workname.$opt} = $val;
|
||||
}
|
||||
} elsif (/^\s*\}\s*$/) {
|
||||
last;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
status("parse error: User Entry $workname without right brace");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
my $u;
|
||||
foreach $u (@userList) {
|
||||
status("found user $user: flags +".$user{$u."flags"})
|
||||
if $param{VERBOSITY} > 1;
|
||||
|
||||
if ($param{VERBOSITY} > 2) {
|
||||
my $h;
|
||||
foreach $h (@{$u."masks"}) {
|
||||
status(" -> hostmask: $h");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub IsFlag {
|
||||
my $flags = $_[0];
|
||||
my ($ret, $f, $o);
|
||||
my @ind = split //, $flags;
|
||||
|
||||
foreach $f (split //, $uFlags) {
|
||||
foreach $o (@ind) {
|
||||
if ($f eq $o) {
|
||||
$ret .= $f;
|
||||
last;
|
||||
}
|
||||
}
|
||||
}
|
||||
$ret;
|
||||
}
|
||||
|
||||
sub verifyUser {
|
||||
my $lnuh = $_[0];
|
||||
my ($u, $m);
|
||||
my $VerifWho;
|
||||
|
||||
foreach $u (@userList) {
|
||||
foreach (@{$u."masks"}) {
|
||||
$m = $_;
|
||||
$m =~ s/\*/.*?/g;
|
||||
$m =~ s/([\@\(\)\[\]])/\\$1/g;
|
||||
if ($lnuh =~ /^$m$/i) {
|
||||
$VerifWho = $u;
|
||||
last;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
my $now = time();
|
||||
|
||||
my $m = $message;
|
||||
if ($msgType !~ /public/) {
|
||||
$m = "<private message>";
|
||||
}
|
||||
&set('seen', lc $who, $now.$;.channel().$;.$m);
|
||||
|
||||
if ($VerifWho) {
|
||||
$uFlags = $user{$VerifWho."flags"};
|
||||
$uPasswd = $user{$VerifWho."pass"};
|
||||
$uTitle = $user{$VerifWho."title"};
|
||||
|
||||
if (exists $seenVerif{$VerifWho} and
|
||||
(time()-$seenVerif{$VerifWho} > 360)) {
|
||||
status("mask verified for $VerifWho");
|
||||
}
|
||||
|
||||
$seenVerif{$VerifWho} = $now;
|
||||
}
|
||||
|
||||
return $VerifWho;
|
||||
}
|
||||
|
||||
sub mkpasswd {
|
||||
my $what = $_[0];
|
||||
my $salt = chr(33+rand(64)).chr(33+rand(64));
|
||||
$salt =~ s/:/;/g;
|
||||
|
||||
return crypt($what, $salt);
|
||||
}
|
||||
|
||||
sub ckuser {
|
||||
# returns user level if matched, zero otherwise
|
||||
my ($nuh, $plaintextpass) = @_;
|
||||
if (!$plaintextpass) {
|
||||
($nuh, $plaintextpass) = split(/\s+/, $nuh);
|
||||
}
|
||||
|
||||
return '' unless $nuh;
|
||||
my ($level, $cryptedpass, $rest, $nuh2) = &userinfo($nuh);
|
||||
|
||||
if (&ckpasswd($plaintextpass, $cryptedpass)) {
|
||||
# password matched for user nick!user@host
|
||||
&status("confirmed user: $nuh");
|
||||
return $level;
|
||||
} else {
|
||||
# no match
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
sub ckpasswd {
|
||||
# returns true if arg1 encrypts to arg2
|
||||
my ($plain, $encrypted) = @_;
|
||||
if (!$encrypted) {
|
||||
($plain, $encrypted) = split(/\s+/, $plain, 2);
|
||||
}
|
||||
return '' unless ($plain && $encrypted);
|
||||
return ($encrypted eq crypt($plain, $encrypted));
|
||||
}
|
||||
|
||||
sub userinfo {
|
||||
my $lnuh = $_[0];
|
||||
my $k;
|
||||
|
||||
if (!$lnuh) {
|
||||
$lnuh = $nuh;
|
||||
}
|
||||
foreach $k (keys %userList) {
|
||||
my $n = $k;
|
||||
$n =~ s/\*/.*/g;
|
||||
$n =~ s/([\@\(\)\[\]])/\\$1/g;
|
||||
|
||||
if ($lnuh =~ /^$n$/i) {
|
||||
# this may expand later
|
||||
my ($userlevel, $pass, $rest) = split(/:/, $userList{$k}, 3);
|
||||
return ($userlevel, $pass, $rest, $k);
|
||||
}
|
||||
}
|
||||
return ();
|
||||
}
|
||||
|
||||
sub users {
|
||||
my @stuff;
|
||||
foreach (sort keys %userList) {
|
||||
push(@stuff, "$_ => $userList{$_}\n");
|
||||
}
|
||||
return @stuff;
|
||||
}
|
||||
|
||||
sub adduser {
|
||||
my($nuh, $level, $plainpass, $rest) = @_;
|
||||
if (!$level) {
|
||||
($nuh, $level, $plainpass, $rest) = split(/\s+/, $nuh, 4);
|
||||
}
|
||||
if (!$plainpass && ($level =~ /\D/)) {
|
||||
my $x = $level;
|
||||
if ($plainpass =~ /^\D+/) {
|
||||
$level = $plainpass;
|
||||
$plainpass = $level;
|
||||
}
|
||||
}
|
||||
|
||||
if (($level =~ /^\d+/) && $plainpass) {
|
||||
my $cryptedpass = mkpasswd($plainpass);
|
||||
my $i = join(":", $level, $cryptedpass, $rest);
|
||||
$userLevel{$nuh} = $i;
|
||||
&status("user $nuh added at level $i");
|
||||
return "user $nuh added at level $i";
|
||||
} else {
|
||||
&status("bad params to adduser");
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
sub writeUserFile {
|
||||
my $where = $_[0];
|
||||
chomp $where;
|
||||
if (!$where) {
|
||||
$where = $param{'confdir'}.$filesep.$param{'userList'};
|
||||
}
|
||||
if (!$where) {
|
||||
return "no file given and no param set for writing user file\n";
|
||||
}
|
||||
if (open(UF, ">$where")) {
|
||||
foreach (sort keys %userLevel) {
|
||||
print UF "$_:$userLevel{$_}\n";
|
||||
}
|
||||
close UF;
|
||||
&status("wrote user file to $where");
|
||||
return "wrote user file";
|
||||
} else {
|
||||
&status("failed to write user file to $where");
|
||||
return "couldn't write user file";
|
||||
}
|
||||
}
|
||||
|
||||
sub changepass {
|
||||
my ($nuh, $oldpass, $newpass) = @_;
|
||||
|
||||
if (&ckuser($nuh, $oldpass)) {
|
||||
my $cryptednew = mkpasswd($newpass);
|
||||
my ($level, $pass, $rest, $nuh2) = &userinfo($nuh);
|
||||
my $i = join(":", $level, $newpass, $rest);
|
||||
$userList{$nuh2} = $i;
|
||||
&status("password changed for $nuh");
|
||||
return "password changed for $nuh";
|
||||
} else {
|
||||
&status("password change failed for $nuh");
|
||||
return "password did not match you: $nuh";
|
||||
}
|
||||
}
|
||||
|
||||
sub removeuser {
|
||||
my $nuh = $_[0];
|
||||
|
||||
if ($userList{$nuh}) {
|
||||
delete $userList{$nuh};
|
||||
&status("deleted $nuh from userlist");
|
||||
return "deleted $nuh from the userlist";
|
||||
} else {
|
||||
return 'No match for $nuh';
|
||||
}
|
||||
}
|
||||
|
||||
sub setlevel {
|
||||
my ($nuh, $newlevel) = @_;
|
||||
if (!$newlevel) {
|
||||
($nuh, $newlevel) = split(/\s+/, $nuh, 2);
|
||||
}
|
||||
my ($level, $pass, $rest, $nuh2) = &userinfo($nuh);
|
||||
if ($newlevel !~ /^\d+/) {
|
||||
return "bad user level: $newlevel";
|
||||
}
|
||||
if ($userList{$nuh}) {
|
||||
($level, $pass, $rest) = split(/:/, $userList{$nuh});
|
||||
$nuh2 = $nuh;
|
||||
}
|
||||
if ($nuh2) {
|
||||
my $i = join(":", $newlevel, $pass, $rest);
|
||||
$userList{$nuh2} = $i;
|
||||
&status("level for $nuh changed to $newlevel (was $level)");
|
||||
} else {
|
||||
&status("no match for $nuh");
|
||||
}
|
||||
0;
|
||||
}
|
||||
|
||||
sub userProcessing {
|
||||
my $now = time();
|
||||
|
||||
if ($VerifWho) {
|
||||
if ($msgType =~ /private/) {
|
||||
my $unverified_message = "you must identify yourself; /msg $param{nick} <pass> <command>";
|
||||
|
||||
if (IsFlag("e")) { # eval
|
||||
if ($message =~ s/^(\S+) eval//) {
|
||||
if (!exists $verified{$VerifWho}) {
|
||||
&status("unverified <$who> $message");
|
||||
&msg($who, $unverified_message);
|
||||
return 'NOREPLY';
|
||||
}
|
||||
my ($pass, $m) = ($1, $message);
|
||||
$_ = "";
|
||||
&msg($who, "WARNING: exposed eval security risk");
|
||||
$x = eval($m);
|
||||
&msg($who, $x);
|
||||
}
|
||||
}
|
||||
|
||||
if (IsFlag("o")) { # owner/operator flag
|
||||
if ($message =~ /^die/) {
|
||||
if (!exists $verified{$VerifWho}) {
|
||||
&status("unverified <$who> $message");
|
||||
&msg($who, $unverified_message);
|
||||
return 'NOREPLY';
|
||||
}
|
||||
&rawout("QUIT :$who");
|
||||
&closeDBMAll();
|
||||
sleep 2;
|
||||
status("Dying by $who\'s request");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if ($message =~ /^reload$/i) {
|
||||
if (!exists $verified{$VerifWho}) {
|
||||
&status("unverified <$who> $message");
|
||||
&msg($who, $unverified_message);
|
||||
return 'NOREPLY';
|
||||
}
|
||||
&status("RELOAD <$who>");
|
||||
opendir DIR, $infobot_src_dir;
|
||||
while ($file = readdir DIR) {
|
||||
next unless $file =~ /\.pl$/;
|
||||
next if $file eq 'Process.pl';
|
||||
if (!do $file) {
|
||||
&status("Error reloading $file: "
|
||||
. ($@ || "did not return a true value"));
|
||||
}
|
||||
}
|
||||
close DIR;
|
||||
&msg($who, "reloaded init files");
|
||||
return 'NOREPLY';
|
||||
}
|
||||
|
||||
if ($message =~ /^rehash$/i) {
|
||||
if (!exists $verified{$VerifWho}) {
|
||||
&status("unverified <$who> $message");
|
||||
&msg($who, $unverified_message);
|
||||
return 'NOREPLY';
|
||||
}
|
||||
&status("REHASH <$who>\n");
|
||||
&setup();
|
||||
&msg($who, "rehashed");
|
||||
return 'NOREPLY';
|
||||
}
|
||||
|
||||
if ($message =~ /^modes$/) {
|
||||
if (!exists $verified{$VerifWho}) {
|
||||
&status("unverified <$who> $message");
|
||||
&msg($who, $unverified_message);
|
||||
return 'NOREPLY';
|
||||
}
|
||||
my ($chan, $mode, $user, $msg, $m1);
|
||||
foreach $chan (keys %channels) {
|
||||
my $msg = "$chan: ";
|
||||
foreach $mode (keys %{$channels{$chan}}) {
|
||||
my $m1 = $msg." $mode: ";
|
||||
foreach $user (keys %{$channels{$chan}{$mode}}) {
|
||||
$m1 .= "$user ";
|
||||
}
|
||||
&msg($who, $m1);
|
||||
}
|
||||
}
|
||||
return 'NOREPLY';
|
||||
}
|
||||
}
|
||||
|
||||
if (IsFlag("p") eq "p") { # oP on channel
|
||||
if ($message =~ s/^op( me)?$//i or $message =~ s/^op //i) {
|
||||
if (!exists $verified{$VerifWho}) {
|
||||
&status("unverified <$who> $message");
|
||||
&msg($who, $unverified_message);
|
||||
return 'NOREPLY';
|
||||
}
|
||||
&status("trying to op $who at their request");
|
||||
foreach $chan (keys %channels) {
|
||||
if ($message) {
|
||||
&op($chan, $message);
|
||||
} else {
|
||||
&op($chan, $who);
|
||||
}
|
||||
}
|
||||
return 'NOREPLY';
|
||||
}
|
||||
my $regex = 0;
|
||||
|
||||
if ($message =~ /^ignore\s+(.*)/) {
|
||||
my $what = $1;
|
||||
|
||||
&postInc(ignore => $what);
|
||||
&status("ignoring $what at $VerifWho's request");
|
||||
&msg($who, "added $what to the ignore list");
|
||||
|
||||
return 'NOREPLY';
|
||||
}
|
||||
|
||||
if ($message =~ /^ignorelist$/) {
|
||||
&status("$who asked for the ignore list");
|
||||
my $all = join " ", &getDBMKeys('ignore');
|
||||
while (length($all) > 200) {
|
||||
$all =~ s/(.{0,200}) //;
|
||||
&msg($who, $1);
|
||||
}
|
||||
&msg($who, $all);
|
||||
return 'NOREPLY';
|
||||
}
|
||||
|
||||
if ($message =~ /^unignore\s+(.*)/) {
|
||||
my $what = $1;
|
||||
|
||||
if (&clear(ignore => $what)) {
|
||||
&status("unignoring $what at $VerifWho's request");
|
||||
&msg($who, "removed $what from the ignore list");
|
||||
} else {
|
||||
&status("unignore FAILED for $1 at $who's request");
|
||||
&msg($who, "no entry for $1 on the ignore list");
|
||||
}
|
||||
return 'NOREPLY';
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$uFlags = $user{"defaultflags"};
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
|
@ -0,0 +1,120 @@
|
||||
# $Id: Util.pm,v 1.1 2000/11/01 22:40:50 lenzo Exp $
|
||||
|
||||
use strict;
|
||||
|
||||
package Util;
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Util - infobot utility functions
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
export_to_main qw(func &func2 $scalar @array %hash);
|
||||
import_from_main qw(func &func2 $scalar @array %hash);
|
||||
import_export $from_pkg, $to_pkg, @symbol;
|
||||
|
||||
process_args \@arg_list, myarg => \$myvar, %more_pairs or die;
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This module provides some utility functions for the B<infobot>.
|
||||
|
||||
=cut
|
||||
|
||||
use Carp qw(croak);
|
||||
use Exporter ();
|
||||
|
||||
use vars qw($VERSION @ISA @EXPORT_OK);
|
||||
|
||||
$VERSION = do{my@r=q$Revision: 1.1 $=~/\d+/g;sprintf '%d.'.'%03d'x$#r,@r};
|
||||
|
||||
@ISA = qw(Exporter);
|
||||
@EXPORT_OK = qw(
|
||||
export_to_main
|
||||
import_export
|
||||
import_from_main
|
||||
process_args
|
||||
);
|
||||
|
||||
=head1 IMPORTABLE SYMBOLS
|
||||
|
||||
=over 4
|
||||
|
||||
=cut
|
||||
|
||||
sub import_export {
|
||||
my ($from_pkg, $to_pkg, @symbol) = @_;
|
||||
my ($symbol, $type, $name, $code);
|
||||
|
||||
$code = "package $to_pkg;\n";
|
||||
for $symbol (@symbol) {
|
||||
($type, $name) = $symbol =~ /^([\$\@%&])?(\w+)$/
|
||||
or croak "Invalid symbol `$symbol'";
|
||||
$type ||= '&';
|
||||
$code .= "*$name = \\$type${from_pkg}::$name;\n";
|
||||
}
|
||||
print $code if 0;
|
||||
|
||||
{
|
||||
no strict 'refs';
|
||||
eval $code;
|
||||
die if $@;
|
||||
}
|
||||
}
|
||||
|
||||
sub export_to_main {
|
||||
my @symbol = @_;
|
||||
import_export scalar(caller), 'main', @symbol;
|
||||
}
|
||||
|
||||
sub import_from_main {
|
||||
my @symbol = @_;
|
||||
import_export 'main', scalar(caller), @symbol;
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
|
||||
BEGIN {
|
||||
import_from_main qw(status);
|
||||
}
|
||||
|
||||
sub process_args {
|
||||
my ($rarg, %desc) = @_;
|
||||
|
||||
my $caller_sub = (caller 1)[3];
|
||||
my $fail = 0;
|
||||
|
||||
while (@$rarg > 1) {
|
||||
my ($key, $val) = splice @$rarg, 0, 2;
|
||||
if ($desc{$key}) {
|
||||
${ $desc{$key} } = $val;
|
||||
} else {
|
||||
status "$caller_sub: invalid arg `$key'";
|
||||
$fail = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (@$rarg) {
|
||||
status "$caller_sub: ignoring trailing value-less arg `$rarg->[0]'";
|
||||
$fail = 1;
|
||||
}
|
||||
|
||||
return !$fail;
|
||||
}
|
||||
|
||||
1
|
||||
|
||||
__END__
|
||||
|
||||
=back
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Roderick Schertler <F<roderick@argon.org>>
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
infobot(1), perl(1).
|
||||
|
||||
=cut
|
Loading…
Reference in New Issue