1 # This file is part of Acrobat.
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.
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.
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
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
24 # Acrobat configuration file
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
34 # Also a function called "command"; see later.
36 # Everything else in this file is configuration-specific.
38 import os, time, re, twitter, subprocess, sys, os.path
40 # Most command implementations are stored in a separate module.
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.
56 # load the "blame" details for a file
57 def loadblame(filename):
58 p=subprocess.Popen(["git","blame","-s",filename],
59 stdout=subprocess.PIPE,stderr=subprocess.PIPE)
60 out,err=p.communicate()
62 sys.exit("git blame failure: %s" % err)
67 if len(line.strip())>0:
74 #set up blame dbs for trouts/flirts/slashes
75 tbdb,tbdbk=loadblame("trouts")
76 fbdb,fbdbk=loadblame("flirts")
77 sbdb,sbdbk=loadblame("slashes")
79 # load a file full of flirts or trouts
82 f = open(filename, "r")
83 r = [l.strip() for l in f.readlines() if l.find("%s") != -1]
86 r = [ "doesn't know what to do about %s." ]
89 # (troutlist,selftroutmsg,DoSmsg,notargetmsg,nofishmsg,fishpond,selftroutprob)
92 ' (at the instigation of %s)',
93 "Sorry, but %s is being a spoilsport.",
94 "Who do you wish me to trout?",
95 "Fish stocks exhausted.",
101 ' (but %s is their secret admirer)',
102 "Sorry, but %s made me take Holy Orders.",
103 "Who do you wish me to flirt with?",
104 "My libido is over-used!",
110 ' (while %s watches)',
111 "Sorry, but %s stole my pen.",
112 "Who do you want to slash?",
113 "I have writer's block!",
117 # Hacky command to output the current fishpond state
118 def fishq(bot, cmd, nick, conn, public,f):
119 from irclib import irc_lower
120 if not public and irc_lower(nick) == irc_lower(bot.owner):
121 state=("Fishpond state: cur_fish=%d, max_fish=%d, nofish_time=%d, "
122 +"fish_time_inc=%d, fish_inc=%d, DoS=%d, Boring_Git=%s, "
123 +"quotatime=%d")%(f.cur_fish,f.max_fish,f.nofish_time,
124 f.fish_time_inc,f.fish_inc,f.DoS,f.Boring_Git,
126 bot.automsg(public,nick,state)
128 # Karma implementation
130 karmafilename = "chiark-karma-"+channel
133 f = open(karmafilename, "r")
134 karmadb = cPickle.load(f)
139 def karma(cmd, amount):
140 thing=cmd.split()[0][:-2].lower()
141 if karmadb.has_key(thing):
142 karmadb[thing] += amount
144 karmadb[thing] = amount
147 tmp = "%s.tmp" % karmafilename
150 cPickle.dump(karmadb, f)
152 os.rename(tmp, karmafilename)
154 sys.stderr.write("error writing karma: %s" % e)
156 def quit(bot,cmd,nick,conn,public):
157 c.quitq(bot,cmd,nick,conn,public)
158 def reload(bot,cmd,nick,conn,public):
159 c.reloadq(bot,cmd,nick,conn,public)
161 # initialise the urldb on startup
164 #expire urls if not asked about or seen for >71 hours
166 #do an expiry run every hour
170 #path where Oauth details are kept
171 twioauthpath=os.path.expanduser("~/private/servus_twapi_oauth.txt")
174 f=open(twioauthpath,"r")
178 key,val=map(str.strip,line.split(':'))
179 if key == "consumer_key":
181 elif key == "consumer_secret":
183 elif key == "access_token":
185 elif key == "access_token_secret":
188 raise ValueError, "Invalid line in twitter auth details file %s" % line
190 twitapi = twitter.Api(consumer_key = twoaapck,
191 consumer_secret = twoaapcs,
192 access_token_key = twoapat,
193 access_token_secret = twoapats,
194 tweet_mode = "extended")
196 # non-authenticated twitter api instance
197 twitapi = twitter.Api()
199 # Command processing: whenever something is said that the bot can hear,
200 # "command" is invoked and must decide what to do. This configuration
201 # defines a couple of special cases (for karma) but is otherwise driven
202 # by a dictionary of commands.
204 commands = {"karma": (c.karmaq,karmadb),
205 "karmalist": (c.listkeysq,karmadb),
206 "karmadel": (c.karmadelq,karmadb),
207 "info": (c.infoq,karmadb),
208 "trout": (c.troutq,troutcfg),
209 "slash": (c.slashq, slashcfg),
211 "fish": (fishq,fish),
212 "flirt": (c.troutq,flirtcfg),
213 "quiet": (c.nofishq,fish),
219 "url": (c.urlq,urldb),
220 "nsfw": (c.nsfwq,urldb),
221 "nws": (c.nsfwq,urldb),
223 "currency":c.currencyq,
224 "blame": (c.blameq,fish,tbdb,tbdbk,fbdb,fbdbk,sbdb,sbdbk),
228 "twit": (c.twitterq,twitapi) }
229 # disconnect and hop annoy people
230 # "disconnect": c.disconnq,
231 # "hop": c.disconnq }
232 commands["list"]=(c.listkeysq,commands,True)
234 triggers = ("!", "~") # what character should the bot be invoked by:
235 # eg !trout, ~trout etc.
237 def command(bot, cmd, nick, conn, public):
238 global urldb,lastexp,expirelen,expirevery,twitapi
241 if public and cmd[0] in triggers:
246 command = cmd.split()[0]
251 if t - lastexp > expirevery:
252 c.urlexpire(urldb,expirelen)
256 if c.urlre.search(cmd) and command.lower()!="url":
257 c.dourl(bot,conn,nick,cmd,urldb)
260 if command.endswith("++"):
263 if command.endswith("--"):
266 if ours and command.lower() in commands.keys():
267 e=commands[command.lower()]
269 e(bot,cmd,nick,conn,public)
271 e[0](bot,cmd,nick,conn,public,*e[1:])