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