]> gitweb.pimeys.fr Git - bots/hung.git/blob - hung.py
Fonction de blacklist
[bots/hung.git] / hung.py
1 #!/usr/bin/python
2 # -*- coding:utf8 -*-
3
4 # Codé par 20-100 le 23/04/12
5
6 # Un bot IRC qui joue au pendu
7
8 import threading
9 import random
10 import time
11 import socket, ssl, json
12 import pickle
13 import re
14 import os
15 import signal
16 import sys
17 from commands import getstatusoutput as ex
18
19 # Oui, j'ai recodé ma version d'irclib pour pouvoir rattrapper les SIGHUP
20 sys.path.insert(0, "/home/vincent/scripts/python-myirclib")
21 import irclib
22 import ircbot
23
24 import sys
25
26 # Fichier de conf
27 import config
28
29 def get_config_logfile(serveur):
30 serveurs={"acoeur.crans.org":"acoeur","irc.crans.org":"crans","localhost":"localhost"}
31 return config.logfile_template%(serveurs[serveur])
32
33 def log(serveur,channel,auteur=None,message=None):
34 f=open(get_config_logfile(serveur),"a")
35 if auteur==message==None:
36 # alors c'est que c'est pas un channel mais juste une ligne de log
37 chain="%s %s"%(time.strftime("%F %T"),channel)
38 else:
39 chain="%s [%s:%s] %s"%(time.strftime("%F %T"),channel,auteur,message)
40 f.write(chain+"\n")
41 if config.debug_stdout:
42 print chain
43 f.close()
44
45 def ignore_event(serv, ev):
46 """Retourne ``True`` si il faut ignorer cet évènement."""
47 for (blackmask, exceptmask) in config.blacklisted_masks:
48 usermask = ev.source()
49 if exceptmask is None:
50 exceptit = False
51 else:
52 exceptit = bool(irclib.mask_matches(usermask, exceptmask))
53 blackit = bool(irclib.mask_matches(usermask, blackmask))
54 return blackit and not exceptit
55
56 class UnicodeBotError(Exception):
57 pass
58 def bot_unicode(chain):
59 try:
60 unicode(chain,"utf8")
61 except UnicodeDecodeError as exc:
62 raise UnicodeBotError
63
64 def remplace_accents(chaine):
65 chaine=chaine.lower()
66 remplacements = {u"á":u"a",u"à":u"a",u"â":u"a",u"ä":u"a",u"é":u"e",u"è":u"e",u"ê":u"e",u"ë":u"e",u"í":u"i",u"ì":u"i",u"î":u"i",u"ï":u"i",u"ó":u"o", u"ò":u"o",u"ô":u"o",u"ö":u"o",u"ú":u"u",u"ù":u"u",u"û":u"u",u"ü":u"u",u"ý":u"y",u"ỳ":u"y",u"ŷ":u"y",u"ÿ":u"y",u"œ":u"oe",u"æ":u"ae"}
67 for avant,apres in remplacements.items():
68 chaine=chaine.replace(avant,apres)
69 return chaine
70
71 def is_something(chain,matches,avant=u".*(?:^| )",apres=u"(?:$|\.| |,|;).*",case_sensitive=False,debug=False):
72 if case_sensitive:
73 chain=unicode(chain,"utf8")
74 else:
75 chain=unicode(chain,"utf8").lower()
76 allmatches="("+"|".join(matches)+")"
77 reg=(avant+allmatches+apres).lower()
78 o=re.match(reg,chain)
79 return o
80
81 def is_tag(chain):
82 return is_something(chain,config.tag_triggers)
83
84 def is_mot(mot,liste):
85 real_word = "".join([lettre[0] for lettre in liste])
86 real_word = real_word.decode("utf8").lower()
87 mot=remplace_accents(mot.decode("utf8"))
88 return mot.startswith(real_word)
89
90 class Hung(ircbot.SingleServerIRCBot):
91 def __init__(self,serveur,debug=False):
92 temporary_pseudo=config.irc_pseudo+str(random.randrange(10000,100000))
93 ircbot.SingleServerIRCBot.__init__(self, [(serveur, 6667)],
94 temporary_pseudo,"Bot irc pour jouer au pendu", 10)
95 self.debug=debug
96 self.serveur=serveur
97 self.overops=config.overops
98 self.ops=self.overops+config.ops
99 self.report_bugs_to=config.report_bugs_to
100 self.chanlist=config.chanlist
101 self.stay_channels=config.stay_channels
102 self.play_channels=config.play_channels
103 self.play_status={i:[None,None,None] for i in self.play_channels}
104 self.lives={}
105 self.tried_letters={}
106 self.quiet_channels=config.quiet_channels
107
108
109 def give_me_my_pseudo(self,serv):
110 serv.privmsg("NickServ","RECOVER %s %s"%(config.irc_pseudo,config.irc_password))
111 serv.privmsg("NickServ","RELEASE %s %s"%(config.irc_pseudo,config.irc_password))
112 time.sleep(0.3)
113 serv.nick(config.irc_pseudo)
114
115 def on_welcome(self, serv, ev):
116 self.serv=serv # ça serv ira :)
117 self.give_me_my_pseudo(serv)
118 serv.privmsg("NickServ","IDENTIFY %s"%(config.irc_password))
119 log(self.serveur,"Connected")
120 if self.debug:
121 self.chanlist=["#bot"]
122 self.play_channels=["#bot"]
123 for c in self.chanlist:
124 log(self.serveur,"JOIN %s"%(c))
125 serv.join(c)
126
127 def pourmoi(self, serv, message):
128 """renvoie (False,lemessage) ou (True, le message amputé de "pseudo: ")"""
129 pseudo=serv.get_nickname()
130 size=len(pseudo)
131 if message[:size]==pseudo and len(message)>size and message[size]==":":
132 return (True,message[size+1:].lstrip(" "))
133 else:
134 return (False,message)
135
136 def on_privmsg(self, serv, ev):
137 if ignore_event(serv, ev):
138 return
139 message=ev.arguments()[0]
140 auteur = irclib.nm_to_n(ev.source())
141 try:
142 test=bot_unicode(message)
143 except UnicodeBotError:
144 if config.utf8_trigger:
145 serv.privmsg(auteur, random.choice(config.utf8_fail_answers).encode("utf8"))
146 return
147 message=message.split()
148 cmd=message[0].lower()
149 notunderstood=False
150 if cmd=="help":
151 helpmsg_default="""Liste des commandes :
152 HELP Affiche ce message d'aide
153 SCORE Affiche ton score
154 SCORES Affiche les scores"""
155 helpmsg_ops="""
156 JOIN Faire rejoindre un channel (sans paramètres, donne la liste des chans actuels)
157 LEAVE Faire quitter un channel
158 PLAY Passe un channel en mode "jouer"
159 NOPLAY Passe un channel en mode "ne pas jouer"
160 QUIET Se taire sur un channel
161 NOQUIET Opposé de QUIET
162 RELOAD Recharge la config"""
163 helpmsg_overops="""
164 SAY Fais envoyer un message sur un chan ou à une personne
165 DO Me fait faire une action sur un chan
166 STAY Ignorera les prochains LEAVE pour un chan
167 NOSTAY Opposé de STAY
168 STATUS Montre l'état courant
169 DIE Mourir"""
170 helpmsg=helpmsg_default
171 if auteur in self.ops:
172 helpmsg+=helpmsg_ops
173 if auteur in self.overops:
174 helpmsg+=helpmsg_overops
175 for ligne in helpmsg.split("\n"):
176 serv.privmsg(auteur,ligne)
177 elif cmd=="join":
178 if auteur in self.ops:
179 if len(message)>1:
180 if message[1] in self.chanlist:
181 serv.privmsg(auteur,"Je suis déjà sur %s"%(message[1]))
182 else:
183 serv.join(message[1])
184 self.chanlist.append(message[1])
185 serv.privmsg(auteur,"Channels : "+" ".join(self.chanlist))
186 log(self.serveur,"priv",auteur," ".join(message))
187 else:
188 serv.privmsg(auteur,"Channels : "+" ".join(self.chanlist))
189 else:
190 notunderstood=True
191 elif cmd=="leave":
192 if auteur in self.ops and len(message)>1:
193 if message[1] in self.chanlist:
194 if not (message[1] in self.stay_channels) or auteur in self.overops:
195 self.quitter(message[1]," ".join(message[2:]))
196 self.chanlist.remove(message[1])
197 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
198 else:
199 serv.privmsg(auteur,"Non, je reste !")
200 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
201 else:
202 serv.privmsg(auteur,"Je ne suis pas sur %s"%(message[1]))
203 else:
204 notunderstood=True
205 elif cmd=="play":
206 if auteur in self.ops:
207 if len(message)>1:
208 if message[1] in self.play_channels:
209 if len(message) > 2:
210 self.start_partie(serv, message[1], " ".join(message[2:]))
211 else:
212 serv.privmsg(auteur,"Je play déjà sur %s."%(message[1]))
213 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
214 else:
215 self.play_channels.append(message[1])
216 self.play_status[message[1]]=[None,None,None]
217 serv.privmsg(auteur,"Play channels : "+" ".join(self.play_channels))
218 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
219 else:
220 serv.privmsg(auteur,"Play channels : "+" ".join(self.play_channels))
221 else:
222 notunderstood=True
223 elif cmd=="noplay":
224 if auteur in self.ops:
225 if len(message)>1:
226 if message[1] in self.play_channels:
227 self.play_channels.remove(message[1])
228 serv.privmsg(auteur,"Play channels : "+" ".join(self.play_channels))
229 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
230 else:
231 serv.privmsg(auteur,"Je ne play pas sur %s."%(message[1]))
232 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
233 else:
234 notunderstood=True
235 elif cmd=="stay":
236 if auteur in self.overops:
237 if len(message)>1:
238 if message[1] in self.stay_channels:
239 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
240 serv.privmsg(auteur,"Je stay déjà sur %s."%(message[1]))
241 else:
242 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
243 self.stay_channels.append(message[1])
244 serv.privmsg(auteur,"Stay channels : "+" ".join(self.stay_channels))
245 else:
246 serv.privmsg(auteur,"Stay channels : "+" ".join(self.stay_channels))
247 else:
248 notunderstood=True
249 elif cmd=="nostay":
250 if auteur in self.overops:
251 if len(message)>1:
252 if message[1] in self.stay_channels:
253 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
254 self.stay_channels.remove(message[1])
255 serv.privmsg(auteur,"Stay channels : "+" ".join(self.stay_channels))
256 else:
257 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
258 serv.privmsg(auteur,"Je ne stay pas sur %s."%(message[1]))
259
260 else:
261 notunderstood=True
262 elif cmd in ["states","status"]:
263 if auteur in self.overops:
264 for k in self.play_status.keys():
265 if self.play_status[k]==[None,None,None]:
266 serv.privmsg(auteur,"None")
267 else:
268 serv.privmsg(auteur,"%s : %s (%s) [%s]"%(k,"".join([str(i[0]) for i in self.play_status[k][0]])
269 ,self.play_status[k][1], self.play_status[k][2]))
270 elif cmd=="die":
271 if auteur in self.overops:
272 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
273 self.mourir()
274 else:
275 notunderstood=True
276 elif cmd=="quiet":
277 if auteur in self.ops:
278 if len(message)>1:
279 if message[1] in self.quiet_channels:
280 serv.privmsg(auteur,"Je me la ferme déjà sur %s"%(message[1]))
281 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
282 else:
283 self.quiet_channels.append(message[1])
284 serv.privmsg(auteur,"Quiet channels : "+" ".join(self.quiet_channels))
285 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
286 else:
287 serv.privmsg(auteur,"Quiet channels : "+" ".join(self.quiet_channels))
288 else:
289 notunderstood=True
290 elif cmd=="noquiet":
291 if auteur in self.ops:
292 if len(message)>1:
293 if message[1] in self.quiet_channels:
294 self.quiet_channels.remove(message[1])
295 serv.privmsg(auteur,"Quiet channels : "+" ".join(self.quiet_channels))
296 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
297 else:
298 serv.privmsg(auteur,"Je ne me la ferme pas sur %s."%(message[1]))
299 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
300 else:
301 notunderstood=True
302 elif cmd=="reload":
303 if auteur in self.ops:
304 self.reload(auteur)
305 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
306 else:
307 notunderstood=True
308 elif cmd=="say":
309 if auteur in self.overops and len(message)>2:
310 serv.privmsg(message[1]," ".join(message[2:]))
311 log(self.serveur,"priv",auteur," ".join(message))
312 elif len(message)<=2:
313 serv.privmsg(auteur,"Syntaxe : SAY <channel> <message>")
314 else:
315 notunderstood=True
316 elif cmd=="do":
317 if auteur in self.overops and len(message)>2:
318 serv.action(message[1]," ".join(message[2:]))
319 log(self.serveur,"priv",auteur," ".join(message))
320 elif len(message)<=2:
321 serv.privmsg(auteur,"Syntaxe : DO <channel> <action>")
322 else:
323 notunderstood=True
324 elif cmd in ["score","scores"]:
325 self.send_scores(serv,auteur)
326 else:
327 notunderstood=True
328 if notunderstood:
329 serv.privmsg(auteur,"Je n'ai pas compris. Essaye HELP…")
330
331 def affiche_mot(self, serv, canal, begin="Mot courant"):
332 if self.play_status.has_key(canal):
333 mot = self.play_status[canal][0]
334 obfuskated=" ".join([lettre[0] if lettre[1] else "_" for lettre in mot])
335 serv.privmsg(canal,"%s : %s"%(begin,obfuskated))
336
337 def start_partie(self, serv, canal, mot=None):
338 if mot is None:
339 mots=[mot.strip() for mot in open(config.dico_mots).readlines()]
340 defs=[defi.strip() for defi in open(config.dico_defs).readlines()]
341 indice = random.randrange(0,len(mots))
342 mot,definition=mots[indice],defs[indice]
343 else:
344 definition = "(custom word)"
345 # ' et - sont considérés comme déjà devinés
346 mot = mot.upper()
347 mot = [(lettre,lettre in config.non_guess_chars) for lettre in list(mot)]
348 self.play_status[canal]=[mot,definition,{}]
349 self.tried_letters[canal] = set ()
350 self.lives[canal] = config.lives
351 self.affiche_mot(serv, canal, begin="Devinez")
352
353 def on_pubmsg(self, serv, ev):
354 if ignore_event(serv, ev):
355 return
356 auteur = irclib.nm_to_n(ev.source())
357 canal = ev.target()
358 message = ev.arguments()[0]
359 try:
360 test=bot_unicode(message)
361 except UnicodeBotError:
362 if config.utf8_trigger and not canal in self.quiet_channels:
363 serv.privmsg(canal, (u"%s: %s"%(auteur,random.choice(config.utf8_fail_answers))).encode("utf8"))
364 return
365 pour_moi,message=self.pourmoi(serv,message)
366 if pour_moi and message.split()!=[]:
367 cmd=message.split()[0].lower()
368 try:
369 args=" ".join(message.split()[1:])
370 except:
371 args=""
372 if cmd in ["meurs","die","crève"]:
373 if auteur in self.overops:
374 log(self.serveur,canal,auteur,message+"[successful]")
375 self.mourir()
376 else:
377 serv.privmsg(canal,"%s: crève !"%(auteur))
378 log(self.serveur,canal,auteur,message+"[failed]")
379 elif cmd == "reload":
380 if auteur in self.ops:
381 log(self.serveur, canal, auteur, message+"[successful]")
382 self.reload(canal)
383 elif cmd in ["part","leave","dégage"]:
384 if auteur in self.ops and (not (canal in self.stay_channels)
385 or auteur in self.overops):
386 self.quitter(canal)
387 log(self.serveur,canal,auteur,message+"[successful]")
388 if canal in self.chanlist:
389 self.chanlist.remove(canal)
390 else:
391 serv.privmsg(canal,"%s: Non, je reste !"%(auteur))
392 log(self.serveur,canal,auteur,message+"[failed]")
393 elif cmd in ["play","jeu","encore","again","partie","pendu","game","mot","go","allez"]:
394 if not canal in self.quiet_channels and canal in self.play_channels:
395 if self.play_status.has_key(canal):
396 if self.play_status[canal]==[None,None,None]:
397 self.start_partie(serv, canal)
398 else:
399 self.affiche_mot(serv, canal, begin="%s: Rappel"%(auteur))
400 else:
401 self.play_status[canal]=[None,None,None]
402 self.start_partie(serv, canal)
403 elif not canal in self.play_channels:
404 serv.privmsg(canal,"%s: pas ici…"%(auteur))
405 elif cmd in ["score","scores","!score","!scores"]:
406 self.send_scores(serv,auteur)
407 if cmd in ["meur", "meurt","meurre","meurres"] and not canal in self.quiet_channels:
408 serv.privmsg(canal,'%s: Mourir, impératif, 2ème personne du singulier : "meurs" (de rien)'%(auteur))
409 if is_tag(message) and not canal in self.quiet_channels:
410 if auteur in self.ops:
411 action=random.choice(config.tag_actions)
412 serv.action(canal,action.encode("utf8"))
413 self.quiet_channels.append(canal)
414 else:
415 answer=random.choice(config.tag_answers)
416 for ligne in answer.split("\n"):
417 serv.privmsg(canal,"%s: %s"%(auteur,ligne.encode("utf8")))
418 # on essaye de voir si le mot fourni matche la partie en cours
419 mot = message
420 if canal in self.play_channels and self.play_status[canal][0]!=None and is_mot(mot, self.play_status[canal][0]):
421 # on a trouvé le mot
422 # on regarde combien de lettre il manquait
423 manquait = sum([not lettre[1] for lettre in self.play_status[canal][0]])
424 self.add_score({auteur: manquait})
425 if self.play_status[canal][2].has_key(auteur):
426 self.play_status[canal][2][auteur]+=manquait
427 else:
428 self.play_status[canal][2][auteur]=manquait
429 self.gagne(serv, canal, bonus=auteur, bonusvalue=manquait)
430 return
431 elif (cmd in list("azertyuiopqsdfghjklmwxcvbn") and canal in self.play_channels
432 and self.play_status.has_key(canal) and self.play_status[canal]!=[None,None,None]):
433 giv_let=cmd.upper()
434 liste=self.play_status[canal][0]
435 listeapres=[(lettre[0],lettre[1] or lettre[0]==giv_let) for lettre in liste]
436 if liste!=listeapres:
437 nbtrouvees=(sum([lettre[1] for lettre in listeapres if not lettre[0] in "'-()"])
438 - sum([lettre[1] for lettre in liste if not lettre[0] in "'-()"]))
439 if self.play_status[canal][2].has_key(auteur):
440 self.play_status[canal][2][auteur]+= nbtrouvees
441 else:
442 self.play_status[canal][2][auteur] = nbtrouvees
443 self.play_status[canal][0]=listeapres
444 self.affiche_mot(serv, canal, begin="%s placé"%(giv_let))
445 else:
446 if not giv_let in self.tried_letters[canal]:
447 # On perd une chance
448 self.lives[canal] -= 1
449 if self.lives[canal] > 0:
450 serv.privmsg(canal, "Pas de %s. Plus que %s chance%s…" % (giv_let, self.lives[canal], "s" * (self.lives[canal] > 1)))
451 if self.lives[canal] == 0:
452 serv.privmsg(canal, "Pas de %s." % (giv_let))
453 self.perd(serv, canal)
454 return
455 self.tried_letters[canal].add(giv_let)
456 if all([lettre[1] for lettre in listeapres]):
457 self.gagne(serv, canal)
458
459 else:
460 pass
461
462
463 def on_action(self, serv, ev):
464 if ignore_event(serv, ev):
465 return
466 action = ev.arguments()[0]
467 auteur = irclib.nm_to_n(ev.source())
468 channel = ev.target()
469
470
471 def on_kick(self,serv,ev):
472 auteur = irclib.nm_to_n(ev.source())
473 channel = ev.target()
474 victime = ev.arguments()[0]
475 raison = ev.arguments()[1]
476 if victime==self.nick:
477 log(self.serveur,"%s kické de %s par %s (raison : %s)" %(victime,channel,auteur,raison))
478 time.sleep(5)
479 serv.join(channel)
480 # on ne dit rien au rejoin
481 #l1,l2=config.kick_answers,config.kick_actions
482 #n1,n2=len(l1),len(l2)
483 #i=random.randrange(n1+n2)
484 #if i>=n1:
485 # serv.action(channel,l2[i-n1].format(auteur).encode("utf8"))
486 #else:
487 # serv.privmsg(channel,l1[i].format(auteur).encode("utf8"))
488
489 def _getnick(self):
490 return self.serv.get_nickname()
491 nick = property(_getnick)
492
493 def quitter(self,chan,leave_message=None):
494 if leave_message==None:
495 leave_message=random.choice(config.leave_messages)
496 self.serv.part(chan,message=leave_message.encode("utf8"))
497
498 def mourir(self):
499 quit_message=random.choice(config.quit_messages)
500 self.die(msg=quit_message.encode("utf8"))
501
502 def get_scores(self):
503 f=open(config.scores_file)
504 scores=pickle.load(f)
505 f.close()
506 return scores
507 def save_scores(self,scores):
508 f=open(config.scores_file,'w')
509 pickle.dump(scores,f)
510 f.close()
511 def add_score(self,dico):
512 scores=self.get_scores()
513 for k,v in dico.items():
514 if scores.has_key(k):
515 scores[k]+=v
516 else:
517 scores[k]=v
518 self.save_scores(scores)
519 def send_scores(self, serv, destinataire):
520 scores=self.get_scores()
521 scores=scores.items()
522 scores.sort(lambda x,y:cmp(x[1],y[1]))
523 scores.reverse()
524 serv.privmsg(destinataire,"Scores by score : "+" ; ".join(["%s %s"%(k,v) for (k,v) in scores]) )
525 scores.sort(lambda x,y:cmp(x[0].lower(),y[0].lower()))
526 serv.privmsg(destinataire,"Scores by pseudo : "+" ; ".join(["%s %s"%(k,v) for (k,v) in scores]) )
527
528 def gagne(self, serv, canal, bonus=None, bonusvalue=2):
529 serv.privmsg(canal,"Bravo !")
530 realword = self.reveal_word(serv, canal)
531 nlettre=float(len([l for l in realword if not l in config.non_guess_chars]))
532 contribs=["%s:%s%%%s"%(pseudo,str(int(100*contrib/nlettre)),("+bonus(%s)"%(bonusvalue))*(bonus==pseudo)) for pseudo,contrib in self.play_status[canal][2].items()]
533 contribs_score={pseudo:int(10*contrib/nlettre) for pseudo,contrib in self.play_status[canal][2].items()}
534 self.add_score(contribs_score)
535 serv.privmsg(canal,"Contributions : %s"%(" ".join(contribs)) )
536 self.play_status[canal]=[None,None,None]
537
538 def reveal_word(self, serv, canal):
539 realword="".join([lettre[0] for lettre in self.play_status[canal][0]])
540 serv.privmsg(canal, "C'était %s." % (realword))
541 definition = self.play_status[canal][1]
542 serv.privmsg(canal,definition)
543 return realword
544
545 def perd(self, serv, canal):
546 serv.privmsg(canal,"Pendu !")
547 self.reveal_word(serv, canal)
548 self.play_status[canal]=[None,None,None]
549
550 def reload(self, auteur=None):
551 reload(config)
552 if auteur in [None, "SIGHUP"]:
553 towrite = "Config reloaded" + " (SIGHUP received)"*(auteur == "SIGHUP")
554 for to in config.report_bugs_to:
555 self.serv.privmsg(to, towrite)
556 log(self.serveur, towrite)
557 else:
558 self.serv.privmsg(auteur,"Config reloaded")
559
560 def start_as_daemon(self, outfile):
561 sys.stderr = Logger(outfile)
562 self.start()
563
564
565 class Logger(object):
566 """Pour écrire ailleurs que sur stdout"""
567 def __init__(self, filename="hung.full.log"):
568 self.filename = filename
569
570 def write(self, message):
571 f = open(self.filename, "a")
572 f.write(message)
573 f.close()
574
575
576 if __name__=="__main__":
577 import sys
578 if len(sys.argv)==1:
579 print "Usage : hung.py <serveur> [--debug] [--no-output] [--daemon [--pidfile]] [--outfile]"
580 print " --outfile sans --no-output ni --daemon n'a aucun effet"
581 exit(1)
582 serveur=sys.argv[1]
583 if "--daemon" in sys.argv:
584 thisfile = os.path.realpath(__file__)
585 thisdirectory = thisfile.rsplit("/", 1)[0]
586 os.chdir(thisdirectory)
587 daemon = True
588 else:
589 daemon = False
590 if "debug" in sys.argv or "--debug" in sys.argv:
591 debug=True
592 else:
593 debug=False
594 if "--no-output" in sys.argv or "--daemon" in sys.argv:
595 outfile = "/var/log/bots/hung.full.log"
596 for arg in sys.argv:
597 arg = arg.split("=")
598 if arg[0].strip('-') in ["out", "outfile", "logfile"]:
599 outfile = arg[1]
600 sys.stdout = Logger(outfile)
601 serveurs={"a♡":"acoeur.crans.org","acoeur":"acoeur.crans.org","acoeur.crans.org":"acoeur.crans.org",
602 "irc":"irc.crans.org","crans":"irc.crans.org","irc.crans.org":"irc.crans.org",
603 "localhost":"localhost"}
604 try:
605 serveur=serveurs[serveur]
606 except KeyError:
607 print "Server Unknown : %s"%(serveur)
608 exit(404)
609 hung=Hung(serveur,debug)
610 # Si on reçoit un SIGHUP, on reload la config
611 def sighup_handler(signum, frame):
612 hung.reload("SIGHUP")
613 signal.signal(signal.SIGHUP, sighup_handler)
614 if daemon:
615 child_pid = os.fork()
616 if child_pid == 0:
617 os.setsid()
618 hung.start_as_daemon(outfile)
619 else:
620 # on enregistre le pid de hung
621 pidfile = "/var/run/bots/hung.pid"
622 for arg in sys.argv:
623 arg = arg.split("=")
624 if arg[0].strip('-') in ["pidfile"]:
625 pidfile = arg[1]
626 f = open(pidfile, "w")
627 f.write("%s\n" % child_pid)
628 f.close()
629 else:
630 hung.start()
631