]> gitweb.pimeys.fr Git - bots/saturnin.git/blob - saturnin.py
34380206d62e514cae867710653455c2ac06a9a4
[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=="spawn":
310 if auteur in self.ops:
311 if len(message)>1:
312 if message[1] in self.play_channels:
313 # Le plus pratique pour pas s'embêter c'est de mettre un
314 # delay d'une seconde, comme ça .spawn() fait le boulot
315 self.spawn(message[1], time.time(), 1)
316 else:
317 serv.privmsg(auteur, "Je ne joue pas sur %s" % message[1])
318 else:
319 serv.privmsg(auteur, "Syntaxe : SPAWN <channel>")
320 else:
321 notunderstood=True
322 elif cmd=="say":
323 if auteur in self.overops and len(message)>2:
324 serv.privmsg(message[1]," ".join(message[2:]))
325 log(self.serveur,"priv",auteur," ".join(message))
326 elif len(message)<=2:
327 serv.privmsg(auteur,"Syntaxe : SAY <channel> <message>")
328 else:
329 notunderstood=True
330 elif cmd=="do":
331 if auteur in self.overops and len(message)>2:
332 serv.action(message[1]," ".join(message[2:]))
333 log(self.serveur,"priv",auteur," ".join(message))
334 elif len(message)<=2:
335 serv.privmsg(auteur,"Syntaxe : DO <channel> <action>")
336 else:
337 notunderstood=True
338 elif cmd=="kick":
339 if auteur in self.overops and len(message)>2:
340 serv.kick(message[1],message[2]," ".join(message[3:]))
341 log(self.serveur,"priv",auteur," ".join(message))
342 elif len(message)<=2:
343 serv.privmsg(auteur,"Syntaxe : KICK <channel> <pseudo> [<raison>]")
344 else:
345 notunderstood=True
346 elif cmd=="ops":
347 if auteur in self.overops:
348 serv.privmsg(auteur," ".join(self.ops))
349 else:
350 notunderstood=True
351 elif cmd=="overops":
352 if auteur in self.overops:
353 serv.privmsg(auteur," ".join(self.overops))
354 else:
355 notunderstood=True
356 elif cmd=="reload":
357 if auteur in self.ops:
358 self.reload(auteur)
359 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
360 else:
361 notunderstood=True
362 elif cmd=="score":
363 if len(message)>1:
364 if len(message) in [3,4] and message[1].lower()=="transfert":
365 scores=self.get_scores()
366 de,to=auteur,message[2]
367 value=scores.get(de,0)
368 if len(message)==4:
369 try:
370 asked=int(message[3])
371 except ValueError:
372 serv.privmsg(auteur,"Syntaxe : SCORE TRANSFERT <pseudo> [<n>]")
373 return
374 else:
375 asked=value
376 if value==0:
377 serv.privmsg(auteur,"Vous n'avez pas de points")
378 return
379 elif asked<=0:
380 serv.privmsg(auteur,"Bien tenté…")
381 return
382 elif asked>value:
383 serv.privmsg(auteur,"Vous n'avez que %s points"%(value))
384 return
385 else:
386 self.add_score(de,-asked)
387 self.add_score(to,asked)
388 serv.privmsg(auteur,"Transfert de %s points de %s à %s"%(asked,de,to))
389 else:
390 serv.privmsg(auteur,"Syntaxe : SCORE TRANSFERT <pseudo> [<n>]")
391 else:
392 self.sendscore(auteur)
393 elif cmd=="scores":
394 if len(message)==1:
395 self.sendscores(auteur)
396 elif auteur in self.overops:
397 souscmd=message[1].lower()
398 if souscmd=="del":
399 if len(message)==3:
400 todelete=message[2]
401 scores=self.get_scores()
402 if scores.has_key(todelete):
403 del scores[todelete]
404 self.save_scores(scores)
405 serv.privmsg(auteur,"Score de %s supprimé"%(todelete))
406 else:
407 serv.privmsg(auteur,"Ce score n'existe pas : %s"%(todelete))
408 else:
409 serv.privmsg(auteur,"Syntaxe : SCORES DEL <pseudo>")
410 elif souscmd in ["add","sub"]:
411 if len(message)==4:
412 toadd,val=message[2],message[3]
413 try:
414 val=int(val)
415 except ValueError:
416 serv.privmsg(auteur,"Syntaxe : SCORES {ADD|SUB} <pseudo> <n>")
417 return
418 if souscmd=="sub":
419 val=-val
420 self.add_score(toadd,val)
421 serv.privmsg(auteur,"Done")
422 else:
423 serv.privmsg(auteur,"Syntaxe : SCORES {ADD|SUB} <pseudo> <n>")
424 else:
425 serv.privmsg(auteur,"Syntaxe : SCORES {DEL|ADD|SUB} <pseudo> [<n>]")
426 else:
427 notunderstood=True
428 else:
429 notunderstood=True
430 if notunderstood:
431 serv.privmsg(auteur,"Je n'ai pas compris. Essayez HELP…")
432
433 def sendscore(self, to):
434 self.serv.privmsg(to, "Votre score : %s"%(self.get_scores().get(to,0)) )
435
436 def sendscores(self, to):
437 scores=self.get_scores().items()
438 # trie par score
439 scores.sort(lambda x,y:cmp(x[1],y[1]))
440 scores.reverse()
441 self.serv.privmsg(to, "Scores by score : "+" ; ".join(["%s %s"%(i[0],i[1]) for i in scores]))
442 # trie par pseudo
443 scores.sort(lambda x,y:cmp(x[0].lower(),y[0].lower()))
444 self.serv.privmsg(to, "Scores by pseudo : "+" ; ".join(["%s %s"%(i[0],i[1]) for i in scores]))
445
446 def on_pubmsg(self, serv, ev):
447 auteur = irclib.nm_to_n(ev.source())
448 channel = ev.target()
449 message = ev.arguments()[0]
450 try:
451 test=bot_unicode(message)
452 except UnicodeBotError:
453 if config.utf8_trigger and not channel in self.quiet_channels:
454 serv.privmsg(channel, (u"%s: %s"%(auteur,random.choice(config.utf8_fail_answers))).encode("utf8"))
455 return
456 pour_moi,message=self.pourmoi(serv,message)
457 if pour_moi and message.split()!=[]:
458 cmd=message.split()[0].lower()
459 try:
460 args=" ".join(message.split()[1:])
461 except:
462 args=""
463 if cmd in ["meurs","die","crève"]:
464 if auteur in self.overops:
465 log(self.serveur,channel,auteur,message+"[successful]")
466 self.mourir()
467 else:
468 serv.privmsg(channel,("%s: %s"%(auteur,random.choice(config.quit_fail_messages))).encode("utf8"))
469 log(self.serveur,channel,auteur,message+"[failed]")
470 elif cmd == "reload":
471 if auteur in self.ops:
472 log(self.serveur, channel, auteur, message+"[successful]")
473 self.reload(channel)
474 elif cmd in ["part","leave","dégage","va-t-en","tut'tiresailleurs,c'estmesgalets"]:
475 if auteur in self.ops and (not (channel in self.stay_channels)
476 or auteur in self.overops):
477 self.quitter(channel)
478 log(self.serveur,channel,auteur,message+"[successful]")
479 if channel in self.chanlist:
480 self.chanlist.remove(channel)
481 else:
482 serv.privmsg(channel,("%s: %s"%(auteur,random.choice(config.leave_fail_messages))).encode("utf8"))
483 log(self.serveur,channel,auteur,message+"[failed]")
484 elif cmd == "score":
485 self.sendscore(auteur)
486 elif cmd == "scores":
487 self.sendscores(auteur)
488 else:
489 if is_pan(message):
490 self.shot(channel, auteur)
491
492 def on_action(self, serv, ev):
493 action = ev.arguments()[0]
494 auteur = irclib.nm_to_n(ev.source())
495 channel = ev.target()
496 #~ try:
497 #~ test=bot_unicode(action)
498 #~ except UnicodeBotError:
499 #~ if config.utf8_trigger and not channel in self.quiet_channels:
500 #~ serv.privmsg(channel, (u"%s: %s"%(auteur,random.choice(config.utf8_fail_answers))).encode("utf8"))
501 #~ return
502 #~ mypseudo=self.nick
503
504 def on_kick(self,serv,ev):
505 auteur = irclib.nm_to_n(ev.source())
506 channel = ev.target()
507 victime = ev.arguments()[0]
508 raison = ev.arguments()[1]
509 if victime==self.nick:
510 log(self.serveur,"%s kické de %s par %s (raison : %s)" %(victime,channel,auteur,raison))
511 time.sleep(2)
512 serv.join(channel)
513 #~ l1,l2=config.kick_answers,config.kick_actions
514 #~ n1,n2=len(l1),len(l2)
515 #~ i=random.randrange(n1+n2)
516 #~ if i>=n1:
517 #~ serv.action(channel,l2[i-n1].format(auteur).encode("utf8"))
518 #~ else:
519 #~ serv.privmsg(channel,l1[i].format(auteur).encode("utf8"))
520
521 def spawn(self, channel, timestamp, delay=0):
522 if channel in self.play_channels:
523 if delay>0:
524 self.serv.execute_delayed(delay, self.spawn, (channel, timestamp))
525 self.status[channel] = [1, timestamp]
526 else:
527 # on teste le timestamp pour pas s'emmêler dans les spawn
528 infos = self.status.get(channel, [0,0])
529 if infos == [1, timestamp]:
530 spawn_sentence = random.choice(config.canards) + random.choice(config.spawn_sentences)
531 self.serv.privmsg(channel, spawn_sentence.encode("utf8"))
532 self.status[channel] = [2, timestamp]
533 times_up_delay = random.randrange(*config.times_up_delays)
534 self.serv.execute_delayed(times_up_delay, self.too_slow, (channel, timestamp))
535
536 def too_slow(self, channel, timestamp):
537 infos = self.status.get(channel, [0,0])
538 if infos == [2, timestamp]:
539 self.serv.privmsg(channel, random.choice(config.times_up_sentences).encode("utf8"))
540 respawn_delay = random.randrange(*config.spawn_delays)
541 self.spawn(channel, time.time(), respawn_delay)
542
543 def shot(self, channel, auteur):
544 if self.status.get(channel, [0, 0])[0] == 2:
545 succeed = random.randrange(0,101) > config.proba_miss
546 if succeed:
547 self.serv.privmsg(channel, random.choice(config.killed_templates).format(auteur).encode("utf8"))
548 self.add_score(auteur, 1)
549 if random.randrange(0, 101) < config.proba_killed_sentence:
550 self.serv.privmsg(channel, random.choice(config.killed_sentences).encode("utf8"))
551 respawn_delay = random.randrange(*config.spawn_delays)
552 self.spawn(channel, time.time(), respawn_delay)
553 else:
554 self.serv.privmsg(channel, random.choice(config.miss_templates).format(auteur).encode("utf8"))
555 if random.randrange(0,101) < config.proba_miss_sentence:
556 self.serv.privmsg(channel, random.choice(config.miss_sentences).encode("utf8"))
557
558 def quitter(self,chan,leave_message=None):
559 if leave_message==None:
560 leave_message=random.choice(config.leave_messages)
561 self.serv.part(chan,message=leave_message.encode("utf8"))
562
563 def mourir(self):
564 quit_message=random.choice(config.quit_messages)
565 self.die(msg=quit_message.encode("utf8"))
566
567 def get_scores(self):
568 f=open(config.score_file)
569 scores=pickle.load(f)
570 f.close()
571 return scores
572
573 def add_score(self, pseudo, value):
574 scores=self.get_scores()
575 if scores.has_key(pseudo):
576 scores[pseudo]+=value
577 else:
578 scores[pseudo]=value
579 self.save_scores(scores)
580
581 def save_scores(self,scores):
582 f=open(config.score_file,"w")
583 pickle.dump(scores,f)
584 f.close()
585
586 def _getnick(self):
587 return self.serv.get_nickname()
588 nick=property(_getnick)
589
590 def reload(self, auteur=None):
591 reload(config)
592 if auteur in [None, "SIGHUP"]:
593 towrite = "Config reloaded" + " (SIGHUP received)"*(auteur == "SIGHUP")
594 for to in config.report_bugs_to:
595 self.serv.privmsg(to, towrite)
596 log(self.serveur, towrite)
597 else:
598 self.serv.privmsg(auteur,"Config reloaded")
599
600 def start_as_daemon(self, outfile):
601 sys.stderr = Logger(outfile)
602 self.start()
603
604
605 class Logger(object):
606 """Pour écrire ailleurs que sur stdout"""
607 def __init__(self, filename="saturnin.full.log"):
608 self.filename = filename
609
610 def write(self, message):
611 f = open(self.filename, "a")
612 f.write(message)
613 f.close()
614
615
616 if __name__=="__main__":
617 import sys
618 if len(sys.argv)==1:
619 print "Usage : saturnin.py <serveur> [--debug] [--no-output] [--daemon [--pidfile]] [--outfile]"
620 print " --outfile sans --no-output ni --daemon n'a aucun effet"
621 exit(1)
622 serveur=sys.argv[1]
623 if "--daemon" in sys.argv:
624 thisfile = os.path.realpath(__file__)
625 thisdirectory = thisfile.rsplit("/", 1)[0]
626 os.chdir(thisdirectory)
627 daemon = True
628 else:
629 daemon = False
630 if "debug" in sys.argv or "--debug" in sys.argv:
631 debug=True
632 else:
633 debug=False
634 if "--no-output" in sys.argv or "--daemon" in sys.argv:
635 outfile = "/var/log/bots/saturnin.full.log"
636 for arg in sys.argv:
637 arg = arg.split("=")
638 if arg[0].strip('-') in ["out", "outfile", "logfile"]:
639 outfile = arg[1]
640 sys.stdout = Logger(outfile)
641 if "--quiet" in sys.argv:
642 config.debug_stdout=False
643 serveurs={"a♡":"acoeur.crans.org","acoeur":"acoeur.crans.org","acoeur.crans.org":"acoeur.crans.org",
644 "irc":"irc.crans.org","crans":"irc.crans.org","irc.crans.org":"irc.crans.org",
645 "local":"localhost"}
646 try:
647 serveur=serveurs[serveur]
648 except KeyError:
649 print "Server Unknown : %s"%(serveur)
650 exit(404)
651 saturnin = Saturnin(serveur,debug)
652 # Si on reçoit un SIGHUP, on reload la config
653 def sighup_handler(signum, frame):
654 saturnin.reload("SIGHUP")
655 signal.signal(signal.SIGHUP, sighup_handler)
656 if daemon:
657 child_pid = os.fork()
658 if child_pid == 0:
659 os.setsid()
660 saturnin.start_as_daemon(outfile)
661 else:
662 # on enregistre le pid de saturnin
663 pidfile = "/var/run/bots/saturnin.pid"
664 for arg in sys.argv:
665 arg = arg.split("=")
666 if arg[0].strip('-') in ["pidfile"]:
667 pidfile = arg[1]
668 f = open(pidfile, "w")
669 f.write("%s\n" % child_pid)
670 f.close()
671 else:
672 saturnin.start()
673