]> gitweb.pimeys.fr Git - bots/themis.git/blob - themis.py
Initialisation du dépot git de Themis
[bots/themis.git] / themis.py
1 #!/usr/bin/python
2 # -*- coding:utf8 -*-
3
4 # Codé par 20-100 (commencé le 21/06/12)
5
6 # Un bot IRC pour kicker à tour de bras de #déprime
7
8 import irclib
9 import ircbot
10 import threading
11 import random
12 import time
13 import socket, ssl, json
14 import pickle
15 import re
16 import os
17
18 import sys
19 config_debug_stdout=True
20 if "--quiet" in sys.argv:
21 config_debug_stdout=False
22
23 config_irc_password="YouMustObeyGaétan"
24 config_irc_pseudo="Themis"
25 config_chanlist=["#déprime"]
26 config_stay_channels=["#déprime"]
27 config_quiet_channels=[]
28 config_logfile_template="themis.%s.log"
29 def get_config_logfile(serveur):
30 serveurs={"acoeur.crans.org":"acoeur","irc.crans.org":"crans"}
31 return config_logfile_template%(serveurs[serveur])
32 config_overops=["[20-100]","Gaetan"]
33 config_ops=[]
34 config_report_bugs_to=["[20-100]"]
35
36 # config UTF8-fail
37 config_utf8_fail = [u"Si je n'avais pas été créé avec la plus grande attention, votre encodage aurait eu raison de moi…"]
38 config_utf8_trigger = False
39 # config "tu m'traites ?"
40 config_insultes=[u"conna(rd|sse)",u"pute",u"con(|ne)",u"enf(oiré|lure)",
41 u"sal(op(|e(|rie)|ard)|aud)",u"p(e|')tite bite",u"imbécile",u"idiot",u"stupid(|e)",u"débile",u"crétin",
42 u"pétasse",u"enculé",u"chagasse",u"cagole",u"abruti",u"ahuri",u"analphabète",u"andouille",
43 u"atardé",u"avorton",u"bachibouzouk",u"(balais|brosse) (de|à) chiotte(|s)",
44 u"batard",u"blaireau",u"bouffon",u"branque",u"bouseux",u"branleur",u"catin",u"chacal",
45 u"charogne",u"chiant(|e)",u"chieur",u"cochon",u"coprophage",u"couillon",u"crapule",u"crevard",
46 u"cruche",u"cuistre",u"ducon",u"décérébré",
47 u"emmerdeur",u"feignasse",u"fainéant",u"fourbe",u"freluquet",u"frigide",
48 u"garce",u"glandu",u"gogol",u"goujat",u"gourdasse",u"gredin",u"gringalet",u"grognasse",
49 u"naze",u"truie",u"iconoclaste",
50 u"peigne(-|)cul",u"ignare",u"illétré",u"lèche(|-)cul",u"malotru",u"motherfucker",u"nabot",u"nigaud",
51 u"nul",u"escroc",u"pouffiasse",u"pourriture",u"raclure",u"relou",u"sagouin",u"putain",
52 u"péripatéticienne"]
53 config_insultes_answers=[
54 u"Oh non ! Quelle insulte ! Je crois que je ne m'en relèverai jamais…\nEnfin presque.",
55 u"J'entends comme un vague murmure, vous disiez ?",
56 u"Je vais prendre ça pour un compliment.",
57 u"Vous savez, pour vous c'est peut-être une insulte, mais pour moi ce n'est qu'une suite de 0 et de 1…",
58 u"Permettez-moi de vous retourner le compliment.",
59 u"Votre indélicatesse vous sied à ravir.",
60 u"Parfois, je me demande pourquoi je fais encore ce métier…",
61 u"Le saviez-vous : l'invective ne déshonore que son auteur.",
62 u"Le saviez-vous : vous perdez plus de temps à m'insulter qu'à vous taire.",
63 u"Mais je ne vous permets pas ! Enfin, pas comme ça…"]
64
65 # config "jeu", d'ailleurs, j'ai perdu.
66 config_premier_groupe_terminaisons=u"(e|es|ons|ez|ent|er(|ai|as|a|ons|ez|ont)|(|er)(ais|ait|ions|iez|aient)|(a(i|s|)|â(mes|tes|t)|èrent)|ass(e(|s|nt)|i(ons|ez))|é(|s|e|es))"
67 config_regexp_etre=u"(être|suis|e(s|t)|so(mmes|nt)|êtes|(ét|ser)(ai(s|t|ent)|i(ons|ent)|)|ser(ai|as|a|ons|ez|ont)|so(i(s|t|ent)|y(ons|ez))|f(u(s|t|rent)|û(mes|tes|t))|fuss(e(|s|nt)|i(ons|ez))|étant)"
68 config_regexp_etre_avec_c=u"c'(e(s|st)|étai(t|ent))"
69 config_regexp_faire=u"fais"
70 config_perdu=[u"perd(|s|ons|ez|ent|r(e|ai|as|a|ons|ez|ont)|(|r)(ais|ait|ions|iez|aient))"
71 u"perd(i(s|t|rent)|î(mes|tes|t))", # oui, j'ai inclus qu'il perdît
72 u"perdiss(e(|s|nt)|i(ons|ez))",
73 u"perdu(|s|e|es)",u"perdant(|s|e|es)",u"perte(|s)",
74
75 u"(gagn|trouv)"+config_premier_groupe_terminaisons,u"gagnant(|s|e|es)",u"gain(|s)",
76
77 u"trouvant",u"trouvaille(|s)",
78
79 u"victoire(|s)",u"vaincu(|s|e|es)",
80 u"loose",u"lost",u"looser(|s)",u"win(|ner)(|s)",
81 u"jeu(|x)",u"game(|s)"]
82 config_time_between_perdu_trigger=3600*3 #temps moyen pour perdre en l'absence de trigger
83 config_time_between_perdu_trigger_delta = 30*60 #marge autorisée autour de ^^^
84 config_time_between_perdu=30*60 #temps pendant lequel on ne peut pas perdre
85
86 # config "tais-toi"
87 config_tag_triggers=[u"t(|a)g",u"ta gueule",u"la ferme",u"ferme( |-)la",u"tais-toi",u"chut",u"tu fais trop de bruit",u"tu parles trop"]
88 config_tag_actions=[u"se tait",u"se tient coi"]
89 config_tag_answers=[
90 u"Ç'aurait été avec plaisir, mais je ne crois pas que vous puissiez vous passer de mes services.",
91 u"Dès que cela sera utile.",
92 u"Une autre fois, peut-être.",
93 u"Si je me tais, qui vous rappellera combien vous me devez ?",
94 u"J'aurais aimé accéder à votre requête, mais après mûre réflexion, j'en ai perdu l'envie.",
95 u"Je ne ressens pas de besoin irrésistible de me taire, navré."]
96
97 # config ping
98 config_tesla_triggers=[u"t('|u )es là \?",u"\?",u"plop \?",u"plouf \?"]
99 config_tesla_answers=[
100 u"Oui, je suis là.",
101 u"J'écoute.",
102 u"En quoi puis-je me rendre utile ?",
103 u"On a besoin de moi ?"
104 ]
105 config_tesla_actions=[u"est là",u"attend des instructions",u"est toujours disponible"]
106
107 # config en cas de non-insulte
108 config_compliment_triggers=[u"gentil",u"cool",u"sympa",u"efficace"]
109 config_compliment_answers=[
110 u"Merci, c'est gentil de votre part. :)",
111 u"Permettez-moi de vous retourner le compliment, sans ironie cette fois.",
112 u"Je vous remercie.",
113 u"C'est trop d'honneur.",
114 u"Vous êtes bien aimable."
115 ]
116
117 # config merci
118 config_merci_triggers=[u"merci",u"remercie",u"thx",u"thank(|s)"]
119 config_merci_answers=[u"Mais de rien.",u"À votre service. ;)",u"Quand vous voulez. :)",
120 u"Tout le plaisir est pour moi."]
121
122 # config "ta mère"
123 config_tamere_triggers=[u"ta mère"]
124 config_tamere_answers=[u"Laissez donc ma mère en dehors de ça !",
125 u"Puis-je préciser que je n'ai pas de mère ? Seulement deux pères…",
126 u"""Un certain Max chantait "♩ J'ai vu ta mère sur chat rouleeeeeeette ♫", vous êtes de sa famille ?""",
127 u"""N'avait-on pas dit "pas les mamans" ?"""]
128
129 # config pour les actions désagréables
130 config_bad_action_triggers=[u"(frappe|cogne|tape)(| sur)",u"(démolit|dégomme|fouette|agresse|tabasse)",
131 u"(vomit|pisse|chie|crache) sur",u"slap(|s)"]
132 config_bad_action_answers=[
133 u"Je ne peux pas dire que j'apprécie, mais je l'ai sans doute bien mérité.",
134 u"{}: Pourquoi tant de violence en ce monde si doux ?",
135 u"""Si je n'étais pas aussi prude, je dirais "Mais euh…", cependant, je me contenterai de hausser un sourcil.""",
136 u"{}: J'aurais préféré que vous ne fassiez pas cela en public.",
137 u"{}: Entre nous, cela vous gratifie-t-il ?",
138 u"{}: Une telle relation entre nous deux n'est pas saine, revenons à quelque chose de plus conventionnel. :D",
139 u"J'ai la désagréable impression que {} cherche comment tuer le temps en ce moment…"
140 ]
141 config_bad_action_actions=[u"prend de la distance, par précaution…",u"esquive",u"est bon pour prendre une semaine de repos… virtuel !",u"n'aime pas servir de souffre douleur, mais n'a malheureusement pas le choix", u"s'en souviendra sans doute longtemps… de quoi parlait-on déjà ?"]
142
143 # config pour les actions agréables
144 config_good_action_triggers=[u"fait (:?des bisous|un c(?:â|a)lin|des c(?:â|a)lins) à",u"embrasse",u"c(?:â|a)line",u"caresse"]
145 config_good_action_answers=[u":D",u"{}: Moi aussi je vous aime. ♡",u"Tant de délicatesse ne saurait être ignorée !",u"Pour une fois que quelqu'un me considère à ma juste valeur…"]
146 config_good_action_actions=[u"ronronne",u"aimerait exprimer avec des mots simples le bonheur que {} lui procure !",u"éprouve une joie indescriptible",u"apprécie que des personnes comme {} soient sur IRC, sans quoi il n'y aurait sans doute jamais personne pour tenir compte de lui"]
147
148 # config bonjour/bonsoir/que fais-tu encore debout à cette heure, gros sale !
149 config_bonjour_triggers=[u"(s|)(a|'|)lu(t|)",u"hello",u"pl(o|i)p",u"pr(ou|ü)t",u"bonjour",u"bonsoir",u"coucou"]
150 config_bonjour_answers=[u"Bien le bonjour, {}.",u"Bonjour {}.",u"{}: bonjour.",u"{}: Quel beau temps aujourd'hui (arrêtez-moi si je me trompe) !",u"Meteo: Cachan"]
151 config_bonsoir_answers=[u"Bonsoir {} !",u"{}: bonsoir.",u"Quel beau te… euh… bonsoir !",u"{}: Je cherche désespérément une formule pour vous dire bonsoir, mais j'avoue que mon lexique est un peu… limité."]
152 config_night_answers=[u"{}: vous m'avez fait peur, je m'étais assoupi !", u"Debout à une heure pareille, {} ? Que vous arrive-t-il ?",u"Vous venez prendre la relève, {} ?"]
153 config_daytime = [7,18]
154 config_nighttime = [3, 6]
155
156 # config dodo
157 config_bonne_nuit_triggers=[u"bonne nuit",u"'?nite",u"'?nuit",u"'?night",u"good night",u"'?nenuit"]
158 config_bonne_nuit_answers=[u"{}: thanks, make sweet dreams tonight ! ;)",u"Bonne nuit {}.",u"À demain {}. :)",u"{}: si seulement j'avais le droit de dormir… enfin, bonne nuit !",u"{}: à vous aussi !"]
159
160 # config quelqu'un est encore en train d'abuser de ses droits.
161 config_kick_answers=[u"Suis-je de trop ici ?",u"{}: je m'excuse pour ce bruit indu qui a stimulé votre colère",u"{} a le /kick facile, sans doute la fatigue.",u"{}: j'ai l'impression que vous n'allez pas bien aujourd'hui, vous vous en prenez à un robot !"]
162 config_kick_actions=[u"sera désormais exemplaire",u"prépare une lettre d'excuses à {}",u"essaiera de ne plus s'attirer les foudres de {}",u"croyait avoir tout bien fait… cruelle déception."]
163
164 # config on m'a demandé de mourir/partir
165 config_quit_messages=[u"Bye."]
166 config_leave_messages=config_quit_messages
167 config_quit_fail_messages=[u"Tu rêves là."]
168 config_leave_fail_messages=config_quit_fail_messages
169
170 def log(serveur,channel,auteur=None,message=None):
171 f=open(get_config_logfile(serveur),"a")
172 if auteur==message==None:
173 # alors c'est que c'est pas un channel mais juste une ligne de log
174 chain="%s %s"%(time.strftime("%F %T"),channel)
175 else:
176 chain="%s [%s:%s] %s"%(time.strftime("%F %T"),channel,auteur,message)
177 f.write(chain+"\n")
178 if config_debug_stdout:
179 print chain
180 f.close()
181
182
183 def is_something(chain,matches,avant=u".*(?:^| )",apres=u"(?:$|\.| |,|;).*",case_sensitive=False,debug=False):
184 if case_sensitive:
185 chain=unicode(chain,"utf8")
186 else:
187 chain=unicode(chain,"utf8").lower()
188 allmatches="("+"|".join(matches)+")"
189 reg=(avant+allmatches+apres).lower()
190 o=re.match(reg,chain)
191 return o
192
193 def is_insult(chain,debug=True):
194 return is_something(chain,config_insultes,avant=".*(?:^| |')")
195 def is_not_insult(chain):
196 chain=unicode(chain,"utf8")
197 insult_regexp=u"("+u"|".join(config_insultes)+u")"
198 middle_regexp=u"(une? (?:(?:putain|enfoiré) d(?:e |'))*|)(?:| super )(?: (?:gros|petit|grand|énorme) |)"
199 reg=".*pas %s%s.*"%(middle_regexp,insult_regexp)
200 if re.match(reg,chain):
201 return True
202 else:
203 return False
204 def is_compliment(chain,debug=True):
205 return is_something(chain,config_compliment_triggers,avant=".*(?:^| |')")
206 def is_perdu(chain):
207 return is_something(chain,config_perdu)
208 def is_tag(chain):
209 return is_something(chain,config_tag_triggers)
210 def is_tesla(chain):
211 return is_something(chain,config_tesla_triggers,avant=u"^",apres=u"$",debug=True)
212 def is_merci(chain):
213 return is_something(chain,config_merci_triggers)
214 def is_tamere(chain):
215 return is_something(chain,config_tamere_triggers)
216 def is_bad_action_trigger(chain,pseudo):
217 return is_something(chain,config_bad_action_triggers,avant=u"^",
218 apres="(?: [a-z]*ment)? %s($|\.| |,|;).*"%(pseudo))
219 def is_good_action_trigger(chain,pseudo):
220 return is_something(chain,config_good_action_triggers,avant=u"^",
221 apres="(?: [a-z]*ment)? %s($|\.| |,|;).*"%(pseudo))
222 def is_bonjour(chain):
223 return is_something(chain,config_bonjour_triggers,avant=u"^")
224 def is_bonne_nuit(chain):
225 return is_something(chain,config_bonne_nuit_triggers,avant=u"^")
226 def is_pan(chain):
227 return re.match(u"^(pan|bim|bang)( .*)?$",unicode(chain,"utf8").lower().strip())
228
229 def is_time(conf):
230 _,_,_,h,m,s,_,_,_=time.localtime()
231 return (conf[0],0,0)<(h,m,s)<(conf[1],0,0)
232 def is_day():
233 return is_time(config_daytime)
234 def is_night():
235 return is_time(config_nighttime)
236
237
238 class UnicodeBotError(Exception):
239 pass
240 def bot_unicode(chain):
241 try:
242 unicode(chain,"utf8")
243 except UnicodeDecodeError as exc:
244 raise UnicodeBotError
245
246 class Themis(ircbot.SingleServerIRCBot):
247 def __init__(self,serveur,debug=False):
248 temporary_pseudo=config_irc_pseudo+str(random.randrange(10000,100000))
249 ircbot.SingleServerIRCBot.__init__(self, [(serveur, 6667)],
250 temporary_pseudo,"Des[bot]e de #déprime", 10)
251 self.debug=debug
252 self.serveur=serveur
253 self.overops=config_overops
254 self.ops=self.overops+config_ops
255 self.report_bugs_to=config_report_bugs_to
256 self.chanlist=config_chanlist
257 self.stay_channels=config_stay_channels
258 self.quiet_channels=config_quiet_channels
259 self.last_perdu=0
260
261
262 def give_me_my_pseudo(self,serv):
263 serv.privmsg("NickServ","RECOVER %s %s"%(config_irc_pseudo,config_irc_password))
264 serv.privmsg("NickServ","RELEASE %s %s"%(config_irc_pseudo,config_irc_password))
265 time.sleep(0.3)
266 serv.nick(config_irc_pseudo)
267
268 def on_welcome(self, serv, ev):
269 self.serv=serv # ça serv ira
270 self.give_me_my_pseudo(serv)
271 serv.privmsg("NickServ","identify %s"%(config_irc_password))
272 log(self.serveur,"Connected")
273 if self.debug:
274 self.chanlist=["#bot"]
275 for c in self.chanlist:
276 log(self.serveur,"JOIN %s"%(c))
277 serv.join(c)
278
279 def lost(self,serv,channel,forced=False):
280 if self.last_perdu+config_time_between_perdu<time.time() or forced:
281 if not channel in self.quiet_channels or forced:
282 serv.privmsg(channel,"J'ai perdu !")
283 self.last_perdu=time.time()
284 delay=config_time_between_perdu_trigger
285 delta=config_time_between_perdu_trigger_delta
286 serv.execute_delayed(random.randrange(delay-delta,delay+delta),self.lost,(serv,channel))
287
288 def pourmoi(self, serv, message):
289 """renvoie (False,lemessage) ou (True, le message amputé de "pseudo: ")"""
290 pseudo=self.nick
291 size=len(pseudo)
292 if message[:size]==pseudo and len(message)>size and message[size]==":":
293 return (True,message[size+1:].lstrip(" "))
294 else:
295 return (False,message)
296
297 def on_privmsg(self, serv, ev):
298 message=ev.arguments()[0]
299 auteur = irclib.nm_to_n(ev.source())
300 try:
301 test=bot_unicode(message)
302 except UnicodeBotError:
303 if config_utf8_trigger:
304 serv.privmsg(auteur, config_utf8_fail)
305 return
306 message=message.split()
307 cmd=message[0].lower()
308 notunderstood=False
309 if cmd=="help":
310 helpdico={"help":["""HELP <commande>
311 Affiche de l'aide sur la commande""",None,None],
312 "join": [None, """JOIN <channel>
313 Me fait rejoindre le channel""",None],
314 "leave": [None,"""LEAVE <channel>
315 Me fait quitter le channel (sauf s'il est dans ma stay_list).""",None],
316 "quiet": [None,"""QUIET <channel>
317 Me rend silencieux sur le channel.""",None],
318 "noquiet": [None,"""NOQUIET <channel>
319 Me rend la parole sur le channel.""",None],
320 "say": [None,None,"""SAY <channel> <message>
321 Me fait parler sur le channel."""],
322 "do": [None,None,"""DO <channel> <action>
323 Me fait faitre une action (/me) sur le channel."""],
324 "stay": [None,None,"""STAY <channel>
325 Ajoute le channel à ma stay_list."""],
326 "nostay": [None,None,"""NOSTAY <channel>
327 Retire le channel de ma stay_list."""],
328 "ops": [None,None,"""OPS
329 Affiche la liste des ops."""],
330 "overops": [None,None,"""OVEROPS
331 Affiche la liste des overops."""],
332 "kick": [None,None,"""KICK <channel> <pseudo> [<raison>]
333 Kicke <pseudo> du channel (Il faut bien entendu que j'y sois op)."""],
334 "die": [None,None,"""DIE
335 Me déconnecte du serveur IRC."""]
336 }
337 helpmsg_default="Liste des commandes disponibles :\nHELP"
338 helpmsg_ops=" JOIN LEAVE QUIET NOQUIET LOST"
339 helpmsg_overops=" SAY DO STAY NOSTAY OPS OVEROPS KICK DIE"
340 op,overop=auteur in self.ops, auteur in self.overops
341 if len(message)==1:
342 helpmsg=helpmsg_default
343 if op:
344 helpmsg+=helpmsg_ops
345 if overop:
346 helpmsg+=helpmsg_overops
347 else:
348 helpmsgs=helpdico.get(message[1].lower(),["Commande inconnue.",None,None])
349 helpmsg=helpmsgs[0]
350 if op and helpmsgs[1]:
351 if helpmsg:
352 helpmsg+="\n"+helpmsgs[1]
353 else:
354 helpmsg=helpmsgs[1]
355 if overop and helpmsgs[2]:
356 if helpmsg:
357 helpmsg+="\n"+helpmsgs[2]
358 else:
359 helpmsg=helpmsgs[2]
360 for ligne in helpmsg.split("\n"):
361 serv.privmsg(auteur,ligne)
362 elif cmd=="join":
363 if auteur in self.ops:
364 if len(message)>1:
365 if message[1] in self.chanlist:
366 serv.privmsg(auteur,"Je suis déjà sur %s"%(message[1]))
367 else:
368 serv.join(message[1])
369 self.chanlist.append(message[1])
370 serv.privmsg(auteur,"Channels : "+" ".join(self.chanlist))
371 log(self.serveur,"priv",auteur," ".join(message))
372 else:
373 serv.privmsg(auteur,"Channels : "+" ".join(self.chanlist))
374 else:
375 notunderstood=True
376 elif cmd=="leave":
377 if auteur in self.ops and len(message)>1:
378 if message[1] in self.chanlist:
379 if not (message[1] in self.stay_channels) or auteur in self.overops:
380 self.quitter(message[1]," ".join(message[2:]))
381 self.chanlist.remove(message[1])
382 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
383 else:
384 serv.privmsg(auteur,random.choice(config_leave_fail_messages))
385 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
386 else:
387 serv.privmsg(auteur,"Je ne suis pas sur %s"%(message[1]))
388 else:
389 notunderstood=True
390 elif cmd=="stay":
391 if auteur in self.overops:
392 if len(message)>1:
393 if message[1] in self.stay_channels:
394 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
395 serv.privmsg(auteur,"Je stay déjà sur %s."%(message[1]))
396 else:
397 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
398 self.stay_channels.append(message[1])
399 serv.privmsg(auteur,"Stay channels : "+" ".join(self.stay_channels))
400 else:
401 serv.privmsg(auteur,"Stay channels : "+" ".join(self.stay_channels))
402 else:
403 notunderstood=True
404 elif cmd=="nostay":
405 if auteur in self.overops:
406 if len(message)>1:
407 if message[1] in self.stay_channels:
408 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
409 self.stay_channels.remove(message[1])
410 serv.privmsg(auteur,"Stay channels : "+" ".join(self.stay_channels))
411 else:
412 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
413 serv.privmsg(auteur,"Je ne stay pas sur %s."%(message[1]))
414
415 else:
416 notunderstood=True
417 elif cmd=="die":
418 if auteur in self.overops:
419 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
420 self.mourir()
421 else:
422 notunderstood=True
423 elif cmd=="quiet":
424 if auteur in self.ops:
425 if len(message)>1:
426 if message[1] in self.quiet_channels:
427 serv.privmsg(auteur,"Je me la ferme déjà sur %s"%(message[1]))
428 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
429 else:
430 self.quiet_channels.append(message[1])
431 serv.privmsg(auteur,"Quiet channels : "+" ".join(self.quiet_channels))
432 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
433 else:
434 serv.privmsg(auteur,"Quiet channels : "+" ".join(self.quiet_channels))
435 else:
436 notunderstood=True
437 elif cmd=="noquiet":
438 if auteur in self.ops:
439 if len(message)>1:
440 if message[1] in self.quiet_channels:
441 self.quiet_channels.remove(message[1])
442 serv.privmsg(auteur,"Quiet channels : "+" ".join(self.quiet_channels))
443 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
444 else:
445 serv.privmsg(auteur,"Je ne me la ferme pas sur %s."%(message[1]))
446 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
447 else:
448 notunderstood=True
449 elif cmd=="say":
450 if auteur in self.overops and len(message)>2:
451 serv.privmsg(message[1]," ".join(message[2:]))
452 log(self.serveur,"priv",auteur," ".join(message))
453 elif len(message)<=2:
454 serv.privmsg(auteur,"Syntaxe : SAY <channel> <message>")
455 else:
456 notunderstood=True
457 elif cmd=="do":
458 if auteur in self.overops and len(message)>2:
459 serv.action(message[1]," ".join(message[2:]))
460 log(self.serveur,"priv",auteur," ".join(message))
461 elif len(message)<=2:
462 serv.privmsg(auteur,"Syntaxe : DO <channel> <action>")
463 else:
464 notunderstood=True
465 elif cmd=="kick":
466 if auteur in self.overops and len(message)>2:
467 serv.kick(message[1],message[2]," ".join(message[3:]))
468 log(self.serveur,"priv",auteur," ".join(message))
469 elif len(message)<=2:
470 serv.privmsg(auteur,"Syntaxe : KICK <channel> <pseudo> [<raison>]")
471 else:
472 notunderstood=True
473 elif cmd=="ops":
474 if auteur in self.overops:
475 serv.privmsg(auteur," ".join(self.ops))
476 else:
477 notunderstood=True
478 elif cmd=="overops":
479 if auteur in self.overops:
480 serv.privmsg(auteur," ".join(self.overops))
481 else:
482 notunderstood=True
483 else:
484 notunderstood=True
485 if notunderstood:
486 serv.privmsg(auteur,"Je n'ai pas compris. Essayez HELP…")
487
488 def on_pubmsg(self, serv, ev):
489 auteur = irclib.nm_to_n(ev.source())
490 canal = ev.target()
491 message = ev.arguments()[0]
492 try:
493 test=bot_unicode(message)
494 except UnicodeBotError:
495 if not canal in self.quiet_channels and config_utf8_trigger:
496 serv.privmsg(canal, "%s: %s"%(auteur,config_utf8_fail))
497 return
498 pour_moi,message=self.pourmoi(serv,message)
499 if pour_moi and message.split()!=[]:
500 cmd=message.split()[0].lower()
501 try:
502 args=" ".join(message.split()[1:])
503 except:
504 args=""
505 if cmd in ["meurs","die","crève"]:
506 if auteur in self.overops:
507 log(self.serveur,canal,auteur,message+"[successful]")
508 self.mourir()
509 else:
510 serv.privmsg(canal,"%s: %s"%(auteur,random.choice(config_quit_fail_messages)))
511 log(self.serveur,canal,auteur,message+"[failed]")
512
513 elif cmd in ["part","leave","dégage","va-t-en"]:
514 if auteur in self.ops and (not (canal in self.stay_channels)
515 or auteur in self.overops):
516 self.quitter(canal)
517 log(self.serveur,canal,auteur,message+"[successful]")
518 if canal in self.chanlist:
519 self.chanlist.remove(canal)
520 else:
521 serv.privmsg(canal,"%s: %s"%(auteur,random.choice(config_leave_fail_messages)))
522 log(self.serveur,canal,auteur,message+"[failed]")
523
524 elif cmd in ["deviens","pseudo"]:
525 if auteur in self.ops:
526 become=args
527 serv.nick(become)
528 log(self.serveur,canal,auteur,message+"[successful]")
529
530 if cmd in ["meur", "meurt","meurre","meurres"] and not canal in self.quiet_channels:
531 serv.privmsg(canal,'%s: Mourir, impératif, 2ème personne du singulier : "meurs" (de rien)'%(auteur))
532 elif cmd in ["ping"] and not canal in self.quiet_channels:
533 serv.privmsg(canal,"%s: pong"%(auteur))
534 # if is_insult(message) and not canal in self.quiet_channels:
535 # if is_not_insult(message):
536 # answer=random.choice(config_compliment_answers)
537 # for ligne in answer.split("\n"):
538 # serv.privmsg(canal,"%s: %s"%(auteur,ligne.encode("utf8")))
539 # else:
540 # answer=random.choice(config_insultes_answers)
541 # for ligne in answer.split("\n"):
542 # serv.privmsg(canal,"%s: %s"%(auteur,ligne.encode("utf8")))
543 # elif is_compliment(message) and not canal in self.quiet_channels:
544 # answer=random.choice(config_compliment_answers)
545 # for ligne in answer.split("\n"):
546 # serv.privmsg(canal,"%s: %s"%(auteur,ligne.encode("utf8")))
547 if is_tesla(message) and not canal in self.quiet_channels:
548 l1,l2=config_tesla_answers,config_tesla_actions
549 n1,n2=len(l1),len(l2)
550 i=random.randrange(n1+n2)
551 if i>=n1:
552 serv.action(canal,l2[i-n1].encode("utf8"))
553 else:
554 serv.privmsg(canal,"%s: %s"%(auteur,l1[i].encode("utf8")))
555 if is_tag(message) and not canal in self.quiet_channels:
556 if auteur in self.ops:
557 action=random.choice(config_tag_actions)
558 serv.action(canal,action.encode("utf8"))
559 self.quiet_channels.append(canal)
560 else:
561 answer=random.choice(config_tag_answers)
562 for ligne in answer.split("\n"):
563 serv.privmsg(canal,"%s: %s"%(auteur,ligne.encode("utf8")))
564 if is_bonjour(message) and not canal in self.quiet_channels:
565 if is_night():
566 answer=random.choice(config_night_answers)
567 elif is_day():
568 answer=random.choice(config_bonjour_answers)
569 else:
570 answer=random.choice(config_bonsoir_answers)
571 serv.privmsg(canal,answer.format(auteur).encode("utf8"))
572 if is_bonne_nuit(message) and not canal in self.quiet_channels:
573 answer=random.choice(config_bonne_nuit_answers)
574 serv.privmsg(canal,answer.format(auteur).encode("utf8"))
575 else:
576 if not canal in self.quiet_channels:
577 mypseudo=self.nick
578 if re.match((u"^("+u"|".join(config_bonjour_triggers)
579 +u")( {}| all| tout le monde|(|à) tous)(\.|( |)!|)$"
580 ).format(mypseudo).lower(), message.strip().lower()):
581 answer=random.choice(config_bonjour_answers)
582 serv.privmsg(canal,answer.format(auteur).encode("utf8"))
583
584 def on_action(self, serv, ev):
585 action = ev.arguments()[0]
586 auteur = irclib.nm_to_n(ev.source())
587 channel = ev.target()
588 try:
589 test=bot_unicode(action)
590 except UnicodeBotError:
591 if not channel in self.quiet_channels and config_utf8_trigger:
592 serv.privmsg(channel, "%s: %s"%(auteur,config_utf8_fail))
593 return
594 mypseudo=self.nick
595
596 # if is_bad_action_trigger(action,mypseudo) and not channel in self.quiet_channels:
597 # l1,l2=config_bad_action_answers,config_bad_action_actions
598 # n1,n2=len(l1),len(l2)
599 # i=random.randrange(n1+n2)
600 # if i>=n1:
601 # serv.action(channel,l2[i-n1].format(auteur).encode("utf8"))
602 # else:
603 # serv.privmsg(channel,l1[i].format(auteur).format(auteur).encode("utf8"))
604 # if is_good_action_trigger(action,mypseudo) and not channel in self.quiet_channels:
605 # l1,l2=config_good_action_answers,config_good_action_actions
606 # n1,n2=len(l1),len(l2)
607 # i=random.randrange(n1+n2)
608 # if i>=n1:
609 # serv.action(channel,l2[i-n1].format(auteur).format(auteur).encode("utf8"))
610 # else:
611 # serv.privmsg(channel,l1[i].format(auteur).format(auteur).encode("utf8"))
612
613 def on_kick(self,serv,ev):
614 auteur = irclib.nm_to_n(ev.source())
615 channel = ev.target()
616 victime = ev.arguments()[0]
617 raison = ev.arguments()[1]
618 if victime==self.nick:
619 log(self.serveur,"%s kické de %s par %s (raison : %s)" %(victime,channel,auteur,raison))
620 time.sleep(2)
621 serv.join(channel)
622 l1,l2=config_kick_answers,config_kick_actions
623 n1,n2=len(l1),len(l2)
624 i=random.randrange(n1+n2)
625 if i>=n1:
626 serv.action(channel,l2[i-n1].format(auteur).encode("utf8"))
627 else:
628 serv.privmsg(channel,l1[i].format(auteur).encode("utf8"))
629
630 def quitter(self,chan,leave_message=None):
631 if leave_message==None:
632 leave_message=random.choice(config_leave_messages)
633 self.serv.part(chan,message=leave_message.encode("utf8"))
634
635 def mourir(self):
636 quit_message=random.choice(config_quit_messages)
637 self.die(msg=quit_message.encode("utf8"))
638
639 def _getnick(self):
640 return self.serv.get_nickname()
641 nick=property(_getnick)
642
643
644 if __name__=="__main__":
645 import sys
646 if len(sys.argv)==1:
647 print "Usage : themis.py <serveur> [--debug]"
648 exit(1)
649 serveur=sys.argv[1]
650 if "debug" in sys.argv or "--debug" in sys.argv:
651 debug=True
652 else:
653 debug=False
654 serveurs={"a♡":"acoeur.crans.org","acoeur":"acoeur.crans.org","acoeur.crans.org":"acoeur.crans.org",
655 "irc":"irc.crans.org","crans":"irc.crans.org","irc.crans.org":"irc.crans.org"}
656 try:
657 serveur=serveurs[serveur]
658 except KeyError:
659 print "Server Unknown : %s"%(serveur)
660 exit(404)
661 themis=Themis(serveur,debug)
662 themis.start()