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