# Part of Acrobat.
-import string, cPickle, random, urllib, sys
+import string, cPickle, random, urllib, sys, time, re, os
from irclib import irc_lower, nm_to_n
# query karma
-def karmaq(bot, cmd, nick, conn, public):
- # in public
- if public == 1:
- try:
- if bot.karma.dict.has_key(cmd.split()[1]):
- conn.privmsg(bot.channel, "%s has karma %s."
- %(cmd.split()[1],
- bot.karma.dict[cmd.split()[1]]))
- else:
- conn.privmsg(bot.channel, "%s has no karma set." %
- cmd.split()[1])
- except IndexError:
- conn.privmsg(bot.channel, "I have karma on %s items." %
- len(bot.karma.dict.keys()))
- # in private
- else:
- try:
- if bot.karma.dict.has_key(cmd.split()[1]):
- conn.notice(nick, "%s has karma %s." %
- (cmd.split()[1],
- bot.karma.dict[cmd.split()[1]]))
- else:
- conn.notice(nick, "I have karma on %s items." %
- len(bot.karma.dict.keys()))
- except IndexError:
- conn.notice(nick, "I have karma on %s items." %
- len(bot.karma.dict.keys()))
-# query bot status
-def infoq(bot, cmd, nick, conn, public):
- if public == 1:
- conn.privmsg(bot.channel,
- "I am Acrobat %s, on %s, as nick %s." %
- (bot.revision.split()[1], bot.channel, conn.get_nickname()))
- conn.privmsg(bot.channel,
- "My owner is %s; I have karma on %s items." %
- (bot.owner, len(bot.karma.dict.keys())))
+def karmaq(bot, cmd, nick, conn, public, karma):
+ try:
+ item=cmd.split()[1].lower()
+ except IndexError:
+ item=None
+ if item==None:
+ bot.automsg(public,nick,"I have karma on %s items." %
+ len(karma.keys()))
+ elif karma.has_key(item):
+ bot.automsg(public,nick,"%s has karma %s."
+ %(item,karma[item]))
else:
- conn.notice(nick, "I am Acrobat %s, on %s, as nick %s." %
- (bot.revision.split()[1], bot.channel, conn.get_nickname()))
- conn.notice(nick, "My owner is %s; I have karma on %s items." %
- (bot.owner, len(bot.karma.dict.keys())))
+ bot.automsg(public,nick, "%s has no karma set." % item)
-# trout someone
-def troutq(bot, cmd, nick, conn, public):
+# delete karma
+def karmadelq(bot, cmd, nick, conn, public, karma):
try:
- target = string.join(cmd.split()[1:])
- me = bot.connection.get_nickname()
- trout_msg = random.choice(bot.trouts)
- # The bot won't trout itself;
- if irc_lower(me) == irc_lower(target):
- target = nick
- conn.action(bot.channel, trout_msg % target)
- if public == 0:
- if random.random() <= bot.config.selftroutrisk:
- conn.action(bot.channel,
- "notes %s is conducting a whispering campaign." % nick)
+ item=cmd.split()[1].lower()
except IndexError:
- conn.notice(nick, "Who do you wish me to trout?")
+ conn.notice(nick, "What should I delete?")
+ return
+ if nick != bot.owner:
+ conn.notice(nick, "You are not my owner.")
+ return
+ if karma.has_key(item):
+ del karma[item]
+ conn.notice(nick, "Item %s deleted."%item)
+ else:
+ conn.notice(nick, "There is no karma stored for %s."%item)
+
+# help - provides the URL of the help file
+def helpq(bot, cmd, nick, conn, public):
+ bot.automsg(public,nick,
+ "For help see http://www.pick.ucam.org/~matthew/irc/servus.html")
+
+
+# query bot status
+def infoq(bot, cmd, nick, conn, public, karma):
+ bot.automsg(public,nick,
+ ("I am Acrobat %s, on %s, as nick %s. "+
+ "My owner is %s; I have karma on %s items.") %
+ (bot.revision.split()[1], bot.channel, conn.get_nickname(),
+ bot.owner, len(karma.keys())))
+
+# Check on fish stocks
+def fish_quota(pond):
+ if pond.DoS:
+ if time.time()>=pond.quotatime:
+ pond.DoS=0
+ else:
+ return
+ if (time.time()-pond.quotatime)>pond.fish_time_inc:
+ pond.cur_fish+=(((time.time()-pond.quotatime)
+ /pond.fish_time_inc)*pond.fish_inc)
+ if pond.cur_fish>pond.max_fish:
+ pond.cur_fish=pond.max_fish
+ pond.quotatime=time.time()
+
+# trout someone, or flirt with them
+def troutq(bot, cmd, nick, conn, public, cfg):
+ fishlist=cfg[0]
+ selftrout=cfg[1]
+ quietmsg=cfg[2]
+ notargetmsg=cfg[3]
+ nofishmsg=cfg[4]
+ fishpond=cfg[5]
+ selftroutchance=cfg[6]
+
+ fish_quota(fishpond)
+ if fishpond.DoS:
+ conn.notice(nick, quietmsg%fishpond.Boring_Git)
+ return
+ if fishpond.cur_fish<=0:
+ conn.notice(nick, nofishmsg)
+ return
+ target = string.join(cmd.split()[1:])
+ if len(target)==0:
+ conn.notice(nick, notargetmsg)
+ return
+ me = bot.connection.get_nickname()
+ trout_msg = random.choice(fishlist)
+ # The bot won't trout or flirt with itself;
+ if irc_lower(me) == irc_lower(target):
+ target = nick
+ # There's a chance the game may be given away if the request was not
+ # public...
+ if not public:
+ if random.random()<=selftroutchance:
+ trout_msg=trout_msg+(selftrout%nick)
+
+ conn.action(bot.channel, trout_msg % target)
+ fishpond.cur_fish-=1
+
+# slash a pair
+def slashq(bot, cmd, nick, conn, public, cfg):
+ fishlist=cfg[0]
+ selfslash=cfg[1]
+ quietmsg=cfg[2]
+ notargetmsg=cfg[3]
+ nofishmsg=cfg[4]
+ fishpond=cfg[5]
+ selfslashchance=cfg[6]
+
+ fish_quota(fishpond)
+ if fishpond.DoS:
+ conn.notice(nick, quietmsg%fishpond.Boring_Git)
+ return
+ if fishpond.cur_fish<=0:
+ conn.notice(nick, nofishmsg)
+ return
+ target = string.join(cmd.split()[1:])
+ #who = cmd.split()[1:]
+ who = ' '.join(cmd.split()[1:]).split(' / ')
+ if len(who) < 2:
+ conn.notice(nick, "it takes two to tango!")
+ return
+ elif len(who) > 2:
+ conn.notice(nick, "we'll have none of that round here")
+ return
+ me = bot.connection.get_nickname()
+ slash_msg = random.choice(fishlist)
+ # The bot won't slash people with themselves
+ if irc_lower(who[0]) == irc_lower(who[1]):
+ conn.notice(nick, "oooooh no missus!")
+ return
+ # The bot won't slash with itself, instead slashing the requester
+ for n in [0,1]:
+ if irc_lower(me) == irc_lower(who[n]):
+ who[n] = nick
+ # Perhaps someone asked to slash themselves with the bot then we get
+ if irc_lower(who[0]) == irc_lower(who[1]):
+ conn.notice(nick, "you wish!")
+ return
+ # There's a chance the game may be given away if the request was not
+ # public...
+ if not public:
+ if random.random()<=selfslashchance:
+ slash_msg=slash_msg+(selfslash%nick)
+
+ conn.action(bot.channel, slash_msg % (who[0], who[1]))
+ fishpond.cur_fish-=1
+
+#query units
+def unitq(bot, cmd, nick, conn, public):
+ args = ' '.join(cmd.split()[1:]).split(' as ')
+ if len(args) != 2:
+ args = ' '.join(cmd.split()[1:]).split(' / ')
+ if len(args) != 2:
+ conn.notice(nick, "syntax: units arg1 as arg2")
+ return
+ if args[1]=='?':
+ sin,sout=os.popen2(["units","--verbose",args[0]],"r")
+ else:
+ sin,sout=os.popen2(["units","--verbose",args[0],args[1]],"r")
+ sin.close()
+ res=sout.readlines()
+ #popen2 doesn't clean up the child properly. Do this by hand
+ child=os.wait()
+ if os.WEXITSTATUS(child[1])==0:
+ bot.automsg(public,nick,res[0].strip())
+ else:
+ conn.notice(nick,'; '.join(map(lambda x: x.strip(),res)))
+
+# Shut up trouting for a minute
+def nofishq(bot, cmd, nick, conn, public, fish):
+ fish.cur_fish=0
+ fish.DoS=1
+ fish.Boring_Git=nick
+ fish.quotatime=time.time()
+ fish.quotatime+=fish.nofish_time
+ conn.notice(nick, "Fish stocks depleted, as you wish.")
# rehash bot config
def reloadq(bot, cmd, nick, conn, public):
- if irc_lower(nick) == irc_lower(bot.owner):
+ if not public and irc_lower(nick) == irc_lower(bot.owner):
try:
reload(bot.config)
- bot.trouts = bot.config.trouts
- conn.privmsg(nick, "Config reloaded.")
+ conn.notice(nick, "Config reloaded.")
except ImportError:
conn.notice(nick, "Config reloading failed!")
else:
- conn.notice(nick, "This command can only be invoked by my owner.")
+ bot.automsg(public,nick,
+ "Configuration can only be reloaded by my owner, by /msg.")
+
+# lose the game and/or install a new trigger word
+def gameq(bot, cmd, nick, conn, public, game):
+ #only install a new trigger if it's not too short.
+ if len(' '.join(cmd.split()[1:]))>2:
+ game.trigger=' '.join(cmd.split()[1:])
+ if (time.time()> game.grace):
+ if not public:
+ if irc_lower(nick) == irc_lower(bot.owner):
+ conn.action(bot.channel,"loses the game!")
+ else:
+ conn.privmsg(bot.channel,nick+" just lost the game!")
+ else:
+ if not public:
+ conn.notice(nick, "It's a grace period!")
+ game.grace=time.time()+60*20 #20 minutes' grace
+ game.losetime=time.time()+random.randrange(game.minlose,game.maxlose)
+ conn.notice(bot.owner, str(game.losetime-time.time())+" "+game.trigger)
# quit irc
def quitq(bot, cmd, nick, conn, public):
if irc_lower(nick) == irc_lower(bot.owner):
- try:
- f = open(bot.karmafilename, "w")
- cPickle.dump(bot.karma, f)
- f.close()
- except IOError:
- sys.stderr.write("Problems dumping karma: probably lost :(")
bot.die(msg = "I have been chosen!")
- elif public == 1:
- conn.privmsg(nick, "Such aggression in public!")
+ elif public:
+ conn.notice(nick, "Such aggression in public!")
else:
conn.notice(nick, "You're not my owner.")
# google for something
def googleq(bot, cmd, nick, conn, public):
cmdrest = string.join(cmd.split()[1:])
- #sys.stderr.write(conn)
# "I'm Feeling Lucky" rather than try and parse the html
targ = ("http://www.google.com/search?q=%s&btnI=I'm+Feeling+Lucky"
% urllib.quote_plus(cmdrest))
# get redirected and grab the resulting url for returning
gsearch = urllib.urlopen(targ).geturl()
if gsearch != targ: # we've found something
- if public == 0:
- conn.notice(nick, str(gsearch))
- else: # we haven't found anything.
- conn.privmsg(nick, str(gsearch))
- else:
- if public == 0:
- conn.notice(nick, "No pages found.")
- else:
- conn.privmsg(nick, "No pages found.")
+ bot.automsg(public,nick,str(gsearch))
+ else: # we haven't found anything.
+ bot.automsg(public,nick,"No pages found.")
except IOError: # if the connection times out. This blocks. :(
- if public == 0:
- conn.notice(nick, "The web's broken. Waah!")
+ bot.automsg(public,nick,"The web's broken. Waah!")
+
+# Look up the definition of something using google
+def defineq(bot, cmd, nick, conn, public):
+ cmdrest = string.join(cmd.split()[1:])
+ targ = ("http://www.google.com/search?q=define%%3A%s&ie=utf-8&oe=utf-8"
+ % urllib.quote_plus(cmdrest))
+ try:
+ # Just slurp everything into a string
+ defnpage = urllib.urlopen(targ).read()
+ # For definitions we really do have to parse the HTML, sadly.
+ # This is of course going to be a bit fragile. We first look for
+ # 'Definitions of %s on the Web' -- if this isn't present we
+ # assume we have the 'no definitions found page'.
+ # The first defn starts after the following <p> tag.
+ # Following that we assume that each definition is all the non-markup
+ # before a <br> tag. Currently we just dump out the first definition.
+ match = re.search(r"Definitions of <b>.*?</b> on the Web.*?<p>\s*([^>]*)<br>",defnpage,re.MULTILINE)
+ if match == None:
+ bot.automsg(public,nick,"Some things defy definition.")
else:
- conn.privmsg(nick, "The web's broken. Waah!")
+ # We assume google has truncated the definition for us so this
+ # won't flood the channel with text...
+ defn = " ".join(match.group(1).split("\n"));
+ bot.automsg(public,nick,defn)
+ except IOError: # if the connection times out. This blocks. :(
+ bot.automsg(public,nick,"The web's broken. Waah!")
### say to msg/channel
def sayq(bot, cmd, nick, conn, public):
if irc_lower(nick) == irc_lower(bot.owner):
conn.privmsg(bot.channel, string.join(cmd.split()[1:]))
else:
- conn.privmsg(nick, "You're not my owner!")
+ if not public:
+ conn.notice(nick, "You're not my owner!")
### action to msg/channel
def doq(bot, cmd, nick, conn, public):
sys.stderr.write(irc_lower(bot.owner))
sys.stderr.write(irc_lower(nick))
- if public == 0:
+ if not public:
if irc_lower(nick) == irc_lower(bot.owner):
conn.action(bot.channel, string.join(cmd.split()[1:]))
else:
- conn.privmsg(nick, "You're not my owner!")
+ conn.notice(nick, "You're not my owner!")
###disconnect
def disconnq(bot, cmd, nick, conn, public):
if cmd == "disconnect": # hop off for 60s
bot.disconnect(msg="Be right back.")
+### list keys of a dictionary
+def listkeysq(bot, cmd, nick, conn, public, dict, sort=False):
+ d=dict.keys()
+ if sort:
+ d.sort()
+ bot.automsg(public,nick,string.join(d))
+
+### rot13 text (yes, I could have typed out the letters....)
+### also "foo".encode('rot13') would have worked
+def rot13q(bot, cmd, nick, conn, public):
+ a=''.join(map(chr,range((ord('a')),(ord('z')+1))))
+ b=a[13:]+a[:13]
+ trans=string.maketrans(a+a.upper(),b+b.upper())
+ conn.notice(nick, string.join(cmd.split()[1:]).translate(trans))