chiark / gitweb /
new trout from Art
[irc.git] / Servus-chiark.py
1 # This file is part of Acrobat.
2 #
3 # Acrobat is free software; you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published
5 # by the Free Software Foundation; either version 2 of the License,
6 # or (at your option) any later version.
7 #
8 # Acrobat is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 # GNU General Public License for more details.
12 #
13 # You should have received a copy of the GNU General Public License
14 # along with Acrobat; if not, write to the Free Software
15 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
16 # USA.
17
18 # Andrew Walkingshaw <andrew@lexical.org.uk>
19 # Peter Corbett <ptc24@cam.ac.uk>
20 # Matthew Vernon <matthew@debian.org>
21 # Stephen Early <steve@greenend.org.uk>
22 # Richard Kettlewell <rjk@greenend.org.uk
23
24 # Acrobat configuration file
25
26 # The following definitions are required to be present in this module:
27 # You can also override them on the command-line
28 # e.g. python acrobat.py Servus-chiark nickname=testbot channel=\#test owner=MyNick
29 server = "chiark"
30 port = 6667
31 nickname = "Servus"
32 channel = "#chiark"
33 owner = "Emperor"
34 # Also a function called "command"; see later.
35
36 # Everything else in this file is configuration-specific.
37
38 import os, time, re, twitter
39
40 # Most command implementations are stored in a separate module.
41 import commands as c
42
43 # This fishpond is shared between trouts and flirts.  It doesn't have to be;
44 # you can define as many ponds as you like.
45 class fish:
46         cur_fish=5
47         max_fish=5
48         nofish_time=60
49         fish_time_inc=60
50         fish_inc=2
51         DoS=0
52         Boring_Git='Nobody'
53         quotatime=0
54
55 # load a file full of flirts or trouts
56 def __load(filename):
57     try:
58         f = open(filename, "r")
59         r = [l.strip() for l in f.readlines() if l.find("%s") != -1]
60         f.close()
61     except IOError:
62         r = [ "doesn't know what to do about %s." ]
63     return r
64
65 # (troutlist,selftroutmsg,DoSmsg,notargetmsg,nofishmsg,fishpond,selftroutprob)
66 troutcfg = (
67         __load("trouts"),
68         ' (at the instigation of %s)',
69         "Sorry, but %s is being a spoilsport.",
70         "Who do you wish me to trout?",
71         "Fish stocks exhausted.",
72         fish,
73         0.1)
74
75 flirtcfg = (
76         __load("flirts"),
77         ' (but %s is their secret admirer)',
78         "Sorry, but %s made me take Holy Orders.",
79         "Who do you wish me to flirt with?",
80         "My libido is over-used!",
81         fish,
82         0.1)
83
84 slashcfg= ( 
85         __load("slashes"),
86         ' (while %s watches)',
87         "Sorry, but %s stole my pen.",
88         "Who do you want to slash?",
89         "I have writer's block!",
90         fish,
91         0.1)
92
93 # Hacky command to output the current fishpond state
94 def fishq(bot, cmd, nick, conn, public,f):
95         from irclib import irc_lower
96         if not public and irc_lower(nick) == irc_lower(bot.owner):
97                 state=("Fishpond state: cur_fish=%d, max_fish=%d, nofish_time=%d, "
98                        +"fish_time_inc=%d, fish_inc=%d, DoS=%d, Boring_Git=%s, "
99                        +"quotatime=%d")%(f.cur_fish,f.max_fish,f.nofish_time,
100                                          f.fish_time_inc,f.fish_inc,f.DoS,f.Boring_Git,
101                                          f.quotatime)
102                 bot.automsg(public,nick,state)
103                     
104 # Karma implementation
105 import cPickle
106 karmafilename = "chiark-karma-"+channel
107 # load the karma db
108 try:
109     f = open(karmafilename, "r")
110     karmadb = cPickle.load(f)
111     f.close()
112 except IOError:
113     karmadb = {}
114 # Modify karma
115 def karma(cmd, amount):
116     thing=cmd.split()[0][:-2].lower()
117     if karmadb.has_key(thing):
118         karmadb[thing] += amount
119     else:
120         karmadb[thing] = amount
121     savekarma()
122 def savekarma():
123     tmp = "%s.tmp" % karmafilename
124     try:
125         f = open(tmp, "w")
126         cPickle.dump(karmadb, f)
127         f.close()
128         os.rename(tmp, karmafilename)
129     except IOError, e:
130         sys.stderr.write("error writing karma: %s" % e)
131
132 def quit(bot,cmd,nick,conn,public):
133     c.quitq(bot,cmd,nick,conn,public)
134 def reload(bot,cmd,nick,conn,public):
135     c.reloadq(bot,cmd,nick,conn,public)
136
137 # initialise the urldb on startup
138 urldb={}
139 lastexp=time.time()
140 #expire urls if not asked about or seen for >71 hours
141 expirelen=71*60*60
142 #do an expiry run every hour
143 expirevery=60*60
144
145 # non-authenticated twitter api instance
146 twitapi = twitter.Api()
147
148 # Command processing: whenever something is said that the bot can hear,
149 # "command" is invoked and must decide what to do.  This configuration
150 # defines a couple of special cases (for karma) but is otherwise driven
151 # by a dictionary of commands.
152
153 commands = {"karma": (c.karmaq,karmadb),
154             "karmalist": (c.listkeysq,karmadb),
155             "karmadel": (c.karmadelq,karmadb),
156             "info": (c.infoq,karmadb),
157             "trout": (c.troutq,troutcfg),
158             "slash": (c.slashq, slashcfg),
159             "rot13": c.rot13q,
160             "fish": (fishq,fish),
161             "flirt": (c.troutq,flirtcfg),
162             "quiet": (c.nofishq,fish),
163             "reload": reload,
164             "quit": quit,
165             "die": quit,
166             "define": c.defineq,
167             "google": c.googleq,
168             "url": (c.urlq,urldb),
169             "nsfw": (c.nsfwq,urldb),
170             "nws": (c.nsfwq,urldb),
171             "units": c.unitq,
172             "help": c.helpq,
173             "say": c.sayq,
174             "do": c.doq, 
175             "twit": (c.twitterq,twitapi) }
176 # disconnect and hop annoy people
177 #            "disconnect": c.disconnq,
178 #            "hop": c.disconnq }
179 commands["list"]=(c.listkeysq,commands,True)
180
181 triggers = ("!", "~") # what character should the bot be invoked by:
182                       # eg !trout, ~trout etc.
183
184 def command(bot, cmd, nick, conn, public):
185     global urldb,lastexp,expirelen,expirevery,twitapi
186     ours=0
187     try:
188             if public and cmd[0] in triggers:
189                     ours=1
190                     cmd=cmd[1:]
191             if not public:
192                     ours=1
193             command = cmd.split()[0]
194     except IndexError:
195             command=""
196
197     t=time.time()
198     if t - lastexp > expirevery:
199             c.urlexpire(urldb,expirelen)
200             lastexp=t
201
202     if public:
203       if c.urlre.search(cmd) and command.lower()!="url":
204         c.dourl(bot,conn,nick,cmd,urldb)
205
206     # karma: up
207     if command.endswith("++"):
208         karma(cmd,1)
209     # karma: down
210     if command.endswith("--"):
211         karma(cmd,-1)
212
213     if ours and command.lower() in commands.keys():
214         e=commands[command.lower()]
215         if callable(e):
216             e(bot,cmd,nick,conn,public)
217         else:
218             e[0](bot,cmd,nick,conn,public,*e[1:])