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