4 # Joel Rosdahl <joel@rosdahl.net>
5 # Andrew Walkingshaw <andrew@lexical.org.uk>
6 # Peter Corbett <ptc24@cam.ac.uk>
7 # Matthew Vernon <matthew@debian.org>
9 # This file is part of Acrobat.
11 # Acrobat is free software; you can redistribute it and/or modify
12 # it under the terms of the GNU General Public License as published
13 # by the Free Software Foundation; either version 2 of the License,
14 # or (at your option) any later version.
16 # Acrobat is distributed in the hope that it will be useful,
17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 # GNU General Public License for more details.
21 # You should have received a copy of the GNU General Public License
22 # along with Acrobat; if not, write to the Free Software
23 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
27 disconnect -- Disconnect the bot. The bot will try to reconnect
30 die -- Let the bot cease to exist.
32 google -- search, 'I'm Feeling Lucky', and notice the user who searches
36 import string, urllib, sys, cPickle, os, random, re
37 from ircbot import SingleServerIRCBot
38 from irclib import nm_to_n, irc_lower
46 class Acrobat(SingleServerIRCBot):
47 def __init__(self, channel, nickname, server, owner, port=6667):
48 SingleServerIRCBot.__init__(self,
49 [(server, port)], nickname, nickname)
50 self.channel = channel
52 # version control magic
53 acrorevision=$Revision$
54 acroversion=re.sub($Revision$]*\)$,\1)
57 f = open("karmadump", "r")
58 self.karma = cPickle.load(f)
63 f = open("trouts", "r")
64 self.trouts = [l.strip() for l in f.readlines() if l.find("%s") != -1]
67 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."]
71 def on_welcome(self, conn, evt):
72 conn.join(self.channel)
74 def on_privmsg(self, conn, evt):
75 self.do_command(nm_to_n(evt.source()), evt.arguments()[0])
77 def on_pubmsg(self, conn, evt):
78 payload = evt.arguments()[0]
79 a = string.split(evt.arguments()[0], " ", 1)
81 and (irc_lower(a[0]) == irc_lower(self.connection.get_nickname())
82 or irc_lower(a[0])[:-1] == irc_lower(self.connection.get_nickname())):
84 self.do_command(self.channel, string.strip(a[1]), public = 1)
85 if a[0].endswith("++"):
87 if a[0].endswith("--"):
89 if payload[0] == "!" and len(payload)>1:
90 self.do_command(self.channel, string.strip(payload[1:]), public=1)
91 if payload[0] == "~" and len(payload)>1:
92 self.do_command(self.channel, string.strip(payload[1:]), public=1)
94 # And now bot commands;
97 def karmaup(self, cmd):
98 if self.karma.dict.has_key(cmd.split()[0][:-2]):
99 self.karma.dict[cmd.split()[0][:-2]] += 1
101 self.karma.dict[cmd.split()[0][:-2]] = 1
104 def karmadown(self, cmd):
105 if self.karma.dict.has_key(cmd.split()[0][:-2]):
106 self.karma.dict[cmd.split()[0][:-2]] -= 1
108 self.karma.dict[cmd.split()[0][:-2]] = -1
111 def karmaq(self, cmd, conn, nick, public):
115 if self.karma.dict.has_key(cmd.split()[1]):
116 conn.privmsg(self.channel, "%s has karma %s."
118 self.karma.dict[cmd.split()[1]]))
120 conn.privmsg(self.channel, "%s has no karma set." %
123 conn.privmsg(self.channel, "I have karma on %s items." %
124 len(self.karma.dict.keys()))
128 if self.karma.dict.has_key(cmd.split()[1]):
129 conn.notice(nick, "%s has karma %s." %
131 self.karma.dict[cmd.split()[1]]))
133 conn.notice(nick, "I have karma on %s items." %
134 len(self.karma.dict.keys()))
136 conn.notice(nick, "I have karma on %s items." %
137 len(self.karma.dict.keys()))
139 def infoq(self, cmd, nick, conn, public):
141 conn.privmsg(self.channel,
142 "I am Acrobat 0.2.1chiark, on %s, as nick %s." %
143 (self.channel, self.connection.get_nickname()))
144 conn.privmsg(self.channel,
145 "My owner is %s; I have karma on %s items." %
146 (self.owner, len(self.karma.dict.keys())))
148 conn.notice(nick, "I am Acrobat 0.2.1chiark, on %s, as nick %s." %
149 (self.channel, self.connection.get_nickname()))
150 conn.notice(nick, "My owner is %s; I have karma on %s items." %
151 (self.owner, len(self.karma.dict.keys())))
154 def troutq(self, cmd, nick, conn, public):
156 target = string.join(cmd.split()[1:])
157 me = self.connection.get_nickname()
158 trout_msg = random.choice(self.trouts)
159 # # The bot is loyal(ish)...
160 # if target.lower() == self.owner.lower():
163 if me.lower() == target.lower():
165 conn.action(self.channel, trout_msg % target)
167 if random.random() <= 0.1:
168 conn.action(self.channel, "notes %s is conducting a whispering campaign" % nick)
170 conn.notice(nick, "Who do you wish me to trout?")
173 def reloadq(self, cmd, nick, conn, public):
174 if irc_lower(nick) == irc_lower(self.owner):
177 f = open("trouts", "r")
178 self.trouts = [l.strip() for l in f.readlines() if l.find("%s") != -1]
180 conn.notice(nick, "I am re-armed!")
182 conn.notice(nick, "Trout re-arming failed!")
185 conn.notice(nick, "This command can only be invoked by my owner.")
188 def quit(self, cmd, nick, conn, public):
189 if irc_lower(nick) == irc_lower(self.owner):
190 f = open("karmadump", "w")
191 cPickle.dump(self.karma, f)
193 self.die(msg="I have been chosen!")
195 conn.privmsg(nick, "Such aggression in public!")
197 conn.notice(nick, "You're not my owner.")
199 # google for something
200 def googleq(self, cmd, nick, conn, public):
201 cmdrest = string.join(cmd.split()[1:])
202 # "I'm Feeling Lucky" rather than try and parse the html
203 targ = ("http://www.google.com/search?q=%s&btnI=I'm+Feeling+Lucky"
204 % urllib.quote_plus(cmdrest))
206 # get redirected and grab the resulting url for returning
207 gsearch = urllib.urlopen(targ).geturl()
208 if gsearch != targ: # we've found something
210 conn.notice(nick, str(gsearch))
211 else: # we haven't found anything.
212 conn.privmsg(nick, str(gsearch))
215 conn.notice(nick, "No pages found.")
217 conn.privmsg(nick, "No pages found.")
218 except IOError: # if the connection times out. This blocks. :(
220 conn,notice(nick, "The web's broken. Waah!")
222 conn.privmsg(nick, "The web's broken. Waah!")
224 # General query handler
225 def do_command(self, nick, cmd, public=0):
226 conn = self.connection
228 if cmd.split()[0].endswith("++"):
232 if cmd.split()[0].endswith("--"):
236 if cmd.split()[0] == "karma" or cmd.split()[0] == "Karma":
237 self.karmaq(cmd, conn, nick, public)
239 # bot's vital statistics
241 self.infoq(cmd, nick, conn, public)
244 if cmd.split()[0] == "trout":
245 self.troutq(cmd, nick, conn, public)
247 self.reloadq(cmd, nick, conn, public)
250 if cmd == "disconnect": # hop off for 60s
251 self.disconnect(msg="Be right back.")
254 elif cmd.split()[0] == "say" \
255 and irc_lower(nick) == irc_lower(self.owner):
256 conn.privmsg(self.channel, string.join(cmd.split()[1:]))
258 # action to msg/channel
259 elif cmd.split()[0] == "do" \
260 and irc_lower(nick) == irc_lower(self.owner):
261 conn.action(self.channel, string.join(cmd.split()[1:]))
265 self.quit(cmd, nick, conn, public)
268 elif (cmd.split()[0] == "google" or cmd.split()[0] == "Google"):
269 self.googleq(cmd, nick, conn, public)
272 if len(sys.argv) != 5: # insufficient arguments
273 print "Usage: acrobat <server[:port]> <channel> <nickname> owner"
275 sv_port = string.split(sys.argv[1], ":", 1) # tuple; (server, port)
277 if len(sv_port) == 2:
279 port = int(sv_port[1])
281 print "Error: Erroneous port."
284 port = 6667 # default irc port
285 channel = sys.argv[2]
286 nickname = sys.argv[3]
289 bot = Acrobat(channel, nickname, server, owner, port)
290 sys.stderr.write("Trying to connect...\n")
294 if __name__ == "__main__":