chiark / gitweb /
First hacked version
[irc.git] / acrobat-chiark-0.2.py
1 #!/usr/local/bin/python
2 #
3 # Joel Rosdahl <joel@rosdahl.net>
4 # Andrew Walkingshaw <andrew@lexical.org.uk>
5
6 # This file is part of Acrobat.
7 #
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.
12 #
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.
17
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
21 # USA.
22
23 """
24     disconnect -- Disconnect the bot.  The bot will try to reconnect
25                   after 60 seconds.
26
27     die -- Let the bot cease to exist.
28
29     google -- search, 'I'm Feeling Lucky', and notice the user who searches
30               back with the url.
31 """
32
33 import string, urllib, sys, cPickle, os
34 from ircbot import SingleServerIRCBot
35 from irclib import nm_to_n, irc_lower
36
37 class Karma:
38     def __init__(self):
39         self.dict = {}
40     
41 class Acrobat(SingleServerIRCBot):
42     def __init__(self, channel, nickname, server, owner, port=6667):
43         SingleServerIRCBot.__init__(self,
44                                     [(server, port)], nickname, nickname)
45         self.channel = channel
46         self.owner = owner
47         # load the karma db
48         try:
49             f = open("karmadump", "r")
50             self.karma = cPickle.load(f)
51             f.close()
52         except IOError:
53             self.karma = Karma()
54
55     ## EVENT HANDLERS
56             
57     def on_welcome(self, conn, evt):
58         conn.join(self.channel)
59
60     def on_privmsg(self, conn, evt):
61         self.do_command(nm_to_n(evt.source()), evt.arguments()[0])
62         
63     def on_pubmsg(self, conn, evt):
64         payload = evt.arguments()[0]
65         a = string.split(evt.arguments()[0], " ", 1)
66         if len(a) > 1 \
67            and (irc_lower(a[0]) == irc_lower(self.connection.get_nickname())
68                 or irc_lower(a[0])[:-1] == irc_lower(self.connection.get_nickname())):
69
70             self.do_command(self.channel, string.strip(a[1]), public = 1)
71         if a[0].endswith("++"):
72             self.karmaup(a[0])
73         if a[0].endswith("--"):
74             self.karmadown(a[0])
75         if payload[0] == "!" and len(payload)>1:
76             self.do_command(self.channel, string.strip(payload[1:]), public=1)
77         if payload[0] == "~" and len(payload)>1:
78             self.do_command(self.channel, string.strip(payload[1:]), public=1)
79
80     # And now bot commands;
81
82     # increment karma
83     def karmaup(self, cmd):
84         if self.karma.dict.has_key(cmd.split()[0][:-2]):
85             self.karma.dict[cmd.split()[0][:-2]] += 1
86         else:
87             self.karma.dict[cmd.split()[0][:-2]] = 1
88
89     #decrement karma
90     def karmadown(self, cmd):
91         if self.karma.dict.has_key(cmd.split()[0][:-2]):
92             self.karma.dict[cmd.split()[0][:-2]] -= 1
93         else:
94             self.karma.dict[cmd.split()[0][:-2]] = -1
95
96     # query karma
97     def karmaq(self, cmd, conn, nick, public):
98         # in public
99         if public == 1:
100             try:
101                 if self.karma.dict.has_key(cmd.split()[1]):
102                     conn.privmsg(self.channel, "%s has karma %s."
103                                  %(cmd.split()[1],
104                                        self.karma.dict[cmd.split()[1]]))
105                 else:
106                     conn.privmsg(self.channel, "%s has no karma set." %
107                                  cmd.split()[1])
108             except IndexError:
109                 conn.privmsg(self.channel, "I have karma on %s items." %
110                              len(self.karma.dict.keys()))
111         # in private
112         else:
113             try:
114                 if self.karma.dict.has_key(cmd.split()[1]):
115                     conn.notice(nick, "%s has karma %s." %
116                                 (cmd.split()[1],
117                                  self.karma.dict[cmd.split()[1]]))
118                 else:
119                     conn.notice(nick, "I have karma on %s items." %
120                                 len(self.karma.dict.keys()))
121             except IndexError:
122                 conn.notice(nick, "I have karma on %s items." %
123                             len(self.karma.dict.keys()))
124     # query bot status
125     def infoq(self, cmd, nick, conn, public):
126         if public == 1:
127             conn.privmsg(self.channel,
128                          "I am Acrobat 0.2chiark, on %s, as nick %s." %
129                          (self.channel, self.connection.get_nickname()))
130             conn.privmsg(self.channel,
131                          "My owner is %s; I have karma on %s items." %
132                          (self.owner, len(self.karma.dict.keys())))
133         else:
134             conn.notice(nick, "I am Acrobat 0.2chiark, on %s, as nick %s." %
135                         (self.channel, self.connection.get_nickname()))
136             conn.notice(nick, "My owner is %s; I have karma on %s items." %
137                         (self.owner, len(self.karma.dict.keys())))
138
139     # quit irc
140     def quit(self, cmd, nick, conn, public):
141         if irc_lower(nick) == irc_lower(self.owner):
142             f = open("karmadump", "w")
143             cPickle.dump(self.karma, f)
144             f.close()
145             self.die(msg="I have been chosen!")
146         elif public == 1:
147             conn.privmsg(nick, "Such aggression in public!")
148         else:
149             conn.notice(nick, "You're not my owner.")
150             
151     # google for something
152     def googleq(self, cmd, nick, conn, public):
153         cmdrest = string.join(cmd.split()[1:])
154         # "I'm Feeling Lucky" rather than try and parse the html
155         targ = ("http://www.google.com/search?q=%s&btnI=I'm+Feeling+Lucky"
156                 % urllib.quote_plus(cmdrest))
157         try:
158             # get redirected and grab the resulting url for returning
159             gsearch = urllib.urlopen(targ).geturl()
160             if gsearch != targ: # we've found something
161                 if public == 0:
162                     conn.notice(nick, str(gsearch))
163                 else: # we haven't found anything.
164                     conn.privmsg(nick, str(gsearch))
165             else:
166                 if public == 0:
167                     conn.notice(nick, "No pages found.")
168                 else:
169                     conn.privmsg(nick, "No pages found.")
170         except IOError: # if the connection times out. This blocks. :(
171             if public == 0:
172                 conn,notice(nick, "The web's broken. Waah!")
173             else:
174                 conn.privmsg(nick, "The web's broken. Waah!")
175                 
176     # General query handler
177     def do_command(self, nick, cmd, public=0):
178         conn = self.connection
179         # karma: up
180         if cmd.split()[0].endswith("++"):
181             self.karmaup(cmd)
182         
183         # karma: down
184         if cmd.split()[0].endswith("--"):
185             self.karmadown(cmd)
186             
187         # karma: query
188         if cmd.split()[0] == "karma" or cmd.split()[0] == "Karma":
189             self.karmaq(cmd, conn, nick, public)
190             
191         # bot's vital statistics
192         if cmd == "info":
193             self.infoq(cmd, nick, conn, public)
194
195         #disconnect
196         if cmd == "disconnect": # hop off for 60s
197             self.disconnect(msg="Be right back.")
198
199         # say to msg/channel
200         elif cmd.split()[0] == "say" \
201              and irc_lower(nick) == irc_lower(self.owner):
202             conn.privmsg(self.channel, string.join(cmd.split()[1:]))
203
204         # action to msg/channel
205         elif cmd.split()[0] == "do" \
206              and irc_lower(nick) == irc_lower(self.owner):
207             conn.action(self.channel, string.join(cmd.split()[1:]))
208
209         # quit IRC
210         elif cmd == "die":
211             self.quit(cmd, nick, conn, public)
212
213         # Google!
214         elif (cmd.split()[0] == "google" or cmd.split()[0] == "Google"):
215             self.googleq(cmd, nick, conn, public)            
216
217 def main():
218     if len(sys.argv) != 5: # insufficient arguments
219         print "Usage: acrobat <server[:port]> <channel> <nickname> owner"
220         sys.exit(1)
221     sv_port = string.split(sys.argv[1], ":", 1) # tuple; (server, port)
222     server = sv_port[0]
223     if len(sv_port) == 2:
224         try:
225             port = int(sv_port[1])
226         except ValueError:
227             print "Error: Erroneous port."
228             sys.exit(1)
229     else:
230         port = 6667 # default irc port
231     channel = sys.argv[2]
232     nickname = sys.argv[3]
233     owner = sys.argv[4]
234     # initialize the bot
235     bot = Acrobat(channel, nickname, server, owner, port)
236     sys.stderr.write("Trying to connect...\n")
237     # and the event loop
238     bot.start()
239
240 if __name__ == "__main__":
241     main()