chiark / gitweb /
Upstream version 0.3
[irc.git] / acrobat.py
1 #!/usr/bin/env python2
2 #
3 # Bot logic:
4 # Andrew Walkingshaw <andrew@lexical.org.uk>
5 #
6 # IRC framework:
7 # Joel Rosdahl <joel@rosdahl.net>
8 #
9 # Contributors:
10 # Peter Corbett <ptc24@cam.ac.uk>
11 # Matthew Vernon <matthew@debian.org>
12
13 # This file is part of Acrobat.
14 #
15 # Acrobat is free software; you can redistribute it and/or modify
16 # it under the terms of the GNU General Public License as published
17 # by the Free Software Foundation; either version 2 of the License,
18 # or (at your option) any later version.
19 #
20 # Acrobat is distributed in the hope that it will be useful,
21 # but WITHOUT ANY WARRANTY; without even the implied warranty of
22 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23 # GNU General Public License for more details.
24 #
25 # You should have received a copy of the GNU General Public License
26 # along with Acrobat; if not, write to the Free Software
27 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
28 # USA.
29
30 """
31 Acrobat - an extensible, minmalist irc bot.
32 """
33
34 import string, urllib, sys, cPickle, os, random
35 from ircbot import SingleServerIRCBot
36 from irclib import nm_to_n, irc_lower
37 import config
38
39 #splitting out the configuration to a separate (source, but this is incidental-
40 #it's just the nearest free parser) file.
41
42 import config
43
44 class Karma:
45     def __init__(self):
46         self.dict = {}
47
48 class Acrobat(SingleServerIRCBot):
49     def __init__(self, channel, nickname, server, owner, port=6667):
50         SingleServerIRCBot.__init__(self,
51                                     [(server, port)], nickname, nickname)
52         self.channel = channel
53         self.owner = owner
54         self.revision = "$Revision$" # global version number
55         self.trouts = config.trouts
56         self.karmafilename = config.karmafilename
57         self.config = config
58         
59         # load the karma db
60         try:
61             f = open(self.karmafilename, "r")
62             self.karma = cPickle.load(f)
63             f.close()
64         except IOError:
65             self.karma = Karma()
66         
67     ## EVENT HANDLERS
68             
69     def on_welcome(self, conn, evt):
70         conn.join(self.channel)
71
72     def on_privmsg(self, conn, evt):
73         self.do_command(nm_to_n(evt.source()), evt.arguments()[0])
74         
75     def on_pubmsg(self, conn, evt):
76         payload = evt.arguments()[0]
77         nc = string.split(payload, " ", 1)
78         if len(nc) > 1 and (irc_lower(nc[0]).startswith(
79             irc_lower(self.connection.get_nickname()))):
80             self.do_command(self.channel, nc[1].strip(), public = 1)
81         elif payload[0] in config.triggers and len(payload)>1:
82             self.do_command(self.channel, payload[1:].strip(), public=1)
83         elif payload.find("++") != -1 or payload.find("--") != -1:
84             self.do_command(self.channel, payload.strip(), public=1)
85     # General query handler
86     def do_command(self, nick, cmd, public=0):
87         conn = self.connection
88         command = cmd.split()[0]
89         sys.stderr.write(command)
90         args = (self, cmd, nick, conn, public)
91
92         # regrettably, these (and anything else with special triggers)
93         # must be special-cased, which is aesthetically unsatisfying.
94         
95         # karma: up
96         if command.endswith("++"):
97             self.karmaup(cmd)
98         # karma: down
99         if command.endswith("--"):
100             self.karmadown(cmd)
101
102         # and in the general case (this is slightly magical)
103         if command.lower() in config.commands.keys():
104             config.commands[command](*args)
105         # else do nothing.
106
107         # What this _means_ is: you write a
108         # function(bot, cmd, nick, conn, public), where bot is the bot class
109         # (ie self here), and drop it in commands.py; then add a trigger command
110         # to config.py for it, in the dictionary "commands", and it will
111         # just start working on bot restart or config reload.
112
113         # This is, IMO, quite nifty. :)
114
115     # And now the karma commands, as these pretty much have to be here :(
116     # increment karma
117     def karmaup(self, cmd):
118         if self.karma.dict.has_key(cmd.split()[0][:-2]):
119             self.karma.dict[cmd.split()[0][:-2]] += 1
120         else:
121             self.karma.dict[cmd.split()[0][:-2]] = 1
122     #decrement karma
123     def karmadown(self, cmd):
124         if self.karma.dict.has_key(cmd.split()[0][:-2]):
125             self.karma.dict[cmd.split()[0][:-2]] -= 1
126         else:
127             self.karma.dict[cmd.split()[0][:-2]] = -1
128                 
129
130 def main():
131     # initialize the bot
132     bot = Acrobat(config.channel, config.nickname, config.server,
133                   config.owner, config.port)
134     sys.stderr.write("Trying to connect...\n")
135     # and the event loop
136     bot.start()
137
138 #    if len(sys.argv) != 5: # insufficient arguments
139 #        print "Usage: acrobat <server[:port]> <channel> <nickname> owner"
140 #        sys.exit(1)
141 #    sv_port = string.split(sys.argv[1], ":", 1) # tuple; (server, port)
142 #    server = sv_port[0]
143 #    if len(sv_port) == 2:
144 #        try:
145 #            port = int(sv_port[1])
146 #        except ValueError:
147 #            print "Error: Erroneous port."
148 #            sys.exit(1)
149 #    else:
150 #        port = 6667 # default irc port
151 #    channel = sys.argv[2]
152 #    nickname = sys.argv[3]
153 #    owner = sys.argv[4]
154
155 if __name__ == "__main__":
156     main()