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