-#!/usr/bin/env python2
-# $Id: acrobat-chiark-0.2.py,v 1.20 2002/10/06 16:04:42 matthew Exp $
-#
-# Joel Rosdahl <joel@rosdahl.net>
-# Andrew Walkingshaw <andrew@lexical.org.uk>
-# Peter Corbett <ptc24@cam.ac.uk>
-# Matthew Vernon <matthew@debian.org>
-#
-# This file is part of Acrobat.
-#
-# Acrobat is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published
-# by the Free Software Foundation; either version 2 of the License,
-# or (at your option) any later version.
-#
-# Acrobat is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-
-# You should have received a copy of the GNU General Public License
-# along with Acrobat; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
-# USA.
-
-"""
- disconnect -- Disconnect the bot. The bot will try to reconnect
- after 60 seconds.
-
- die -- Let the bot cease to exist.
-
- google -- search, 'I'm Feeling Lucky', and notice the user who searches
- back with the url.
-"""
-
-import string, urllib, sys, cPickle, os, random, re, time
-from ircbot import SingleServerIRCBot
-from irclib import nm_to_n, irc_lower
-
-
-
-class Karma:
- def __init__(self):
- self.dict = {}
-
-class Acrobat(SingleServerIRCBot):
- def __init__(self, channel, nickname, server, owner, port=6667):
- SingleServerIRCBot.__init__(self,
- [(server, port)], nickname, nickname)
- self.channel = channel
- self.owner = owner
- self.quotatime = time.time()
- #List of known !commands we respond to
- self.known =['karma','trout','info','die','quiet','list','google','say','do','reload','flirt']
- #Configurable stuff - how often do we add how many fish?
- self.cur_fish=5
- self.max_fish=5 #Maximum of 5 fish
- self.fish_time_inc=60 #Add fish with 20s granularity
- self.fish_inc=2 #Rate of increase is 2 fish per 60s
- self.DoS=0 #Have we been told to shut up?
- self.Boring_Git='Nobody' #Who told us to shut up?
- # load the karma db
- try:
- f = open("karmadump", "r")
- self.karma = cPickle.load(f)
- f.close()
- except IOError:
- self.karma = Karma()
- try:
- f = open("trouts", "r")
- self.trouts = [l.strip() for l in f.readlines() if l.find("%s") != -1]
- f.close()
- except IOError:
- self.trouts = [ "hits %s with a wet trout.", "thwaps %s.", "questions %s's parentage.", "pokes its tounge out at %s.", "bites its thumb at %s."]
- try:
- f = open("flirts", "r")
- self.flirts = [l.strip() for l in f.readlines() if l.find("%s") != -1]
- f.close()
- except IOError:
- self.flirts = [ "falls madly in love with %s", "blows kisses at %s"]
-
- ## EVENT HANDLERS
-
- def on_welcome(self, conn, evt):
- conn.join(self.channel)
-
- def on_privmsg(self, conn, evt):
- self.do_command(nm_to_n(evt.source()), evt.arguments()[0])
-
- def on_pubmsg(self, conn, evt):
- payload = evt.arguments()[0]
- a = string.split(evt.arguments()[0], " ", 1)
- if len(a) > 1 \
- and (irc_lower(a[0]) == irc_lower(self.connection.get_nickname())
- or irc_lower(a[0])[:-1] == irc_lower(self.connection.get_nickname())):
-
- self.do_command(nm_to_n(evt.source()), string.strip(a[1]), public = 1)
- if a[0].endswith("++"):
- self.karmaup(a[0])
- if a[0].endswith("--"):
- self.karmadown(a[0])
- if payload[0] == "!" and len(payload)>1:
- self.do_command(nm_to_n(evt.source()), string.strip(payload[1:]), public=1)
- if payload[0] == "~" and len(payload)>1:
- self.do_command(nm_to_n(evt.source()), string.strip(payload[1:]), public=1)
-
- # And now bot commands;
-
- # increment karma
- def karmaup(self, cmd):
- if self.karma.dict.has_key(cmd.split()[0][:-2]):
- self.karma.dict[cmd.split()[0][:-2]] += 1
- else:
- self.karma.dict[cmd.split()[0][:-2]] = 1
-
- #decrement karma
- def karmadown(self, cmd):
- if self.karma.dict.has_key(cmd.split()[0][:-2]):
- self.karma.dict[cmd.split()[0][:-2]] -= 1
- else:
- self.karma.dict[cmd.split()[0][:-2]] = -1
-
- # query karma
- def karmaq(self, cmd, conn, nick, public):
- # in public
- if public == 1:
- try:
- if self.karma.dict.has_key(cmd.split()[1]):
- conn.privmsg(self.channel, "%s has karma %s."
- %(cmd.split()[1],
- self.karma.dict[cmd.split()[1]]))
- else:
- conn.privmsg(self.channel, "%s has no karma set." %
- cmd.split()[1])
- except IndexError:
- conn.privmsg(self.channel, "I have karma on %s items." %
- len(self.karma.dict.keys()))
- # in private
- else:
- try:
- if self.karma.dict.has_key(cmd.split()[1]):
- conn.notice(nick, "%s has karma %s." %
- (cmd.split()[1],
- self.karma.dict[cmd.split()[1]]))
- else:
- conn.notice(nick, "I have karma on %s items." %
- len(self.karma.dict.keys()))
- except IndexError:
- conn.notice(nick, "I have karma on %s items." %
- len(self.karma.dict.keys()))
- # query bot status
- def infoq(self, cmd, nick, conn, public):
- # version control magic
- acrorevision="$Revision: 1.20 $"
- acrorev1=re.sub(r'\$Revision: (.*)',r'\1',acrorevision)
- acroversion=re.sub(r'(.*) \$',r'\1',acrorev1)
- if public == 1:
- conn.privmsg(self.channel,
- "I am Acrobat %s, on %s, as nick %s." %
- (acroversion, self.channel, self.connection.get_nickname()))
- conn.privmsg(self.channel,
- "My owner is %s; I have karma on %s items." %
- (self.owner, len(self.karma.dict.keys())))
- else:
- conn.notice(nick, "I am Acrobat %s, on %s, as nick %s." %
- (acroversion, self.channel, self.connection.get_nickname()))
- conn.notice(nick, "My owner is %s; I have karma on %s items." %
- (self.owner, len(self.karma.dict.keys())))
-
- # list know commands
- def listq(self, cmd, nick, conn, public):
- conn.notice(nick, "%s" % string.join(self.known))
- # flirt with someone
- def flirtq(self, cmd, nick, conn, public):
- self.fish_quota()
- if self.DoS == 1:
- conn.notice(nick, "Sorry, but %s made me take Holy Orders." %
- self.Boring_Git)
- return
- if self.cur_fish <= 0:
- conn.notice(nick, "My libido is over-used!")
- else:
- self.cur_fish -=1
- try:
- target = string.join(cmd.split()[1:])
- me = self.connection.get_nickname()
- trout_msg = random.choice(self.flirts)
- # ...and touchy.
- if me.lower() == target.lower():
- target = nick
- if public == 0:
- if random.random() <= 0.1:
- trout_msg+= ' (but %s is their secret admirer)' % nick
- conn.action(self.channel, trout_msg % target)
- except IndexError:
- conn.notice(nick, "Who do you wish me to flirt with?")
-
- # trout someone
- def troutq(self, cmd, nick, conn, public):
- self.fish_quota()
- if self.DoS == 1:
- conn.notice(nick, "Sorry, but %s is being a spoilsport." %
- self.Boring_Git)
- return
- if self.cur_fish <= 0:
- conn.notice(nick, "Fish stocks exhausted.")
- else:
- self.cur_fish -=1
- try:
- target = string.join(cmd.split()[1:])
- me = self.connection.get_nickname()
- trout_msg = random.choice(self.trouts)
-# # The bot is loyal(ish)...
-# if target.lower() == self.owner.lower():
-# target = nick
- # ...and touchy.
- if me.lower() == target.lower():
- target = nick
- if public == 0:
- if random.random() <= 0.1:
- trout_msg+= ' (at the instigation of %s)' % nick
- conn.action(self.channel, trout_msg % target)
- except IndexError:
- conn.notice(nick, "Who do you wish me to trout?")
-
- # stock up on trouts
- def reloadq(self, cmd, nick, conn, public):
- if irc_lower(nick) == irc_lower(self.owner):
- tback = self.trouts
- fback = self.flirts
- try:
- f = open("trouts", "r")
- self.trouts = [l.strip() for l in f.readlines() if l.find("%s") != -1]
- f.close()
- f = open("flirts", "r")
- self.flirts = [l.strip() for l in f.readlines() if l.find("%s") != -1]
- conn.notice(nick, "I am re-armed!")
- except IOError:
- conn.notice(nick, "Trout re-arming failed!")
- self.trouts = tback
- self.flirts = fback
- else:
- conn.notice(nick, "This command can only be invoked by my owner.")
- # Shut up trouting for a minute
- def nofish(self, cmd, nick, conn, public):
- self.cur_fish=0
- self.DoS=1
- self.Boring_Git=nick
- self.quotatime=time.time()
- self.quotatime+=60 #60 seconds of no fishing
- conn.notice(nick, "Fish stocks depleted, as you wish.")
- # Check on fish stocks
- def fish_quota(self):
- if self.DoS==1:
- if time.time()>=self.quotatime:
- self.DoS=0
- else:
- return
- if self.DoS==0:
- if (time.time()-self.quotatime)>self.fish_time_inc:
- self.cur_fish+=(((time.time()-self.quotatime)/self.fish_time_inc)*self.fish_inc)
- if self.cur_fish>self.max_fish:
- self.cur_fish=self.max_fish
- self.quotatime=time.time()
-
- # quit irc
- def quit(self, cmd, nick, conn, public):
- if irc_lower(nick) == irc_lower(self.owner):
- f = open("karmadump", "w")
- cPickle.dump(self.karma, f)
- f.close()
- self.die(msg="I have been chosen!")
- elif public == 1:
- conn.privmsg(nick, "Such aggression in public!")
- else:
- conn.notice(nick, "You're not my owner.")
-
- # google for something
- def googleq(self, cmd, nick, conn, public):
- cmdrest = string.join(cmd.split()[1:])
- # "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))
- try:
- # 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(self.channel, str(gsearch))
- else:
- if public == 0:
- conn.notice(nick, "No pages found.")
- else:
- conn.privmsg(self.channel, "No pages found.")
- except IOError: # if the connection times out. This blocks. :(
- if public == 0:
- conn,notice(nick, "The web's broken. Waah!")
- else:
- conn.privmsg(self.channel, "The web's broken. Waah!")
-
- # General query handler
- def do_command(self, nick, cmd, public=0):
- conn = self.connection
- # karma: up
- if cmd.split()[0].endswith("++"):
- self.karmaup(cmd)
-
- # karma: down
- if cmd.split()[0].endswith("--"):
- self.karmadown(cmd)
-
- # karma: query
- if cmd.split()[0] == "karma" or cmd.split()[0] == "Karma":
- self.karmaq(cmd, conn, nick, public)
-
- # bot's vital statistics
- if cmd == "info":
- self.infoq(cmd, nick, conn, public)
-
- # Known commands
- if cmd == "list":
- self.listq(cmd, nick, conn, public)
- # weaponry
- if cmd.split()[0] == "trout":
- self.troutq(cmd, nick, conn, public)
- if cmd.split()[0] == "flirt":
- self.flirtq(cmd, nick, conn, public)
- if cmd == "reload":
- self.reloadq(cmd, nick, conn, public)
-
-#Disconnect disabled 'cos people hated it
-# #disconnect
-# if cmd == "disconnect": # hop off for 60s
-# self.disconnect(msg="Be right back.")
-
- # No more trout
- if cmd.split()[0] == "quiet":
- self.nofish(cmd,nick,conn, public)
-
- # say to msg/channel
- elif cmd.split()[0] == "say" \
- and irc_lower(nick) == irc_lower(self.owner):
- conn.privmsg(self.channel, string.join(cmd.split()[1:]))
-
- # action to msg/channel
- elif cmd.split()[0] == "do" \
- and irc_lower(nick) == irc_lower(self.owner):
- conn.action(self.channel, string.join(cmd.split()[1:]))
-
- # quit IRC
- elif cmd == "die":
- self.quit(cmd, nick, conn, public)
-
- # Google!
- elif (cmd.split()[0] == "google" or cmd.split()[0] == "Google"):
- self.googleq(cmd, nick, conn, public)
-
-def main():
- if len(sys.argv) != 5: # insufficient arguments
- print "Usage: acrobat <server[:port]> <channel> <nickname> owner"
- sys.exit(1)
- sv_port = string.split(sys.argv[1], ":", 1) # tuple; (server, port)
- server = sv_port[0]
- if len(sv_port) == 2:
- try:
- port = int(sv_port[1])
- except ValueError:
- print "Error: Erroneous port."
- sys.exit(1)
- else:
- port = 6667 # default irc port
- channel = sys.argv[2]
- nickname = sys.argv[3]
- owner = sys.argv[4]
- # initialize the bot
- bot = Acrobat(channel, nickname, server, owner, port)
- sys.stderr.write("Trying to connect...\n")
- # and the event loop
- bot.start()
-
-if __name__ == "__main__":
- main()