]> gitweb.pimeys.fr Git - bots/historien.git/blob - historien.py
0d4842dd9377850138affaa3a4f2e0a9d84593dc
[bots/historien.git] / historien.py
1 #!/usr/bin/python
2 # -*- coding:utf8 -*-
3
4 # Codé par 20-100 le 25/05/12
5
6 # Un bot IRC qui pose des questions d'histoire
7
8 import threading
9 import random
10 import time
11 import pickle
12 import re
13 import signal
14 import sys
15 import os
16 from cast_as_date import *
17
18 # Oui, j'ai recodé ma version d'irclib pour pouvoir rattrapper les SIGHUP
19 sys.path.insert(0, "/home/vincent/scripts/python-myirclib")
20 import irclib
21 import ircbot
22
23 # Fichier de conf
24 import config
25
26 def get_config_played_file(serveur):
27 serveurs={"acoeur.crans.org":"acoeur","irc.crans.org":"crans"}
28 return config.played_file_template%(serveurs[serveur])
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 class UnicodeBotError(Exception):
35 pass
36 def bot_unicode(chain):
37 try:
38 unicode(chain,"utf8")
39 except UnicodeDecodeError:
40 raise UnicodeBotError
41
42 def log(serveur,channel,auteur=None,message=None):
43 f=open(get_config_logfile(serveur),"a")
44 if auteur==message==None:
45 # alors c'est que c'est pas un channel mais juste une ligne de log
46 chain="%s %s"%(time.strftime("%F %T"),channel)
47 else:
48 chain="%s [%s:%s] %s"%(time.strftime("%F %T"),channel,auteur,message)
49 f.write(chain+"\n")
50 if config.debug_stdout:
51 print chain
52 f.close()
53
54
55 class GoodCentury(Exception):
56 pass
57
58 class GoodDeceny(Exception):
59 pass
60
61 def reussi(message,answer,auteur):
62 if auteur in config.level3:
63 return answer in message
64 if auteur in config.level2:
65 return answer in message
66 else:
67 try:
68 date=cast_as_date(message.lower().strip())
69 except ThisIsNotADate:
70 return False
71 realdate=map(lambda x:int(x), answer.split('/'))
72 realdate.reverse()
73 score=0
74 if date[0]==realdate[0]:
75 score=config.score_annee
76 if date[1]==realdate[1]:
77 score+=config.score_mois
78 if date[2]==realdate[2]:
79 score+=config.score_jour
80 elif date[0]/10 == realdate[0]/10:
81 raise GoodDeceny
82 elif date[0]/100 == realdate[0]/100:
83 raise GoodCentury
84 return score
85
86 def is_something(chain,matches,avant=u".*(?:^| )",apres=u"(?:$|\.| |,|;).*",case_sensitive=False,debug=False):
87 if case_sensitive:
88 chain=unicode(chain,"utf8")
89 else:
90 chain=unicode(chain,"utf8").lower()
91 allmatches="("+"|".join(matches)+")"
92 reg=(avant+allmatches+apres).lower()
93 o=re.match(reg,chain)
94 return o
95
96 def is_tag(chain):
97 return is_something(chain,config.tag_triggers)
98
99 class RefuseError(Exception):
100 pass
101
102 class Historien(ircbot.SingleServerIRCBot):
103 def __init__(self,serveur,debug=False):
104 temporary_pseudo=config.pseudo+str(random.randrange(10000,100000))
105 ircbot.SingleServerIRCBot.__init__(self, [(serveur, 6667)],
106 temporary_pseudo,"Un bot irc qui a au moins l'agreg d'histoire", 10)
107 self.debug=debug
108 self.serveur=serveur
109 self.overops=config.overops
110 self.ops=self.overops+config.ops
111 self.chanlist=config.chanlist
112 self.stay_channels=config.stay_channels
113 self.play_channels=config.play_channels
114 self.play_status={i:[0] for i in self.play_channels}
115 self.last_activity={}
116 self.quiet_channels=[]
117
118 def give_me_my_pseudo(self,serv):
119 serv.privmsg("NickServ","RECOVER %s %s"%(config.pseudo,config.password))
120 serv.privmsg("NickServ","RELEASE %s %s"%(config.pseudo,config.password))
121 time.sleep(0.3)
122 serv.nick(config.pseudo)
123
124 def on_welcome(self, serv, ev):
125 self.serv=serv # ça serv ira :)
126 self.give_me_my_pseudo(serv)
127 serv.privmsg("NickServ","identify %s"%(config.password))
128 log(self.serveur,"Connected")
129 if self.debug:
130 self.chanlist=["#bot"]
131 self.play_channels=["#bot"]
132 for c in self.chanlist:
133 log(self.serveur,"JOIN %s"%(c))
134 serv.join(c)
135 self.update_activity(c,"") # la chaîne vide ne sera jamais un nom de bot et donc marchera toujours
136 for c in self.play_channels:
137 token=time.time()-3600
138 self.play_status[c]=[0,token]
139 serv.execute_delayed(random.randrange(config.ttrig),self.start_enigme,(serv,c,token))
140
141 def start_enigme(self,serv,channel,token=None):
142 # On reste silencieux si lechan n'est pas actif
143 if not self.is_active(channel):
144 serv.execute_delayed(config.ttrig*5,self.start_enigme,(serv,channel,token))
145 return
146 if self.play_status[channel][0]==0 and channel in self.play_channels:
147 ok="skip"
148 if token==self.play_status[channel][-1]:
149 ok="do_it"
150 if token==None:
151 if time.time() > self.play_status[channel][-1]+config.time_incompressible:
152 ok="do_it"
153 else:
154 ok="refuse"
155 if ok=="do_it":
156 date,evenement=self.get_enigme()
157 log(self.serveur,channel,u"$Date$".encode("utf8"),("%s : %s"%(date, evenement)).encode("utf8"))
158 serv.privmsg(channel,evenement.encode("utf8"))
159 token=time.time()
160 # le 0 est le flag "bon siècle" n'a pas encore été dit
161 self.play_status[channel]=[1,date,evenement,0,token]
162 serv.execute_delayed(random.randrange(config.ttrig*3,config.ttrig*5),self.give_indice,(serv,channel,token))
163 elif ok=="refuse":
164 raise RefuseError
165 def give_indice(self,serv,channel,token):
166 if self.play_status[channel][0]==1:
167 if token==None:
168 # c'est donc que l'indice a été demandé
169 if self.play_status[channel][-1]+config.time_incompressible_clue<time.time():
170 token=self.play_status[channel][-1]
171 if self.play_status[channel][-1]==token:
172 date=self.play_status[channel][1]
173 indice=date[:5]
174 serv.privmsg(channel,"indice : %s"%(indice).encode("utf8"))
175 self.play_status[channel][0]=2
176 serv.execute_delayed(random.randrange(config.ttrig*1,config.ttrig*3),self.give_answer,(serv,channel,token))
177 def give_answer(self,serv,channel,token):
178 if self.play_status[channel][0]==2 and self.play_status[channel][-1]==token:
179 date=self.play_status[channel][1]
180 serv.privmsg(channel,"C'était le %s"%(date).encode("utf8"))
181 token=time.time()
182 self.play_status[channel]=[0,token]
183 serv.execute_delayed(random.randrange(config.Ttrig*5,config.Ttrig*10),self.start_enigme,(serv,channel,token))
184
185 def get_enigme(self):
186 # on récupère les dates
187 f=open(config.source_file)
188 l=f.readlines()
189 f.close()
190 l=[i.split(" : ",2) for i in l]
191 dates={int(i[0]):i[1:] for i in l}
192 # on va chercher combien de fois elles ont été jouées
193 played_file=get_config_played_file(self.serveur)
194 f=open(played_file)
195 t=f.read()
196 f.close()
197 l=re.findall("(.*):(.*)",t)
198 played={int(i[0]):int(i[1]) for i in l}
199 # on récupère le nombre d'occurrences le plus faible
200 mini=min(played.values())
201 # on choisit un id dans ceux qui ont ce nombre d'occurences
202 id_choisi=random.choice([k for k,v in played.items() if v==mini])
203 date,evenement=dates[id_choisi]
204 evenement=evenement.replace("\n","")
205 # on incrémente la choisie
206 played[id_choisi]+=1
207 # on enregistre le played_file
208 f=open(played_file,"w")
209 f.write("\n".join(["%-4s : %s"%(k,v) for k,v in played.items()]))
210 f.close()
211 return map(lambda x:x.decode("utf8"), [date,evenement])
212
213 def pourmoi(self, serv, message):
214 pseudo=self.nick
215 size=len(pseudo)
216 if message[:size]==pseudo and len(message)>size and message[size]==":":
217 return (True,message[size+1:].strip(" "))
218 else:
219 return (False,message)
220
221 def on_privmsg(self, serv, ev):
222 message=ev.arguments()[0]
223 auteur = irclib.nm_to_n(ev.source())
224 try:
225 test=bot_unicode(message)
226 except UnicodeBotError:
227 if config.utf8_trigger:
228 serv.privmsg(auteur, random.choice(config.utf8_fail_answers).encode("utf8"))
229 return
230 message=message.split()
231 cmd=message[0].lower()
232 notunderstood=False
233 if cmd=="help":
234 helpmsg_default="""Liste des commandes :
235 HELP Affiche ce message d'aide
236 SCORE Affiche ton score (SCORE TRANSFERT <pseudo> [<n>] pour transférer des points)
237 SCORES Affiche les scores"""
238 helpmsg_ops="""
239 JOIN Faire rejoindre un channel (sans paramètres, donne la liste des chans actuels)
240 LEAVE Faire quitter un channel
241 PLAY Passe un channel en mode "jouer"
242 NOPLAY Passe un channel en mode "ne pas jouer"
243 QUIET Se taire sur un channel
244 NOQUIET Opposé de QUIET"""
245 helpmsg_overops="""
246 SCORES {DEL|ADD|SUB} Tu veux un dessin ?
247 SAY Fais envoyer un message sur un chan ou à une personne
248 STAY Ignorera les prochains LEAVE pour un chan
249 NOSTAY Opposé de STAY
250 STATUS Montre l'état courant
251 DIE Mourir"""
252 helpmsg=helpmsg_default
253 if auteur in self.ops:
254 helpmsg+=helpmsg_ops
255 if auteur in self.overops:
256 helpmsg+=helpmsg_overops
257 for ligne in helpmsg.split("\n"):
258 serv.privmsg(auteur,ligne)
259 elif cmd=="join":
260 if auteur in self.ops:
261 if len(message)>1:
262 if message[1] in self.chanlist:
263 serv.privmsg(auteur,"Je suis déjà sur %s"%(message[1]))
264 else:
265 serv.join(message[1])
266 self.chanlist.append(message[1])
267 serv.privmsg(auteur,"Channels : "+" ".join(self.chanlist))
268 log(self.serveur,"priv",auteur," ".join(message))
269 else:
270 serv.privmsg(auteur,"Channels : "+" ".join(self.chanlist))
271 else:
272 notunderstood=True
273 elif cmd=="leave":
274 if auteur in self.ops and len(message)>1:
275 if message[1] in self.chanlist:
276 if not (message[1] in self.stay_channels) or auteur in self.overops:
277 self.quitter(message[1]," ".join(message[2:]))
278 self.chanlist.remove(message[1])
279 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
280 else:
281 serv.privmsg(auteur,"Non, je reste !")
282 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
283 else:
284 serv.privmsg(auteur,"Je ne suis pas sur %s"%(message[1]))
285 else:
286 notunderstood=True
287 elif cmd=="stay":
288 if auteur in self.overops:
289 if len(message)>1:
290 if message[1] in self.stay_channels:
291 serv.privmsg(auteur,"Je stay déjà sur %s."%(message[1]))
292 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
293 else:
294 self.stay_channels.append(message[1])
295 serv.privmsg(auteur,"Stay channels : "+" ".join(self.stay_channels))
296 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
297 else:
298 serv.privmsg(auteur,"Stay channels : "+" ".join(self.stay_channels))
299 else:
300 notunderstood=True
301 elif cmd=="nostay":
302 if auteur in self.overops:
303 if len(message)>1:
304 if message[1] in self.stay_channels:
305 self.stay_channels.remove(message[1])
306 serv.privmsg(auteur,"Stay channels : "+" ".join(self.stay_channels))
307 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
308 else:
309 serv.privmsg(auteur,"Je ne stay pas sur %s."%(message[1]))
310 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
311 else:
312 notunderstood=True
313 elif cmd=="play":
314 if auteur in self.ops:
315 if len(message)>1:
316 if message[1] in self.play_channels:
317 serv.privmsg(auteur,"Je play déjà sur %s."%(message[1]))
318 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
319 else:
320 self.play_channels.append(message[1])
321 self.play_status[message[1]]=[0,time.time()-3600]
322 serv.privmsg(auteur,"Play channels : "+" ".join(self.play_channels))
323 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
324 else:
325 serv.privmsg(auteur,"Play channels : "+" ".join(self.play_channels))
326 else:
327 notunderstood=True
328 elif cmd=="noplay":
329 if auteur in self.ops:
330 if len(message)>1:
331 if message[1] in self.play_channels:
332 self.play_channels.remove(message[1])
333 serv.privmsg(auteur,"Play channels : "+" ".join(self.play_channels))
334 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
335 else:
336 serv.privmsg(auteur,"Je ne play pas sur %s."%(message[1]))
337 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
338 else:
339 notunderstood=True
340 elif cmd=="quiet":
341 if auteur in self.ops:
342 if len(message)>1:
343 if message[1] in self.quiet_channels:
344 serv.privmsg(auteur,"Je me la ferme déjà sur %s"%(message[1]))
345 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
346 else:
347 self.quiet_channels.append(message[1])
348 serv.privmsg(auteur,"Quiet channels : "+" ".join(self.quiet_channels))
349 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
350 else:
351 serv.privmsg(auteur,"Quiet channels : "+" ".join(self.quiet_channels))
352 else:
353 notunderstood=True
354 elif cmd=="noquiet":
355 if auteur in self.ops:
356 if len(message)>1:
357 if message[1] in self.quiet_channels:
358 self.quiet_channels.remove(message[1])
359 serv.privmsg(auteur,"Quiet channels : "+" ".join(self.quiet_channels))
360 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
361 else:
362 serv.privmsg(auteur,"Je ne me la ferme pas sur %s."%(message[1]))
363 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
364 else:
365 notunderstood=True
366 elif cmd in ["states","status"]:
367 if auteur in self.overops:
368 for k in self.play_status.keys():
369 serv.privmsg(auteur,(u"%s : %s"%(k," | ".join([unicode(i) for i in self.play_status[k]]))).encode("utf8") )
370 elif cmd=="say":
371 if auteur in self.overops and len(message)>2:
372 serv.privmsg(message[1]," ".join(message[2:]))
373 log(self.serveur,"priv",auteur," ".join(message))
374 elif len(message)<=2:
375 serv.privmsg(auteur,"Syntaxe : SAY <channel> <message>")
376 else:
377 notunderstood=True
378 elif cmd=="die":
379 if auteur in self.overops:
380 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
381 self.mourir()
382 elif cmd=="score":
383 if len(message)>1:
384 if len(message) in [3,4] and message[1].lower()=="transfert":
385 scores=self.get_scores()
386 de,to=auteur,message[2]
387 value=scores.get(de,0)
388 if len(message)==4:
389 try:
390 asked=int(message[3])
391 except ValueError:
392 serv.privmsg(auteur,"Syntaxe : SCORE TRANSFERT <pseudo> [<n>]")
393 return
394 else:
395 asked=value
396 if value==0:
397 serv.privmsg(auteur,"Vous n'avez pas de points")
398 return
399 elif asked<=0:
400 serv.privmsg(auteur,"Bien tenté…")
401 return
402 elif asked>value:
403 serv.privmsg(auteur,"Vous n'avez que %s points"%(value))
404 return
405 else:
406 self.add_score(de,-asked)
407 self.add_score(to,asked)
408 serv.privmsg(auteur,"Transfert de %s points de %s à %s"%(asked,de,to))
409 else:
410 serv.privmsg(auteur,"Syntaxe : SCORE TRANSFERT <pseudo> [<n>]")
411 else:
412 serv.privmsg(auteur,"Votre score : %s"%(self.get_scores().get(auteur,0)) )
413 elif cmd=="scores":
414 if len(message)==1:
415 scores=self.get_scores().items()
416 # trie par score
417 scores.sort(lambda x,y:cmp(x[1],y[1]))
418 scores.reverse()
419 serv.privmsg(auteur,"Scores by score : "+" ; ".join(["%s %s"%(i[0],i[1]) for i in scores]))
420 # trie par pseudo
421 scores.sort(lambda x,y:cmp(x[0].lower(),y[0].lower()))
422 serv.privmsg(auteur,"Scores by pseudo : "+" ; ".join(["%s %s"%(i[0],i[1]) for i in scores]))
423 elif auteur in self.overops:
424 souscmd=message[1].lower()
425 if souscmd=="del":
426 if len(message)==3:
427 todelete=message[2]
428 scores=self.get_scores()
429 if scores.has_key(todelete):
430 del scores[todelete]
431 self.save_scores(scores)
432 serv.privmsg(auteur,"Score de %s supprimé"%(todelete))
433 else:
434 serv.privmsg(auteur,"Ce score n'existe pas : %s"%(todelete))
435 else:
436 serv.privmsg(auteur,"Syntaxe : SCORES DEL <pseudo>")
437 elif souscmd in ["add","sub"]:
438 if len(message)==4:
439 toadd,val=message[2],message[3]
440 try:
441 val=int(val)
442 except ValueError:
443 serv.privmsg(auteur,"Syntaxe : SCORES {ADD|SUB} <pseudo> <n>")
444 return
445 if souscmd=="sub":
446 val=-val
447 self.add_score(toadd,val)
448 serv.privmsg(auteur,"Done")
449 else:
450 serv.privmsg(auteur,"Syntaxe : SCORES {ADD|SUB} <pseudo> <n>")
451 else:
452 serv.privmsg(auteur,"Syntaxe : SCORES {DEL|ADD|SUB} <pseudo> [<n>]")
453 else:
454 notunderstood=True
455 else:
456 notunderstood=True
457 if notunderstood:
458 serv.privmsg(auteur,"Je n'ai pas compris. Essaye HELP…")
459
460 def on_pubmsg(self, serv, ev):
461 auteur = irclib.nm_to_n(ev.source())
462 canal = ev.target()
463 message = ev.arguments()[0]
464 self.update_activity(canal,auteur)
465 try:
466 test=bot_unicode(message)
467 except UnicodeBotError:
468 if config.utf8_trigger and not canal in self.quiet_channels:
469 serv.privmsg(canal, (u"%s: %s"%(auteur, random.choice(config.utf8_fail_answers))).encode("utf8"))
470 return
471 tryother=False
472 pour_moi,message=self.pourmoi(serv,message)
473 if pour_moi and message.split()!=[]:
474 cmd=message.split()[0].lower()
475 try:
476 args=" ".join(message.split()[1:])
477 except:
478 args=""
479 if cmd in ["meurs","die","crève"]:
480 if auteur in self.overops:
481 self.mourir()
482 log(self.serveur,canal,auteur,message+"[successful]")
483 else:
484 serv.privmsg(canal,"%s: crève !"%(auteur))
485 log(self.serveur,canal,auteur,message+"[failed]")
486 if cmd in ["meur", "meurt","meurre","meurres"] and not canal in self.quiet_channels:
487 serv.privmsg(canal,'%s: Mourir, impératif, 2ème personne du singulier : "meurs" (de rien)'%(auteur))
488 if cmd in ["part","leave","dégage"]:
489 if auteur in self.ops and (not (canal in self.stay_channels)
490 or auteur in self.overops):
491 self.quitter(canal)
492 log(self.serveur,canal,auteur,message+"[successful]")
493 self.chanlist.remove(canal)
494 else:
495 serv.privmsg(canal,"%s: Non, je reste !"%(auteur))
496 log(self.serveur,canal,auteur,message+"[failed]")
497
498 if cmd in ["deviens","pseudo"]:
499 if auteur in self.ops:
500 become=args
501 serv.nick(become)
502 log(self.serveur,canal,auteur,message+"[successful]")
503 if cmd in ["coucou"] and not canal in self.quiet_channels:
504 serv.privmsg(canal,"%s: coucou"%(auteur))
505 if cmd in ["ping"] and not canal in self.quiet_channels:
506 serv.privmsg(canal,"%s: pong"%(auteur))
507 if cmd in ["date","dates","histoire","énigme","enigme","encore"]:
508 if canal in self.play_channels:
509 if self.play_status.get(canal,[-1])[0]==0:
510 try:
511 self.start_enigme(serv,canal)
512 except RefuseError:
513 serv.privmsg(canal,"%s: Je peux souffler une minute ?"%(auteur))
514 else:
515 serv.privmsg(canal,("%s: Rappel : %s"%(auteur,self.play_status[canal][2])).encode("utf8") )
516 else:
517 serv.privmsg(canal,"%s: pas ici…"%(auteur))
518 if cmd in ["score","!score"]:
519 serv.privmsg(auteur,"Votre score : %s"%(self.get_scores().get(auteur,0)) )
520 if cmd in ["scores","!scores"]:
521 scores=self.get_scores().items()
522 # trie par score
523 scores.sort(lambda x,y:cmp(x[1],y[1]))
524 scores.reverse()
525 serv.privmsg(auteur,"Scores by score : "+" ; ".join(["%s %s"%(i[0],i[1]) for i in scores]))
526 # trie par pseudo
527 scores.sort(lambda x,y:cmp(x[0].lower(),y[0].lower()))
528 serv.privmsg(auteur,"Scores by pseudo : "+" ; ".join(["%s %s"%(i[0],i[1]) for i in scores]))
529 if cmd=="indice" and canal in self.play_channels:
530 self.give_indice(serv,canal,None)
531 if is_tag(message) and not canal in self.quiet_channels:
532 if auteur in self.ops:
533 action=random.choice(config.tag_actions)
534 serv.action(canal,action.encode("utf8"))
535 self.quiet_channels.append(canal)
536 else:
537 answer=random.choice(config.tag_answers)
538 for ligne in answer.split("\n"):
539 serv.privmsg(canal,"%s: %s"%(auteur,ligne.encode("utf8")))
540 else:
541 tryother=True
542 else:
543 tryother=True
544 if tryother:
545 if self.play_status.get(canal,[-1])[0] in [1,2]:
546 answer=self.play_status[canal][1]
547 flag_century=self.play_status[canal][3]
548 try:
549 score_obtenu=reussi(message.decode("utf8"),answer,auteur)
550 except GoodCentury:
551 if not flag_century:
552 serv.privmsg(canal,"%s: C'est le bon siècle, mais pas la bonne année, cherche encore ;)"%(auteur))
553 self.play_status[canal][3]=1
554 return
555 except GoodDeceny:
556 if flag_century in [0,1]:
557 serv.privmsg(canal,"%s: C'est la bonne décennie, mais pas la bonne année, encore un effort ;)"%(auteur))
558 self.play_status[canal][3]=2
559 return
560 if score_obtenu:
561 if self.play_status[canal][0]==1:
562 bonusmsg=u" [+bonus_mois"*(score_obtenu>config.score_annee)+u"+bonus_jour"*(score_obtenu>config.score_annee+config.score_mois)
563 else:
564 bonusmsg=""
565 score_obtenu=1
566 if bonusmsg:
567 bonusmsg+=u"]"
568 serv.privmsg(canal,(u"%s: bravo ! (C'était le %s)%s"%(auteur,answer,bonusmsg)).encode("utf8"))
569 log(self.serveur,canal,auteur+"$win",message)
570 if auteur in config.noscore:
571 score_obtenu=0
572 self.add_score(auteur,score_obtenu)
573 token=time.time()
574 self.play_status[canal]=[0,token]
575 serv.execute_delayed(random.randrange(config.Ttrig*5,config.Ttrig*10),self.start_enigme,(serv,canal,token))
576
577 def on_kick(self,serv,ev):
578 auteur = irclib.nm_to_n(ev.source())
579 channel = ev.target()
580 victime = ev.arguments()[0]
581 raison = ev.arguments()[1]
582 if victime==self.nick:
583 log(self.serveur,"%s kické de %s par %s (raison : %s)" %(victime,channel,auteur,raison))
584 time.sleep(5)
585 serv.join(channel)
586 self.update_activity(channel,"")
587 # on ne dit rien au rejoin
588 #l1,l2=config.kick_answers,config.kick_actions
589 #n1,n2=len(l1),len(l2)
590 #i=random.randrange(n1+n2)
591 #if i>=n1:
592 # serv.action(channel,l2[i-n1].format(auteur).encode("utf8"))
593 #else:
594 # serv.privmsg(channel,l1[i].format(auteur).encode("utf8"))
595
596 def quitter(self,chan,leave_message=None):
597 if leave_message==None:
598 leave_message=random.choice(config.leave_messages)
599 try:
600 leave_message=leave_message%(time.strftime("le %d/%m/%Y à %T").decode("utf8"),self.nick)
601 except:
602 pass
603 self.serv.part(chan,message=leave_message.encode("utf8"))
604
605 def mourir(self):
606 quit_message=random.choice(config.quit_messages)
607 try:
608 quit_message=quit_message%(time.strftime("le %d/%m/%Y à %T").decode("utf8"),self.nick)
609 except:
610 pass
611 self.die(msg=quit_message.encode("utf8"))
612
613 def get_scores(self):
614 f=open(config.score_file)
615 scores=pickle.load(f)
616 f.close()
617 return scores
618
619 def add_score(self,pseudo,value):
620 scores=self.get_scores()
621 if scores.has_key(pseudo):
622 scores[pseudo]+=value
623 else:
624 scores[pseudo]=value
625 self.save_scores(scores)
626
627 def save_scores(self,scores):
628 f=open(config.score_file,"w")
629 pickle.dump(scores,f)
630 f.close()
631
632 def _getnick(self):
633 return self.serv.get_nickname()
634 nick = property(_getnick)
635
636 def update_activity(self,canal,pseudo):
637 if not pseudo in config.idle_bots:
638 self.last_activity[canal]=time.time()
639 def is_active(self,canal):
640 return time.time()-self.last_activity[canal]<config.idle_time
641
642 def start_as_daemon(self, outfile):
643 sys.stderr = Logger(outfile)
644 self.start()
645
646
647 class Logger(object):
648 """Pour écrire ailleurs que sur stdout"""
649 def __init__(self, filename="historien.full.log"):
650 self.filename = filename
651
652 def write(self, message):
653 f = open(self.filename, "a")
654 f.write(message)
655 f.close()
656
657
658 if __name__=="__main__":
659 import sys
660 if len(sys.argv)==1:
661 print "Usage : historien.py <serveur> [--debug] [--no-output] [--daemon [--pidfile]] [--outfile]"
662 print " --outfile sans --no-output ni --daemon n'a aucun effet"
663 exit(1)
664 serveur=sys.argv[1]
665 if "--daemon" in sys.argv:
666 thisfile = os.path.realpath(__file__)
667 thisdirectory = thisfile.rsplit("/", 1)[0]
668 os.chdir(thisdirectory)
669 daemon = True
670 else:
671 daemon = False
672 if "debug" in sys.argv or "--debug" in sys.argv:
673 debug=True
674 else:
675 debug=False
676 if "--no-output" in sys.argv or "--daemon" in sys.argv:
677 outfile = "/var/log/bots/historien.full.log"
678 for arg in sys.argv:
679 arg = arg.split("=")
680 if arg[0].strip('-') in ["out", "outfile", "logfile"]:
681 outfile = arg[1]
682 sys.stdout = Logger(outfile)
683 serveurs={"a♡":"acoeur.crans.org","acoeur":"acoeur.crans.org","acoeur.crans.org":"acoeur.crans.org",
684 "irc":"irc.crans.org","crans":"irc.crans.org","irc.crans.org":"irc.crans.org"}
685 try:
686 serveur=serveurs[serveur]
687 except KeyError:
688 print "Server Unknown : %s"%(serveur)
689 exit(404)
690 historien=Historien(serveur,debug)
691 if daemon:
692 child_pid = os.fork()
693 if child_pid == 0:
694 os.setsid()
695 historien.start_as_daemon(outfile)
696 else:
697 # on enregistre le pid de historien
698 pidfile = "/var/run/bots/historien.pid"
699 for arg in sys.argv:
700 arg = arg.split("=")
701 if arg[0].strip('-') in ["pidfile"]:
702 pidfile = arg[1]
703 f = open(pidfile, "w")
704 f.write("%s\n" % child_pid)
705 f.close()
706 else:
707 historien.start()
708