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