chiark / gitweb /
Found in /home/matthew/programming/irc/bot - live version, all files as found
[irc.git] / commands.py
index 6f6d1f73dc3f5ff265f86a1825d549517b36b557..4bdc45ce01dcc632ae861a4194ced4a9f5c48aed 100644 (file)
 # 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))
@@ -100,40 +224,69 @@ def googleq(bot, cmd, nick, conn, public):
         # 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):
+    bot.automsg(public,nick,string.join(dict.keys()))
+
+### 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))