]> gitweb.pimeys.fr Git - bots/saturnin.git/blob - saturnin.py
On ignore les bots de jben
[bots/saturnin.git] / saturnin.py
1 #!/usr/bin/python
2 # -*- encoding: utf-8 -*-
3
4 # Codé par 20-100
5
6 # Un bot IRC pour remplacer le canard.
7 # parce que le canard, c'est le bien et que braice ne pong pas
8
9 import threading
10 import random
11 import time
12 import socket, ssl, json
13 import pickle
14 import re
15 import os
16 import signal
17 import sys
18 from commands import getstatusoutput as ex
19
20 # Oui, j'ai recodé ma version d'irclib pour pouvoir rattrapper les SIGHUP
21 sys.path.insert(0, "/home/vincent/scripts/python-myirclib")
22 import irclib
23 import ircbot
24
25 # on récupère la config
26 import config
27
28
29
30 def get_config_logfile(serveur):
31 serveurs={"acoeur.crans.org":"acoeur","irc.crans.org":"crans"}
32 return config.logfile_template%(serveurs[serveur])
33
34 def log(serveur,channel,auteur=None,message=None):
35 f=open(get_config_logfile(serveur),"a")
36 if auteur==message==None:
37 # alors c'est que c'est pas un channel mais juste une ligne de log
38 chain="%s %s"%(time.strftime("%F %T"),channel)
39 else:
40 chain="%s [%s:%s] %s"%(time.strftime("%F %T"),channel,auteur,message)
41 f.write(chain+"\n")
42 if config.debug_stdout:
43 print chain
44 f.close()
45
46 def is_something(chain,matches,avant=u".*(?:^| )",apres=u"(?:$|\.| |,|;).*",case_sensitive=False,debug=False):
47 if case_sensitive:
48 chain=unicode(chain,"utf8")
49 else:
50 chain=unicode(chain,"utf8").lower()
51 allmatches="("+"|".join(matches)+")"
52 reg=(avant+allmatches+apres).lower()
53 o=re.match(reg,chain)
54 return o
55
56 regexp_pan = re.compile(u".*(" + "|".join(config.killwords) + u").*")
57 def is_pan(chain):
58 return regexp_pan.match(unicode(chain,"utf8").lower())
59
60 class UnicodeBotError(Exception):
61 pass
62 def bot_unicode(chain):
63 try:
64 unicode(chain,"utf8")
65 except UnicodeDecodeError as exc:
66 raise UnicodeBotError
67
68 class Saturnin(ircbot.SingleServerIRCBot):
69 def __init__(self,serveur,debug=False):
70 temporary_pseudo=config.irc_pseudo+str(random.randrange(10000,100000))
71 ircbot.SingleServerIRCBot.__init__(self, [(serveur, 6667)],
72 temporary_pseudo,"Coin ? ©braice [mais 'faut frapper 20-100]", 10)
73 self.debug=debug
74 self.serveur=serveur
75 self.overops=config.overops
76 self.ops=self.overops+config.ops
77 self.chanlist=config.chanlist
78 self.stay_channels=config.stay_channels
79 self.quiet_channels=config.quiet_channels
80 self.play_channels=config.play_channels
81 self.status = { chan : [0, None] for chan in self.play_channels }
82 # 0 : pas de spawn prévu
83 # 1 : un spawn prévu,
84 # avec en deuxième paramètre le timestamp du moment où il a été déclenché (pas du moment où il se fera)
85 # 2 : alive
86 self.last_perdu=0
87
88 def give_me_my_pseudo(self,serv):
89 serv.privmsg("NickServ","RECOVER %s %s"%(config.irc_pseudo,config.irc_password))
90 serv.privmsg("NickServ","RELEASE %s %s"%(config.irc_pseudo,config.irc_password))
91 time.sleep(0.3)
92 serv.nick(config.irc_pseudo)
93
94 def on_welcome(self, serv, ev):
95 self.serv=serv # ça serv ira :)
96 self.give_me_my_pseudo(serv)
97 serv.privmsg("NickServ","IDENTIFY %s"%(config.irc_password))
98 log(self.serveur,"Connected")
99 if self.debug:
100 self.chanlist = self.play_channels = ["#bot"]
101 self.status = { chan : [0, 0] for chan in self.play_channels }
102 for c in self.chanlist:
103 log(self.serveur,"JOIN %s"%(c))
104 serv.join(c)
105 if c in self.play_channels:
106 spawn_delay = random.randrange(*config.spawn_delays)
107 self.spawn(c, time.time(), spawn_delay)
108
109 def pourmoi(self, serv, message):
110 """renvoie (False,lemessage) ou (True, le message amputé de "pseudo: ")"""
111 pseudo=self.nick
112 size=len(pseudo)
113 if message[:size]==pseudo and len(message)>size and message[size]==":":
114 return (True,message[size+1:].lstrip(" "))
115 else:
116 return (False,message)
117
118 def on_privmsg(self, serv, ev):
119 message=ev.arguments()[0]
120 auteur = irclib.nm_to_n(ev.source())
121 try:
122 test=bot_unicode(message)
123 except UnicodeBotError:
124 if config.utf8_trigger:
125 serv.privmsg(auteur, random.choice(config.utf8_fail_answers).encode("utf8"))
126 return
127 message=message.split()
128 cmd=message[0].lower()
129 notunderstood=False
130 if cmd=="help":
131 helpdico={"help":["""HELP <commande>
132 Affiche de l'aide sur la commande""",None,None],
133 "score":["""SCORE
134 Affiche votre score""", None, None],
135 "scores":["""SCORES
136 Afficher tous les scores""", None, None],
137 "join": [None, """JOIN <channel>
138 Me fait rejoindre le channel""",None],
139 "leave": [None,"""LEAVE <channel>
140 Me fait quitter le channel (sauf s'il est dans ma stay_list).""",None],
141 "quiet": [None,"""QUIET <channel>
142 Me rend silencieux sur le channel.""",None],
143 "noquiet": [None,"""NOQUIET <channel>
144 Me rend la parole sur le channel.""",None],
145 "play": [None, """PLAY
146 Passe un channel en mode "jouer" """,None],
147 "noplay": [None, """NOPLAY
148 Passe un channel en mode "ne pas jouer" """,None],
149 "SPAWN": [None, """SPAWN <channel>
150 Me fait spawner sur le channel.""",None],
151 "reload": [None,"""RELOAD
152 Recharge la configuration.""",None],
153 "say": [None,None,"""SAY <channel> <message>
154 Me fait parler sur le channel."""],
155 "do": [None,None,"""DO <channel> <action>
156 Me fait faitre une action (/me) sur le channel."""],
157 "stay": [None,None,"""STAY <channel>
158 Ajoute le channel à ma stay_list."""],
159 "nostay": [None,None,"""NOSTAY <channel>
160 Retire le channel de ma stay_list."""],
161 "ops": [None,None,"""OPS
162 Affiche la liste des ops."""],
163 "overops": [None,None,"""OVEROPS
164 Affiche la liste des overops."""],
165 "kick": [None,None,"""KICK <channel> <pseudo> [<raison>]
166 Kicke <pseudo> du channel (Il faut bien entendu que j'y sois op)."""],
167 "die": [None,None,"""DIE
168 Me déconnecte du serveur IRC."""]
169 }
170 helpmsg_default="Liste des commandes disponibles :\nHELP SCORE SCORES"
171 helpmsg_ops=" JOIN LEAVE QUIET NOQUIET PLAY NOPLAY SPAWN"
172 helpmsg_overops=" SAY DO STAY NOSTAY OPS OVEROPS KICK DIE"
173 op,overop=auteur in self.ops, auteur in self.overops
174 if len(message)==1:
175 helpmsg=helpmsg_default
176 if op:
177 helpmsg+=helpmsg_ops
178 if overop:
179 helpmsg+=helpmsg_overops
180 else:
181 helpmsgs=helpdico.get(message[1].lower(),["Commande inconnue.",None,None])
182 helpmsg=helpmsgs[0]
183 if op and helpmsgs[1]:
184 if helpmsg:
185 helpmsg+="\n"+helpmsgs[1]
186 else:
187 helpmsg=helpmsgs[1]
188 if overop and helpmsgs[2]:
189 if helpmsg:
190 helpmsg+="\n"+helpmsgs[2]
191 else:
192 helpmsg=helpmsgs[2]
193 for ligne in helpmsg.split("\n"):
194 serv.privmsg(auteur,ligne)
195 elif cmd=="join":
196 if auteur in self.ops:
197 if len(message)>1:
198 if message[1] in self.chanlist:
199 serv.privmsg(auteur,"Je suis déjà sur %s"%(message[1]))
200 else:
201 serv.join(message[1])
202 self.chanlist.append(message[1])
203 serv.privmsg(auteur,"Channels : "+" ".join(self.chanlist))
204 log(self.serveur,"priv",auteur," ".join(message))
205 else:
206 serv.privmsg(auteur,"Channels : "+" ".join(self.chanlist))
207 else:
208 notunderstood=True
209 elif cmd=="leave":
210 if auteur in self.ops and len(message)>1:
211 if message[1] in self.chanlist:
212 if not (message[1] in self.stay_channels) or auteur in self.overops:
213 self.quitter(message[1]," ".join(message[2:]))
214 self.chanlist.remove(message[1])
215 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
216 else:
217 serv.privmsg(auteur,"Non, je reste !")
218 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
219 else:
220 serv.privmsg(auteur,"Je ne suis pas sur %s"%(message[1]))
221 else:
222 notunderstood=True
223 elif cmd=="stay":
224 if auteur in self.overops:
225 if len(message)>1:
226 if message[1] in self.stay_channels:
227 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
228 serv.privmsg(auteur,"Je stay déjà sur %s."%(message[1]))
229 else:
230 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
231 self.stay_channels.append(message[1])
232 serv.privmsg(auteur,"Stay channels : "+" ".join(self.stay_channels))
233 else:
234 serv.privmsg(auteur,"Stay channels : "+" ".join(self.stay_channels))
235 else:
236 notunderstood=True
237 elif cmd=="nostay":
238 if auteur in self.overops:
239 if len(message)>1:
240 if message[1] in self.stay_channels:
241 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
242 self.stay_channels.remove(message[1])
243 serv.privmsg(auteur,"Stay channels : "+" ".join(self.stay_channels))
244 else:
245 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
246 serv.privmsg(auteur,"Je ne stay pas sur %s."%(message[1]))
247
248 else:
249 notunderstood=True
250 elif cmd=="die":
251 if auteur in self.overops:
252 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
253 self.mourir()
254 else:
255 notunderstood=True
256 elif cmd=="quiet":
257 if auteur in self.ops:
258 if len(message)>1:
259 if message[1] in self.quiet_channels:
260 serv.privmsg(auteur,"Je me la ferme déjà sur %s"%(message[1]))
261 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
262 else:
263 self.quiet_channels.append(message[1])
264 serv.privmsg(auteur,"Quiet channels : "+" ".join(self.quiet_channels))
265 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
266 else:
267 serv.privmsg(auteur,"Quiet channels : "+" ".join(self.quiet_channels))
268 else:
269 notunderstood=True
270 elif cmd=="noquiet":
271 if auteur in self.ops:
272 if len(message)>1:
273 if message[1] in self.quiet_channels:
274 self.quiet_channels.remove(message[1])
275 serv.privmsg(auteur,"Quiet channels : "+" ".join(self.quiet_channels))
276 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
277 else:
278 serv.privmsg(auteur,"Je ne me la ferme pas sur %s."%(message[1]))
279 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
280 else:
281 notunderstood=True
282 elif cmd=="play":
283 if auteur in self.ops:
284 if len(message)>1:
285 if message[1] in self.play_channels:
286 serv.privmsg(auteur,"Je play déjà sur %s."%(message[1]))
287 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
288 else:
289 self.play_channels.append(message[1])
290 self.spawn(message[1], 1)
291 serv.privmsg(auteur,"Play channels : "+" ".join(self.play_channels))
292 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
293 else:
294 serv.privmsg(auteur,"Play channels : "+" ".join(self.play_channels))
295 else:
296 notunderstood=True
297 elif cmd=="noplay":
298 if auteur in self.ops:
299 if len(message)>1:
300 if message[1] in self.play_channels:
301 self.play_channels.remove(message[1])
302 serv.privmsg(auteur,"Play channels : "+" ".join(self.play_channels))
303 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
304 else:
305 serv.privmsg(auteur,"Je ne play pas sur %s."%(message[1]))
306 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
307 else:
308 notunderstood=True
309 elif cmd=="status":
310 if auteur in self.ops:
311 serv.privmsg(auteur,"Status : %s" % (self.status, ))
312 else:
313 notunderstood=True
314 elif cmd=="spawn":
315 if auteur in self.ops:
316 if len(message)>1:
317 if message[1] in self.play_channels:
318 # Le plus pratique pour pas s'embêter c'est de mettre un
319 # delay d'une seconde, comme ça .spawn() fait le boulot
320 self.spawn(message[1], time.time(), 1)
321 else:
322 serv.privmsg(auteur, "Je ne joue pas sur %s" % message[1])
323 else:
324 serv.privmsg(auteur, "Syntaxe : SPAWN <channel>")
325 else:
326 notunderstood=True
327 elif cmd=="say":
328 if auteur in self.overops and len(message)>2:
329 serv.privmsg(message[1]," ".join(message[2:]))
330 log(self.serveur,"priv",auteur," ".join(message))
331 elif len(message)<=2:
332 serv.privmsg(auteur,"Syntaxe : SAY <channel> <message>")
333 else:
334 notunderstood=True
335 elif cmd=="do":
336 if auteur in self.overops and len(message)>2:
337 serv.action(message[1]," ".join(message[2:]))
338 log(self.serveur,"priv",auteur," ".join(message))
339 elif len(message)<=2:
340 serv.privmsg(auteur,"Syntaxe : DO <channel> <action>")
341 else:
342 notunderstood=True
343 elif cmd=="kick":
344 if auteur in self.overops and len(message)>2:
345 serv.kick(message[1],message[2]," ".join(message[3:]))
346 log(self.serveur,"priv",auteur," ".join(message))
347 elif len(message)<=2:
348 serv.privmsg(auteur,"Syntaxe : KICK <channel> <pseudo> [<raison>]")
349 else:
350 notunderstood=True
351 elif cmd=="ops":
352 if auteur in self.overops:
353 serv.privmsg(auteur," ".join(self.ops))
354 else:
355 notunderstood=True
356 elif cmd=="overops":
357 if auteur in self.overops:
358 serv.privmsg(auteur," ".join(self.overops))
359 else:
360 notunderstood=True
361 elif cmd=="reload":
362 if auteur in self.ops:
363 self.reload(auteur)
364 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
365 else:
366 notunderstood=True
367 elif cmd=="score":
368 if len(message)>1:
369 if len(message) in [3,4] and message[1].lower()=="transfert":
370 scores=self.get_scores()
371 de,to=auteur,message[2]
372 value=scores.get(de,0)
373 if len(message)==4:
374 try:
375 asked=int(message[3])
376 except ValueError:
377 serv.privmsg(auteur,"Syntaxe : SCORE TRANSFERT <pseudo> [<n>]")
378 return
379 else:
380 asked=value
381 if value==0:
382 serv.privmsg(auteur,"Vous n'avez pas de points")
383 return
384 elif asked<=0:
385 serv.privmsg(auteur,"Bien tenté…")
386 return
387 elif asked>value:
388 serv.privmsg(auteur,"Vous n'avez que %s points"%(value))
389 return
390 else:
391 self.add_score(de,-asked)
392 self.add_score(to,asked)
393 serv.privmsg(auteur,"Transfert de %s points de %s à %s"%(asked,de,to))
394 else:
395 serv.privmsg(auteur,"Syntaxe : SCORE TRANSFERT <pseudo> [<n>]")
396 else:
397 self.sendscore(auteur)
398 elif cmd=="scores":
399 if len(message)==1:
400 self.sendscores(auteur)
401 elif auteur in self.overops:
402 souscmd=message[1].lower()
403 if souscmd=="del":
404 if len(message)==3:
405 todelete=message[2]
406 scores=self.get_scores()
407 if scores.has_key(todelete):
408 del scores[todelete]
409 self.save_scores(scores)
410 serv.privmsg(auteur,"Score de %s supprimé"%(todelete))
411 else:
412 serv.privmsg(auteur,"Ce score n'existe pas : %s"%(todelete))
413 else:
414 serv.privmsg(auteur,"Syntaxe : SCORES DEL <pseudo>")
415 elif souscmd in ["add","sub"]:
416 if len(message)==4:
417 toadd,val=message[2],message[3]
418 try:
419 val=int(val)
420 except ValueError:
421 serv.privmsg(auteur,"Syntaxe : SCORES {ADD|SUB} <pseudo> <n>")
422 return
423 if souscmd=="sub":
424 val=-val
425 self.add_score(toadd,val)
426 serv.privmsg(auteur,"Done")
427 else:
428 serv.privmsg(auteur,"Syntaxe : SCORES {ADD|SUB} <pseudo> <n>")
429 else:
430 serv.privmsg(auteur,"Syntaxe : SCORES {DEL|ADD|SUB} <pseudo> [<n>]")
431 else:
432 notunderstood=True
433 else:
434 notunderstood=True
435 if notunderstood:
436 serv.privmsg(auteur,"Je n'ai pas compris. Essayez HELP…")
437
438 def sendscore(self, to):
439 self.serv.privmsg(to, "Votre score : %s"%(self.get_scores().get(to,0)) )
440
441 def sendscores(self, to):
442 scores=self.get_scores().items()
443 # trie par score
444 scores.sort(lambda x,y:cmp(x[1],y[1]))
445 scores.reverse()
446 self.serv.privmsg(to, "Scores by score : "+" ; ".join(["%s %s"%(i[0],i[1]) for i in scores]))
447 # trie par pseudo
448 scores.sort(lambda x,y:cmp(x[0].lower(),y[0].lower()))
449 self.serv.privmsg(to, "Scores by pseudo : "+" ; ".join(["%s %s"%(i[0],i[1]) for i in scores]))
450
451 def on_pubmsg(self, serv, ev):
452 auteur = irclib.nm_to_n(ev.source())
453 if re.match(config.ignored_pseudos, auteur):
454 return
455 channel = ev.target()
456 message = ev.arguments()[0]
457 try:
458 test=bot_unicode(message)
459 except UnicodeBotError:
460 if config.utf8_trigger and not channel in self.quiet_channels:
461 serv.privmsg(channel, (u"%s: %s"%(auteur,random.choice(config.utf8_fail_answers))).encode("utf8"))
462 return
463 pour_moi,message=self.pourmoi(serv,message)
464 if pour_moi and message.split()!=[]:
465 cmd=message.split()[0].lower()
466 try:
467 args=" ".join(message.split()[1:])
468 except:
469 args=""
470 if cmd in ["meurs","die","crève"]:
471 if auteur in self.overops:
472 log(self.serveur,channel,auteur,message+"[successful]")
473 self.mourir()
474 else:
475 serv.privmsg(channel,("%s: %s"%(auteur,random.choice(config.quit_fail_messages))).encode("utf8"))
476 log(self.serveur,channel,auteur,message+"[failed]")
477 elif cmd == "reload":
478 if auteur in self.ops:
479 log(self.serveur, channel, auteur, message+"[successful]")
480 self.reload(channel)
481 elif cmd in ["part","leave","dégage","va-t-en","tut'tiresailleurs,c'estmesgalets"]:
482 if auteur in self.ops and (not (channel in self.stay_channels)
483 or auteur in self.overops):
484 self.quitter(channel)
485 log(self.serveur,channel,auteur,message+"[successful]")
486 if channel in self.chanlist:
487 self.chanlist.remove(channel)
488 else:
489 serv.privmsg(channel,("%s: %s"%(auteur,random.choice(config.leave_fail_messages))).encode("utf8"))
490 log(self.serveur,channel,auteur,message+"[failed]")
491 elif cmd == "score":
492 self.sendscore(auteur)
493 elif cmd == "scores":
494 self.sendscores(auteur)
495 else:
496 if is_pan(message):
497 self.shot(channel, auteur)
498
499 def on_action(self, serv, ev):
500 action = ev.arguments()[0]
501 auteur = irclib.nm_to_n(ev.source())
502 channel = ev.target()
503 #~ try:
504 #~ test=bot_unicode(action)
505 #~ except UnicodeBotError:
506 #~ if config.utf8_trigger and not channel in self.quiet_channels:
507 #~ serv.privmsg(channel, (u"%s: %s"%(auteur,random.choice(config.utf8_fail_answers))).encode("utf8"))
508 #~ return
509 #~ mypseudo=self.nick
510
511 def on_kick(self,serv,ev):
512 auteur = irclib.nm_to_n(ev.source())
513 channel = ev.target()
514 victime = ev.arguments()[0]
515 raison = ev.arguments()[1]
516 if victime==self.nick:
517 log(self.serveur,"%s kické de %s par %s (raison : %s)" %(victime,channel,auteur,raison))
518 time.sleep(2)
519 serv.join(channel)
520 #~ l1,l2=config.kick_answers,config.kick_actions
521 #~ n1,n2=len(l1),len(l2)
522 #~ i=random.randrange(n1+n2)
523 #~ if i>=n1:
524 #~ serv.action(channel,l2[i-n1].format(auteur).encode("utf8"))
525 #~ else:
526 #~ serv.privmsg(channel,l1[i].format(auteur).encode("utf8"))
527
528 def spawn(self, channel, timestamp, delay=0):
529 if channel in self.play_channels:
530 if delay>0:
531 self.serv.execute_delayed(delay, self.spawn, (channel, timestamp))
532 self.status[channel] = [1, timestamp]
533 else:
534 # on teste le timestamp pour pas s'emmêler dans les spawn
535 infos = self.status.get(channel, [0,0])
536 if infos == [1, timestamp]:
537 spawn_sentence = random.choice(config.canards) + random.choice(config.spawn_sentences)
538 self.serv.privmsg(channel, spawn_sentence.encode("utf8"))
539 self.status[channel] = [2, timestamp]
540 times_up_delay = random.randrange(*config.times_up_delays)
541 self.serv.execute_delayed(times_up_delay, self.too_slow, (channel, timestamp))
542
543 def too_slow(self, channel, timestamp):
544 infos = self.status.get(channel, [0,0])
545 if infos == [2, timestamp]:
546 self.serv.privmsg(channel, random.choice(config.times_up_sentences).encode("utf8"))
547 respawn_delay = random.randrange(*config.spawn_delays)
548 self.spawn(channel, time.time(), respawn_delay)
549
550 def shot(self, channel, auteur):
551 if self.status.get(channel, [0, 0])[0] == 2:
552 succeed = random.randrange(0,101) > config.proba_miss
553 if succeed:
554 self.serv.privmsg(channel, random.choice(config.killed_templates).format(auteur).encode("utf8"))
555 self.add_score(auteur, 1)
556 if random.randrange(0, 101) < config.proba_killed_sentence:
557 self.serv.privmsg(channel, random.choice(config.killed_sentences).encode("utf8"))
558 respawn_delay = random.randrange(*config.spawn_delays)
559 self.spawn(channel, time.time(), respawn_delay)
560 else:
561 self.serv.privmsg(channel, random.choice(config.miss_templates).format(auteur).encode("utf8"))
562 if random.randrange(0,101) < config.proba_miss_sentence:
563 self.serv.privmsg(channel, random.choice(config.miss_sentences).encode("utf8"))
564
565 def quitter(self,chan,leave_message=None):
566 if leave_message==None:
567 leave_message=random.choice(config.leave_messages)
568 self.serv.part(chan,message=leave_message.encode("utf8"))
569
570 def mourir(self):
571 quit_message=random.choice(config.quit_messages)
572 self.die(msg=quit_message.encode("utf8"))
573
574 def get_scores(self):
575 f=open(config.score_file)
576 scores=pickle.load(f)
577 f.close()
578 return scores
579
580 def add_score(self, pseudo, value):
581 scores=self.get_scores()
582 if scores.has_key(pseudo):
583 scores[pseudo]+=value
584 else:
585 scores[pseudo]=value
586 self.save_scores(scores)
587
588 def save_scores(self,scores):
589 f=open(config.score_file,"w")
590 pickle.dump(scores,f)
591 f.close()
592
593 def _getnick(self):
594 return self.serv.get_nickname()
595 nick=property(_getnick)
596
597 def reload(self, auteur=None):
598 reload(config)
599 if auteur in [None, "SIGHUP"]:
600 towrite = "Config reloaded" + " (SIGHUP received)"*(auteur == "SIGHUP")
601 for to in config.report_bugs_to:
602 self.serv.privmsg(to, towrite)
603 log(self.serveur, towrite)
604 else:
605 self.serv.privmsg(auteur,"Config reloaded")
606
607 def start_as_daemon(self, outfile):
608 sys.stderr = Logger(outfile)
609 self.start()
610
611
612 class Logger(object):
613 """Pour écrire ailleurs que sur stdout"""
614 def __init__(self, filename="saturnin.full.log"):
615 self.filename = filename
616
617 def write(self, message):
618 f = open(self.filename, "a")
619 f.write(message)
620 f.close()
621
622
623 if __name__=="__main__":
624 import sys
625 if len(sys.argv)==1:
626 print "Usage : saturnin.py <serveur> [--debug] [--no-output] [--daemon [--pidfile]] [--outfile]"
627 print " --outfile sans --no-output ni --daemon n'a aucun effet"
628 exit(1)
629 serveur=sys.argv[1]
630 if "--daemon" in sys.argv:
631 thisfile = os.path.realpath(__file__)
632 thisdirectory = thisfile.rsplit("/", 1)[0]
633 os.chdir(thisdirectory)
634 daemon = True
635 else:
636 daemon = False
637 if "debug" in sys.argv or "--debug" in sys.argv:
638 debug=True
639 else:
640 debug=False
641 if "--no-output" in sys.argv or "--daemon" in sys.argv:
642 outfile = "/var/log/bots/saturnin.full.log"
643 for arg in sys.argv:
644 arg = arg.split("=")
645 if arg[0].strip('-') in ["out", "outfile", "logfile"]:
646 outfile = arg[1]
647 sys.stdout = Logger(outfile)
648 if "--quiet" in sys.argv:
649 config.debug_stdout=False
650 serveurs={"a♡":"acoeur.crans.org","acoeur":"acoeur.crans.org","acoeur.crans.org":"acoeur.crans.org",
651 "irc":"irc.crans.org","crans":"irc.crans.org","irc.crans.org":"irc.crans.org",
652 "local":"localhost"}
653 try:
654 serveur=serveurs[serveur]
655 except KeyError:
656 print "Server Unknown : %s"%(serveur)
657 exit(404)
658 saturnin = Saturnin(serveur,debug)
659 # Si on reçoit un SIGHUP, on reload la config
660 def sighup_handler(signum, frame):
661 saturnin.reload("SIGHUP")
662 signal.signal(signal.SIGHUP, sighup_handler)
663 if daemon:
664 child_pid = os.fork()
665 if child_pid == 0:
666 os.setsid()
667 saturnin.start_as_daemon(outfile)
668 else:
669 # on enregistre le pid de saturnin
670 pidfile = "/var/run/bots/saturnin.pid"
671 for arg in sys.argv:
672 arg = arg.split("=")
673 if arg[0].strip('-') in ["pidfile"]:
674 pidfile = arg[1]
675 f = open(pidfile, "w")
676 f.write("%s\n" % child_pid)
677 f.close()
678 else:
679 saturnin.start()
680