3 # Joel Rosdahl <joel@rosdahl.net>
4 # Andrew Walkingshaw <andrew@lexical.org.uk>
6 # This file is part of Acrobat.
8 # Acrobat is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published
10 # by the Free Software Foundation; either version 2 of the License,
11 # or (at your option) any later version.
13 # Foobar is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
18 # You should have received a copy of the GNU General Public License
19 # along with Foobar; if not, write to the Free Software
20 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
24 disconnect -- Disconnect the bot. The bot will try to reconnect
27 die -- Let the bot cease to exist.
29 google -- search, 'I'm Feeling Lucky', and notice the user who searches
33 import string, urllib, sys, cPickle, os, random
34 from ircbot import SingleServerIRCBot
35 from irclib import nm_to_n, irc_lower
43 class Acrobat(SingleServerIRCBot):
44 def __init__(self, channel, nickname, server, owner, port=6667):
45 SingleServerIRCBot.__init__(self,
46 [(server, port)], nickname, nickname)
47 self.channel = channel
51 f = open("karmadump", "r")
52 self.karma = cPickle.load(f)
57 f = open("trouts", "r")
58 self.trouts = [l.strip() for l in f.readlines() if l.find("%s") != -1]
61 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."]
65 def on_welcome(self, conn, evt):
66 conn.join(self.channel)
68 def on_privmsg(self, conn, evt):
69 self.do_command(nm_to_n(evt.source()), evt.arguments()[0])
71 def on_pubmsg(self, conn, evt):
72 payload = evt.arguments()[0]
73 a = string.split(evt.arguments()[0], " ", 1)
75 and (irc_lower(a[0]) == irc_lower(self.connection.get_nickname())
76 or irc_lower(a[0])[:-1] == irc_lower(self.connection.get_nickname())):
78 self.do_command(self.channel, string.strip(a[1]), public = 1)
79 if a[0].endswith("++"):
81 if a[0].endswith("--"):
83 if payload[0] == "!" and len(payload)>1:
84 self.do_command(self.channel, string.strip(payload[1:]), public=1)
85 if payload[0] == "~" and len(payload)>1:
86 self.do_command(self.channel, string.strip(payload[1:]), public=1)
88 # And now bot commands;
91 def karmaup(self, cmd):
92 if self.karma.dict.has_key(cmd.split()[0][:-2]):
93 self.karma.dict[cmd.split()[0][:-2]] += 1
95 self.karma.dict[cmd.split()[0][:-2]] = 1
98 def karmadown(self, cmd):
99 if self.karma.dict.has_key(cmd.split()[0][:-2]):
100 self.karma.dict[cmd.split()[0][:-2]] -= 1
102 self.karma.dict[cmd.split()[0][:-2]] = -1
105 def karmaq(self, cmd, conn, nick, public):
109 if self.karma.dict.has_key(cmd.split()[1]):
110 conn.privmsg(self.channel, "%s has karma %s."
112 self.karma.dict[cmd.split()[1]]))
114 conn.privmsg(self.channel, "%s has no karma set." %
117 conn.privmsg(self.channel, "I have karma on %s items." %
118 len(self.karma.dict.keys()))
122 if self.karma.dict.has_key(cmd.split()[1]):
123 conn.notice(nick, "%s has karma %s." %
125 self.karma.dict[cmd.split()[1]]))
127 conn.notice(nick, "I have karma on %s items." %
128 len(self.karma.dict.keys()))
130 conn.notice(nick, "I have karma on %s items." %
131 len(self.karma.dict.keys()))
133 def infoq(self, cmd, nick, conn, public):
135 conn.privmsg(self.channel,
136 "I am Acrobat 0.2.1chiark, on %s, as nick %s." %
137 (self.channel, self.connection.get_nickname()))
138 conn.privmsg(self.channel,
139 "My owner is %s; I have karma on %s items." %
140 (self.owner, len(self.karma.dict.keys())))
142 conn.notice(nick, "I am Acrobat 0.2.1chiark, on %s, as nick %s." %
143 (self.channel, self.connection.get_nickname()))
144 conn.notice(nick, "My owner is %s; I have karma on %s items." %
145 (self.owner, len(self.karma.dict.keys())))
148 def troutq(self, cmd, nick, conn, public):
150 target = string.join(cmd.split()[1:])
151 me = self.connection.get_nickname()
152 trout_msg = random.choice(self.trouts)
153 # # The bot is loyal(ish)...
154 # if target.lower() == self.owner.lower():
157 if me.lower() == target.lower():
159 conn.action(self.channel, trout_msg % target)
161 if random.random() <= 0.1:
162 conn.action(self.channel, "notes %s is conducting a whispering campaign" % nick)
164 conn.notice(nick, "Who do you wish me to trout?")
167 def reloadq(self, cmd, nick, conn, public):
168 if irc_lower(nick) == irc_lower(self.owner):
171 f = open("trouts", "r")
172 self.trouts = [l.strip() for l in f.readlines() if l.find("%s") != -1]
174 conn.notice(nick, "I am re-armed!")
176 conn.notice(nick, "Trout re-arming failed!")
179 conn.notice(nick, "This command can only be invoked by my owner.")
182 def quit(self, cmd, nick, conn, public):
183 if irc_lower(nick) == irc_lower(self.owner):
184 f = open("karmadump", "w")
185 cPickle.dump(self.karma, f)
187 self.die(msg="I have been chosen!")
189 conn.privmsg(nick, "Such aggression in public!")
191 conn.notice(nick, "You're not my owner.")
193 # google for something
194 def googleq(self, cmd, nick, conn, public):
195 cmdrest = string.join(cmd.split()[1:])
196 # "I'm Feeling Lucky" rather than try and parse the html
197 targ = ("http://www.google.com/search?q=%s&btnI=I'm+Feeling+Lucky"
198 % urllib.quote_plus(cmdrest))
200 # get redirected and grab the resulting url for returning
201 gsearch = urllib.urlopen(targ).geturl()
202 if gsearch != targ: # we've found something
204 conn.notice(nick, str(gsearch))
205 else: # we haven't found anything.
206 conn.privmsg(nick, str(gsearch))
209 conn.notice(nick, "No pages found.")
211 conn.privmsg(nick, "No pages found.")
212 except IOError: # if the connection times out. This blocks. :(
214 conn,notice(nick, "The web's broken. Waah!")
216 conn.privmsg(nick, "The web's broken. Waah!")
218 # General query handler
219 def do_command(self, nick, cmd, public=0):
220 conn = self.connection
222 if cmd.split()[0].endswith("++"):
226 if cmd.split()[0].endswith("--"):
230 if cmd.split()[0] == "karma" or cmd.split()[0] == "Karma":
231 self.karmaq(cmd, conn, nick, public)
233 # bot's vital statistics
235 self.infoq(cmd, nick, conn, public)
238 if cmd.split()[0] == "trout":
239 self.troutq(cmd, nick, conn, public)
241 self.reloadq(cmd, nick, conn, public)
244 if cmd == "disconnect": # hop off for 60s
245 self.disconnect(msg="Be right back.")
248 elif cmd.split()[0] == "say" \
249 and irc_lower(nick) == irc_lower(self.owner):
250 conn.privmsg(self.channel, string.join(cmd.split()[1:]))
252 # action to msg/channel
253 elif cmd.split()[0] == "do" \
254 and irc_lower(nick) == irc_lower(self.owner):
255 conn.action(self.channel, string.join(cmd.split()[1:]))
259 self.quit(cmd, nick, conn, public)
262 elif (cmd.split()[0] == "google" or cmd.split()[0] == "Google"):
263 self.googleq(cmd, nick, conn, public)
266 if len(sys.argv) != 5: # insufficient arguments
267 print "Usage: acrobat <server[:port]> <channel> <nickname> owner"
269 sv_port = string.split(sys.argv[1], ":", 1) # tuple; (server, port)
271 if len(sv_port) == 2:
273 port = int(sv_port[1])
275 print "Error: Erroneous port."
278 port = 6667 # default irc port
279 channel = sys.argv[2]
280 nickname = sys.argv[3]
283 bot = Acrobat(channel, nickname, server, owner, port)
284 sys.stderr.write("Trying to connect...\n")
288 if __name__ == "__main__":