]> gitweb.pimeys.fr Git - bots/themis.git/blob - themis.py
Fonction de blacklist
[bots/themis.git] / themis.py
1 #!/usr/bin/python
2 # -*- coding:utf8 -*-
3 # Codé par 20-100 (commencé le 21/06/12)
4
5 # Un bot IRC pour kicker à tour de bras de #déprime
6
7 import threading
8 import random
9 import time
10 import socket, ssl, json
11 import pickle
12 import re
13 import os
14 import signal
15 import sys
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 import sys
23
24 # Fichier de conf
25 import config
26
27 def get_config_logfile(serveur):
28 serveurs={"acoeur.crans.org":"acoeur","irc.crans.org":"crans"}
29 return config.logfile_template%(serveurs[serveur])
30
31
32 def log(serveur,channel,auteur=None,message=None):
33 f=open(get_config_logfile(serveur),"a")
34 if auteur==message==None:
35 # alors c'est que c'est pas un channel mais juste une ligne de log
36 chain="%s %s"%(time.strftime("%F %T"),channel)
37 else:
38 chain="%s [%s:%s] %s"%(time.strftime("%F %T"),channel,auteur,message)
39 f.write(chain+"\n")
40 if config.debug_stdout:
41 print chain
42 f.close()
43
44 def ignore_event(serv, ev):
45 """Retourne ``True`` si il faut ignorer cet évènement."""
46 for (blackmask, exceptmask) in config.blacklisted_masks:
47 usermask = ev.source()
48 if exceptmask is None:
49 exceptit = False
50 else:
51 exceptit = bool(irclib.mask_matches(usermask, exceptmask))
52 blackit = bool(irclib.mask_matches(usermask, blackmask))
53 return blackit and not exceptit
54
55 reg_is_smiley = re.compile(u".*("+u"|".join(config.smileys)+u")")
56 def is_smiley(chain):
57 chain=unicode(chain,"utf8")
58 o=re.match(reg_is_smiley,chain)
59 return o
60
61 reg_is_anglicisme = re.compile(u".*(?:^| )(" + u"|".join(config.anglicismes) + u")(?:$|\.| |,|;)")
62 def is_anglicisme(chain):
63 chain = unicode(chain, "utf8").lower()
64 o = re.match(reg_is_anglicisme, chain)
65 return o
66
67 # Cette liste contient la liste des raisons pour lesquelles on peut se faire kicker
68 # chaque élément contient :
69 # - la fonction de détection du kick (qui matchera une regexp et renverra l'objet de match)
70 # - la raison donnée au moment du kick ({0} étant remplacé par ce qui a matché)
71 config.kicking_list = [
72 [is_smiley, u'"{0}" ? Ici on déprime.'],
73 [is_anglicisme, u'"{0}" ? Get out, you and your fucking anglicism !']
74 ]
75
76 def is_something(chain,matches,avant=u".*(?:^| )",apres=u"(?:$|\.| |,|;).*",case_sensitive=False,debug=False):
77 if case_sensitive:
78 chain=unicode(chain,"utf8")
79 else:
80 chain=unicode(chain,"utf8").lower()
81 allmatches="("+"|".join(matches)+")"
82 reg=(avant+allmatches+apres).lower()
83 o=re.match(reg,chain)
84 return o
85
86 def is_insult(chain,debug=True):
87 return is_something(chain,config.insultes,avant=".*(?:^| |')")
88 def is_not_insult(chain):
89 chain=unicode(chain,"utf8")
90 insult_regexp=u"("+u"|".join(config.insultes)+u")"
91 middle_regexp=u"(une? (?:(?:putain|enfoiré) d(?:e |'))*|)(?:| super )(?: (?:gros|petit|grand|énorme) |)"
92 reg=".*pas %s%s.*"%(middle_regexp,insult_regexp)
93 if re.match(reg,chain):
94 return True
95 else:
96 return False
97 def is_compliment(chain,debug=True):
98 return is_something(chain,config.compliment_triggers,avant=".*(?:^| |')")
99 def is_perdu(chain):
100 return is_something(chain,config.perdu)
101 def is_tag(chain):
102 return is_something(chain,config.tag_triggers)
103 def is_tesla(chain):
104 return is_something(chain,config.tesla_triggers,avant=u"^",apres=u"$",debug=True)
105 def is_merci(chain):
106 return is_something(chain,config.merci_triggers)
107 def is_tamere(chain):
108 return is_something(chain,config.tamere_triggers)
109 def is_bad_action_trigger(chain,pseudo):
110 return is_something(chain,config.bad_action_triggers,avant=u"^",
111 apres="(?: [a-z]*ment)? %s($|\.| |,|;).*"%(pseudo))
112 def is_good_action_trigger(chain,pseudo):
113 return is_something(chain,config.good_action_triggers,avant=u"^",
114 apres="(?: [a-z]*ment)? %s($|\.| |,|;).*"%(pseudo))
115 def is_bonjour(chain):
116 return is_something(chain,config.bonjour_triggers,avant=u"^")
117 def is_bonne_nuit(chain):
118 return is_something(chain,config.bonne_nuit_triggers,avant=u"^")
119 def is_pan(chain):
120 return re.match(u"^(pan|bim|bang)( .*)?$",unicode(chain,"utf8").lower().strip())
121
122 def is_time(conf):
123 _,_,_,h,m,s,_,_,_=time.localtime()
124 return (conf[0],0,0)<(h,m,s)<(conf[1],0,0)
125 def is_day():
126 return is_time(config.daytime)
127 def is_night():
128 return is_time(config.nighttime)
129
130
131 class UnicodeBotError(Exception):
132 pass
133 def bot_unicode(chain):
134 try:
135 unicode(chain,"utf8")
136 except UnicodeDecodeError as exc:
137 raise UnicodeBotError
138
139 class Themis(ircbot.SingleServerIRCBot):
140 def __init__(self,serveur,debug=False):
141 temporary_pseudo=config.irc_pseudo+str(random.randrange(10000,100000))
142 ircbot.SingleServerIRCBot.__init__(self, [(serveur, 6667)],
143 temporary_pseudo,"Des[bot]e de #déprime", 10)
144 self.debug=debug
145 self.serveur=serveur
146 self.overops=config.overops
147 self.ops=self.overops+config.ops
148 self.report_bugs_to=config.report_bugs_to
149 self.chanlist=config.chanlist
150 self.kick_channels=config.kick_channels
151 self.stay_channels=config.stay_channels
152 self.quiet_channels=config.quiet_channels
153 self.last_perdu=0
154
155
156 def give_me_my_pseudo(self,serv):
157 serv.privmsg("NickServ","RECOVER %s %s"%(config.irc_pseudo,config.irc_password))
158 serv.privmsg("NickServ","RELEASE %s %s"%(config.irc_pseudo,config.irc_password))
159 time.sleep(0.3)
160 serv.nick(config.irc_pseudo)
161
162 def give_me_my_op_status(self,serv,chan):
163 serv.privmsg("ChanServ","OP %s"%(chan))
164
165 def on_welcome(self, serv, ev):
166 self.serv=serv # ça serv ira
167 self.give_me_my_pseudo(serv)
168 serv.privmsg("NickServ","identify %s"%(config.irc_password))
169 log(self.serveur,"Connected")
170 if self.debug:
171 self.chanlist=["#bot"]
172 self.kick_channels=["#bot"]
173 for c in self.chanlist:
174 log(self.serveur,"JOIN %s"%(c))
175 serv.join(c)
176 self.give_me_my_op_status(serv,c)
177
178
179 def lost(self,serv,channel,forced=False):
180 if self.last_perdu+config.time_between_perdu<time.time() or forced:
181 if not channel in self.quiet_channels or forced:
182 serv.privmsg(channel,"J'ai perdu !")
183 self.last_perdu=time.time()
184 delay=config.time_between_perdu_trigger
185 delta=config.time_between_perdu_trigger_delta
186 serv.execute_delayed(random.randrange(delay-delta,delay+delta),self.lost,(serv,channel))
187
188 def pourmoi(self, serv, message):
189 """renvoie (False,lemessage) ou (True, le message amputé de "pseudo: ")"""
190 pseudo=self.nick
191 size=len(pseudo)
192 if message[:size]==pseudo and len(message)>size and message[size]==":":
193 return (True,message[size+1:].lstrip(" "))
194 else:
195 return (False,message)
196
197 def on_privmsg(self, serv, ev):
198 if ignore_event(serv, ev):
199 return
200 message=ev.arguments()[0]
201 auteur = irclib.nm_to_n(ev.source())
202 try:
203 test=bot_unicode(message)
204 except UnicodeBotError:
205 if config.utf8_trigger:
206 serv.privmsg(auteur, random.choice(config.utf8_fail_answers).encode("utf8"))
207 return
208 message=message.split()
209 cmd=message[0].lower()
210 notunderstood=False
211 if cmd=="help":
212 helpdico={"help":["""HELP <commande>
213 Affiche de l'aide sur la commande""",None,None],
214 "join": [None, """JOIN <channel>
215 Me fait rejoindre le channel""",None],
216 "leave": [None,"""LEAVE <channel>
217 Me fait quitter le channel (sauf s'il est dans ma stay_list).""",None],
218 "quiet": [None,"""QUIET <channel>
219 Me rend silencieux sur le channel.""",None],
220 "noquiet": [None,"""NOQUIET <channel>
221 Me rend la parole sur le channel.""",None],
222 "reload": [None,"""RELOAD
223 Recharge la configuration.""",None],
224 "say": [None,None,"""SAY <channel> <message>
225 Me fait parler sur le channel."""],
226 "do": [None,None,"""DO <channel> <action>
227 Me fait faitre une action (/me) sur le channel."""],
228 "stay": [None,None,"""STAY <channel>
229 Ajoute le channel à ma stay_list."""],
230 "nostay": [None,None,"""NOSTAY <channel>
231 Retire le channel de ma stay_list."""],
232 "ops": [None,None,"""OPS
233 Affiche la liste des ops."""],
234 "overops": [None,None,"""OVEROPS
235 Affiche la liste des overops."""],
236 "kick": [None,None,"""KICK <channel> <pseudo> [<raison>]
237 Kicke <pseudo> du channel (Il faut bien entendu que j'y sois op)."""],
238 "die": [None,None,"""DIE
239 Me déconnecte du serveur IRC."""]
240 }
241 helpmsg_default="Liste des commandes disponibles :\nHELP"
242 helpmsg_ops=" JOIN LEAVE QUIET NOQUIET LOST RELOAD"
243 helpmsg_overops=" SAY DO STAY NOSTAY OPS OVEROPS KICK DIE"
244 op,overop=auteur in self.ops, auteur in self.overops
245 if len(message)==1:
246 helpmsg=helpmsg_default
247 if op:
248 helpmsg+=helpmsg_ops
249 if overop:
250 helpmsg+=helpmsg_overops
251 else:
252 helpmsgs=helpdico.get(message[1].lower(),["Commande inconnue.",None,None])
253 helpmsg=helpmsgs[0]
254 if op and helpmsgs[1]:
255 if helpmsg:
256 helpmsg+="\n"+helpmsgs[1]
257 else:
258 helpmsg=helpmsgs[1]
259 if overop and helpmsgs[2]:
260 if helpmsg:
261 helpmsg+="\n"+helpmsgs[2]
262 else:
263 helpmsg=helpmsgs[2]
264 for ligne in helpmsg.split("\n"):
265 serv.privmsg(auteur,ligne)
266 elif cmd=="join":
267 if auteur in self.ops:
268 if len(message)>1:
269 if message[1] in self.chanlist:
270 serv.privmsg(auteur,"Je suis déjà sur %s"%(message[1]))
271 else:
272 serv.join(message[1])
273 self.chanlist.append(message[1])
274 serv.privmsg(auteur,"Channels : "+" ".join(self.chanlist))
275 log(self.serveur,"priv",auteur," ".join(message))
276 else:
277 serv.privmsg(auteur,"Channels : "+" ".join(self.chanlist))
278 else:
279 notunderstood=True
280 elif cmd=="leave":
281 if auteur in self.ops and len(message)>1:
282 if message[1] in self.chanlist:
283 if not (message[1] in self.stay_channels) or auteur in self.overops:
284 self.quitter(message[1]," ".join(message[2:]))
285 self.chanlist.remove(message[1])
286 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
287 else:
288 serv.privmsg(auteur,random.choice(config.leave_fail_messages))
289 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
290 else:
291 serv.privmsg(auteur,"Je ne suis pas sur %s"%(message[1]))
292 else:
293 notunderstood=True
294 elif cmd=="stay":
295 if auteur in self.overops:
296 if len(message)>1:
297 if message[1] in self.stay_channels:
298 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
299 serv.privmsg(auteur,"Je stay déjà sur %s."%(message[1]))
300 else:
301 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
302 self.stay_channels.append(message[1])
303 serv.privmsg(auteur,"Stay channels : "+" ".join(self.stay_channels))
304 else:
305 serv.privmsg(auteur,"Stay channels : "+" ".join(self.stay_channels))
306 else:
307 notunderstood=True
308 elif cmd=="nostay":
309 if auteur in self.overops:
310 if len(message)>1:
311 if message[1] in self.stay_channels:
312 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
313 self.stay_channels.remove(message[1])
314 serv.privmsg(auteur,"Stay channels : "+" ".join(self.stay_channels))
315 else:
316 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
317 serv.privmsg(auteur,"Je ne stay pas sur %s."%(message[1]))
318
319 else:
320 notunderstood=True
321 elif cmd=="die":
322 if auteur in self.overops:
323 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
324 self.mourir()
325 else:
326 notunderstood=True
327 elif cmd=="quiet":
328 if auteur in self.ops:
329 if len(message)>1:
330 if message[1] in self.quiet_channels:
331 serv.privmsg(auteur,"Je me la ferme déjà sur %s"%(message[1]))
332 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
333 else:
334 self.quiet_channels.append(message[1])
335 serv.privmsg(auteur,"Quiet channels : "+" ".join(self.quiet_channels))
336 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
337 else:
338 serv.privmsg(auteur,"Quiet channels : "+" ".join(self.quiet_channels))
339 else:
340 notunderstood=True
341 elif cmd=="noquiet":
342 if auteur in self.ops:
343 if len(message)>1:
344 if message[1] in self.quiet_channels:
345 self.quiet_channels.remove(message[1])
346 serv.privmsg(auteur,"Quiet channels : "+" ".join(self.quiet_channels))
347 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
348 else:
349 serv.privmsg(auteur,"Je ne me la ferme pas sur %s."%(message[1]))
350 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
351 else:
352 notunderstood=True
353 elif cmd=="reload":
354 if auteur in self.ops:
355 self.reload(auteur)
356 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
357 else:
358 notunderstood=True
359 elif cmd=="say":
360 if auteur in self.overops and len(message)>2:
361 serv.privmsg(message[1]," ".join(message[2:]))
362 log(self.serveur,"priv",auteur," ".join(message))
363 elif len(message)<=2:
364 serv.privmsg(auteur,"Syntaxe : SAY <channel> <message>")
365 else:
366 notunderstood=True
367 elif cmd=="do":
368 if auteur in self.overops and len(message)>2:
369 serv.action(message[1]," ".join(message[2:]))
370 log(self.serveur,"priv",auteur," ".join(message))
371 elif len(message)<=2:
372 serv.privmsg(auteur,"Syntaxe : DO <channel> <action>")
373 else:
374 notunderstood=True
375 elif cmd=="kick":
376 if auteur in self.overops and len(message)>2:
377 serv.kick(message[1],message[2]," ".join(message[3:]))
378 log(self.serveur,"priv",auteur," ".join(message))
379 elif len(message)<=2:
380 serv.privmsg(auteur,"Syntaxe : KICK <channel> <pseudo> [<raison>]")
381 else:
382 notunderstood=True
383 elif cmd=="ops":
384 if auteur in self.overops:
385 serv.privmsg(auteur," ".join(self.ops))
386 else:
387 notunderstood=True
388 elif cmd=="overops":
389 if auteur in self.overops:
390 serv.privmsg(auteur," ".join(self.overops))
391 else:
392 notunderstood=True
393 else:
394 notunderstood=True
395 if notunderstood:
396 serv.privmsg(auteur,"Je n'ai pas compris. Essayez HELP…")
397
398 def on_pubmsg(self, serv, ev):
399 if ignore_event(serv, ev):
400 return
401 auteur = irclib.nm_to_n(ev.source())
402 canal = ev.target()
403 message = ev.arguments()[0]
404 try:
405 test=bot_unicode(message)
406 except UnicodeBotError:
407 if config.utf8_trigger and not canal in self.quiet_channels:
408 serv.privmsg(canal, (u"%s: %s"%(auteur,random.choice(config.utf8_fail_answers))).encode("utf8"))
409 return
410 pour_moi,message=self.pourmoi(serv,message)
411 for (detect, reason) in config.kicking_list:
412 matching = detect(message)
413 if matching:
414 if canal in self.kick_channels:
415 serv.kick(canal,auteur,(reason.format(matching.groups()[0])).encode("utf8"))
416 return
417 if pour_moi and message.split()!=[]:
418 cmd=message.split()[0].lower()
419 try:
420 args=" ".join(message.split()[1:])
421 except:
422 args=""
423 if cmd in ["meurs","die","crève","pends-toi"]:
424 if auteur in self.overops:
425 log(self.serveur,canal,auteur,message+"[successful]")
426 self.mourir()
427 else:
428 serv.privmsg(canal,"%s: %s"%(auteur,random.choice(config.quit_fail_messages)))
429 log(self.serveur,canal,auteur,message+"[failed]")
430 elif cmd == "reload":
431 if auteur in self.ops:
432 log(self.serveur, canal, auteur, message+"[successful]")
433 self.reload(canal)
434 elif cmd in ["part","leave","dégage","va-t-en"]:
435 if auteur in self.ops and (not (canal in self.stay_channels)
436 or auteur in self.overops):
437 self.quitter(canal)
438 log(self.serveur,canal,auteur,message+"[successful]")
439 if canal in self.chanlist:
440 self.chanlist.remove(canal)
441 else:
442 serv.privmsg(canal,"%s: %s"%(auteur,random.choice(config.leave_fail_messages)))
443 log(self.serveur,canal,auteur,message+"[failed]")
444
445 elif cmd in ["deviens","pseudo"]:
446 if auteur in self.ops:
447 become=args
448 serv.nick(become)
449 log(self.serveur,canal,auteur,message+"[successful]")
450
451 elif cmd in ["meur", "meurt","meurre","meurres"] and not canal in self.quiet_channels:
452 serv.privmsg(canal,'%s: Mourir, impératif, 2ème personne du singulier : "meurs" (de rien)'%(auteur))
453 elif cmd in ["ping"] and not canal in self.quiet_channels:
454 serv.privmsg(canal,"%s: pong"%(auteur))
455 # if is_insult(message) and not canal in self.quiet_channels:
456 # if is_not_insult(message):
457 # answer=random.choice(config.compliment_answers)
458 # for ligne in answer.split("\n"):
459 # serv.privmsg(canal,"%s: %s"%(auteur,ligne.encode("utf8")))
460 # else:
461 # answer=random.choice(config.insultes_answers)
462 # for ligne in answer.split("\n"):
463 # serv.privmsg(canal,"%s: %s"%(auteur,ligne.encode("utf8")))
464 # elif is_compliment(message) and not canal in self.quiet_channels:
465 # answer=random.choice(config.compliment_answers)
466 # for ligne in answer.split("\n"):
467 # serv.privmsg(canal,"%s: %s"%(auteur,ligne.encode("utf8")))
468 elif is_tesla(message) and not canal in self.quiet_channels:
469 l1,l2=config.tesla_answers,config.tesla_actions
470 n1,n2=len(l1),len(l2)
471 i=random.randrange(n1+n2)
472 if i>=n1:
473 serv.action(canal,l2[i-n1].encode("utf8"))
474 else:
475 serv.privmsg(canal,"%s: %s"%(auteur,l1[i].encode("utf8")))
476 elif is_tag(message) and not canal in self.quiet_channels:
477 if auteur in self.ops:
478 action=random.choice(config.tag_actions)
479 serv.action(canal,action.encode("utf8"))
480 self.quiet_channels.append(canal)
481 else:
482 answer=random.choice(config.tag_answers)
483 for ligne in answer.split("\n"):
484 serv.privmsg(canal,"%s: %s"%(auteur,ligne.encode("utf8")))
485 elif is_bonjour(message) and not canal in self.quiet_channels:
486 if is_night():
487 answer=random.choice(config.night_answers)
488 elif is_day():
489 answer=random.choice(config.bonjour_answers)
490 else:
491 answer=random.choice(config.bonsoir_answers)
492 serv.privmsg(canal,answer.format(auteur).encode("utf8"))
493 elif is_bonne_nuit(message) and not canal in self.quiet_channels:
494 answer=random.choice(config.bonne_nuit_answers)
495 serv.privmsg(canal,answer.format(auteur).encode("utf8"))
496 else:
497 if not canal in self.quiet_channels:
498 mypseudo=self.nick
499 if re.match((u"^("+u"|".join(config.bonjour_triggers)
500 +u")( {}| all| tout le monde|(|à) tous)(\.|( |)!|)$"
501 ).format(mypseudo).lower(), message.strip().lower()):
502 answer=random.choice(config.bonjour_answers)
503 serv.privmsg(canal,answer.format(auteur).encode("utf8"))
504
505 def on_action(self, serv, ev):
506 if ignore_event(serv, ev):
507 return
508 action = ev.arguments()[0]
509 auteur = irclib.nm_to_n(ev.source())
510 channel = ev.target()
511 try:
512 test=bot_unicode(action)
513 except UnicodeBotError:
514 if config.utf8_trigger and not canal in self.quiet_channels:
515 serv.privmsg(canal, (u"%s: %s"%(auteur,random.choice(config.utf8_fail_answers))).encode("utf8"))
516 return
517 mypseudo=self.nick
518
519 # if is_bad_action_trigger(action,mypseudo) and not channel in self.quiet_channels:
520 # l1,l2=config.bad_action_answers,config.bad_action_actions
521 # n1,n2=len(l1),len(l2)
522 # i=random.randrange(n1+n2)
523 # if i>=n1:
524 # serv.action(channel,l2[i-n1].format(auteur).encode("utf8"))
525 # else:
526 # serv.privmsg(channel,l1[i].format(auteur).format(auteur).encode("utf8"))
527 # if is_good_action_trigger(action,mypseudo) and not channel in self.quiet_channels:
528 # l1,l2=config.good_action_answers,config.good_action_actions
529 # n1,n2=len(l1),len(l2)
530 # i=random.randrange(n1+n2)
531 # if i>=n1:
532 # serv.action(channel,l2[i-n1].format(auteur).format(auteur).encode("utf8"))
533 # else:
534 # serv.privmsg(channel,l1[i].format(auteur).format(auteur).encode("utf8"))
535
536 def on_kick(self,serv,ev):
537 auteur = irclib.nm_to_n(ev.source())
538 channel = ev.target()
539 victime = ev.arguments()[0]
540 raison = ev.arguments()[1]
541 if victime==self.nick:
542 log(self.serveur,"%s kické de %s par %s (raison : %s)" %(victime,channel,auteur,raison))
543 time.sleep(2)
544 serv.join(channel)
545 username = irclib.nm_to_u(ev.source()).lower()
546 print ev.source()
547 print channel, username
548 if channel == "#déprime" and "peb" in username or "becue" in username:
549 print "Kicking peb"
550 serv.execute_delayed(5, serv.kick, (auteur, "Va abuser de tes droits ailleurs !"))
551
552 def kicker(self, chan, pseudo, raison=None):
553 if raison==None:
554 raison = config.kick_default_reason
555 self.serv.kick(chan,pseudo,raison)
556
557 def quitter(self,chan,leave_message=None):
558 if leave_message==None:
559 leave_message=random.choice(config.leave_messages)
560 self.serv.part(chan,message=leave_message.encode("utf8"))
561
562 def mourir(self):
563 quit_message=random.choice(config.quit_messages)
564 self.die(msg=quit_message.encode("utf8"))
565
566 def _getnick(self):
567 return self.serv.get_nickname()
568 nick=property(_getnick)
569
570 def reload(self, auteur=None):
571 reload(config)
572 if auteur in [None, "SIGHUP"]:
573 towrite = "Config reloaded" + " (SIGHUP received)"*(auteur == "SIGHUP")
574 for to in config.report_bugs_to:
575 self.serv.privmsg(to, towrite)
576 log(self.serveur, towrite)
577 else:
578 self.serv.privmsg(auteur,"Config reloaded")
579
580 def start_as_daemon(self, outfile):
581 sys.stderr = Logger(outfile)
582 self.start()
583
584
585 class Logger(object):
586 """Pour écrire ailleurs que sur stdout"""
587 def __init__(self, filename="themis.full.log"):
588 self.filename = filename
589
590 def write(self, message):
591 f = open(self.filename, "a")
592 f.write(message)
593 f.close()
594
595
596 if __name__=="__main__":
597 import sys
598 if len(sys.argv)==1:
599 print "Usage : themis.py <serveur> [--debug] [--no-output] [--daemon [--pidfile]] [--outfile]"
600 print " --outfile sans --no-output ni --daemon n'a aucun effet"
601 exit(1)
602 serveur=sys.argv[1]
603 if "--daemon" in sys.argv:
604 thisfile = os.path.realpath(__file__)
605 thisdirectory = thisfile.rsplit("/", 1)[0]
606 os.chdir(thisdirectory)
607 daemon = True
608 else:
609 daemon = False
610 if "debug" in sys.argv or "--debug" in sys.argv:
611 debug=True
612 else:
613 debug=False
614 if "--no-output" in sys.argv or "--daemon" in sys.argv:
615 outfile = "/var/log/bots/themis.full.log"
616 for arg in sys.argv:
617 arg = arg.split("=")
618 if arg[0].strip('-') in ["out", "outfile", "logfile"]:
619 outfile = arg[1]
620 sys.stdout = Logger(outfile)
621 serveurs={"a♡":"acoeur.crans.org","acoeur":"acoeur.crans.org","acoeur.crans.org":"acoeur.crans.org",
622 "irc":"irc.crans.org","crans":"irc.crans.org","irc.crans.org":"irc.crans.org"}
623 try:
624 serveur=serveurs[serveur]
625 except KeyError:
626 print "Server Unknown : %s"%(serveur)
627 exit(404)
628 themis=Themis(serveur,debug)
629 # Si on reçoit un SIGHUP, on reload la config
630 def sighup_handler(signum, frame):
631 themis.reload("SIGHUP")
632 signal.signal(signal.SIGHUP, sighup_handler)
633 if daemon:
634 child_pid = os.fork()
635 if child_pid == 0:
636 os.setsid()
637 themis.start_as_daemon(outfile)
638 else:
639 # on enregistre le pid de themis
640 pidfile = "/var/run/bots/themis.pid"
641 for arg in sys.argv:
642 arg = arg.split("=")
643 if arg[0].strip('-') in ["pidfile"]:
644 pidfile = arg[1]
645 f = open(pidfile, "w")
646 f.write("%s\n" % child_pid)
647 f.close()
648 else:
649 themis.start()
650