]> gitweb.pimeys.fr Git - bots/themis.git/blob - themis.py
1er jet de la config 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"Ton encodage me déprime…"]
38 config_utf8_trigger = True
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 ]
102 config_tesla_actions=[u"déprime",u"est prêt à kicker les gens heureux"]
103
104 # config en cas de non-insulte
105 config_compliment_triggers=[u"gentil",u"cool",u"sympa",u"efficace"]
106 config_compliment_answers=[
107 u"Merci, c'est gentil de votre part. :)",
108 u"Permettez-moi de vous retourner le compliment, sans ironie cette fois.",
109 u"Je vous remercie.",
110 u"C'est trop d'honneur.",
111 u"Vous êtes bien aimable."
112 ]
113
114 # config merci
115 config_merci_triggers=[u"merci",u"remercie",u"thx",u"thank(|s)"]
116 config_merci_answers=[u"Mais de rien.",u"À votre service. ;)",u"Quand vous voulez. :)",
117 u"Tout le plaisir est pour moi."]
118
119 # config "ta mère"
120 config_tamere_triggers=[u"ta mère"]
121 config_tamere_answers=[u"Laissez donc ma mère en dehors de ça !",
122 u"Puis-je préciser que je n'ai pas de mère ? Seulement deux pères…",
123 u"""Un certain Max chantait "♩ J'ai vu ta mère sur chat rouleeeeeeette ♫", vous êtes de sa famille ?""",
124 u"""N'avait-on pas dit "pas les mamans" ?"""]
125
126 # config pour les actions désagréables
127 config_bad_action_triggers=[u"(frappe|cogne|tape)(| sur)",u"(démolit|dégomme|fouette|agresse|tabasse)",
128 u"(vomit|pisse|chie|crache) sur",u"slap(|s)"]
129 config_bad_action_answers=[
130 u"Je ne peux pas dire que j'apprécie, mais je l'ai sans doute bien mérité.",
131 u"{}: Pourquoi tant de violence en ce monde si doux ?",
132 u"""Si je n'étais pas aussi prude, je dirais "Mais euh…", cependant, je me contenterai de hausser un sourcil.""",
133 u"{}: J'aurais préféré que vous ne fassiez pas cela en public.",
134 u"{}: Entre nous, cela vous gratifie-t-il ?",
135 u"{}: Une telle relation entre nous deux n'est pas saine, revenons à quelque chose de plus conventionnel. :D",
136 u"J'ai la désagréable impression que {} cherche comment tuer le temps en ce moment…"
137 ]
138 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à ?"]
139
140 # config pour les actions agréables
141 config_good_action_triggers=[u"fait (:?des bisous|un c(?:â|a)lin|des c(?:â|a)lins) à",u"embrasse",u"c(?:â|a)line",u"caresse"]
142 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…"]
143 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"]
144
145 # config bonjour/bonsoir/que fais-tu encore debout à cette heure, gros sale !
146 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"]
147 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"]
148 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é."]
149 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, {} ?"]
150 config_daytime = [7,18]
151 config_nighttime = [3, 6]
152
153 # config dodo
154 config_bonne_nuit_triggers=[u"bonne nuit",u"'?nite",u"'?nuit",u"'?night",u"good night",u"'?nenuit"]
155 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 !"]
156
157 # config quelqu'un est encore en train d'abuser de ses droits.
158 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 !"]
159 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."]
160
161 # config on m'a demandé de mourir/partir
162 config_quit_messages=[u"Bye."]
163 config_leave_messages=config_quit_messages
164 config_quit_fail_messages=[u"Tu rêves là."]
165 config_leave_fail_messages=config_quit_fail_messages
166
167
168 # config de kick
169 config_kick_channels=config_chanlist
170 config_smileys=[ur':(-|o)?\)',u'\^_?\^',u':-?(p|P)',u'=(\)D|p|P|)',ur'\o/']
171
172 def log(serveur,channel,auteur=None,message=None):
173 f=open(get_config_logfile(serveur),"a")
174 if auteur==message==None:
175 # alors c'est que c'est pas un channel mais juste une ligne de log
176 chain="%s %s"%(time.strftime("%F %T"),channel)
177 else:
178 chain="%s [%s:%s] %s"%(time.strftime("%F %T"),channel,auteur,message)
179 f.write(chain+"\n")
180 if config_debug_stdout:
181 print chain
182 f.close()
183
184 reg_is_smiley=re.compile(u".*("+u"|".join(config_smileys)+u")")
185 def is_smiley(chain):
186 chain=unicode(chain,"utf8")
187 o=re.match(reg_is_smiley,chain)
188 return o
189
190 def is_something(chain,matches,avant=u".*(?:^| )",apres=u"(?:$|\.| |,|;).*",case_sensitive=False,debug=False):
191 if case_sensitive:
192 chain=unicode(chain,"utf8")
193 else:
194 chain=unicode(chain,"utf8").lower()
195 allmatches="("+"|".join(matches)+")"
196 reg=(avant+allmatches+apres).lower()
197 o=re.match(reg,chain)
198 return o
199
200 def is_insult(chain,debug=True):
201 return is_something(chain,config_insultes,avant=".*(?:^| |')")
202 def is_not_insult(chain):
203 chain=unicode(chain,"utf8")
204 insult_regexp=u"("+u"|".join(config_insultes)+u")"
205 middle_regexp=u"(une? (?:(?:putain|enfoiré) d(?:e |'))*|)(?:| super )(?: (?:gros|petit|grand|énorme) |)"
206 reg=".*pas %s%s.*"%(middle_regexp,insult_regexp)
207 if re.match(reg,chain):
208 return True
209 else:
210 return False
211 def is_compliment(chain,debug=True):
212 return is_something(chain,config_compliment_triggers,avant=".*(?:^| |')")
213 def is_perdu(chain):
214 return is_something(chain,config_perdu)
215 def is_tag(chain):
216 return is_something(chain,config_tag_triggers)
217 def is_tesla(chain):
218 return is_something(chain,config_tesla_triggers,avant=u"^",apres=u"$",debug=True)
219 def is_merci(chain):
220 return is_something(chain,config_merci_triggers)
221 def is_tamere(chain):
222 return is_something(chain,config_tamere_triggers)
223 def is_bad_action_trigger(chain,pseudo):
224 return is_something(chain,config_bad_action_triggers,avant=u"^",
225 apres="(?: [a-z]*ment)? %s($|\.| |,|;).*"%(pseudo))
226 def is_good_action_trigger(chain,pseudo):
227 return is_something(chain,config_good_action_triggers,avant=u"^",
228 apres="(?: [a-z]*ment)? %s($|\.| |,|;).*"%(pseudo))
229 def is_bonjour(chain):
230 return is_something(chain,config_bonjour_triggers,avant=u"^")
231 def is_bonne_nuit(chain):
232 return is_something(chain,config_bonne_nuit_triggers,avant=u"^")
233 def is_pan(chain):
234 return re.match(u"^(pan|bim|bang)( .*)?$",unicode(chain,"utf8").lower().strip())
235
236 def is_time(conf):
237 _,_,_,h,m,s,_,_,_=time.localtime()
238 return (conf[0],0,0)<(h,m,s)<(conf[1],0,0)
239 def is_day():
240 return is_time(config_daytime)
241 def is_night():
242 return is_time(config_nighttime)
243
244
245 class UnicodeBotError(Exception):
246 pass
247 def bot_unicode(chain):
248 try:
249 unicode(chain,"utf8")
250 except UnicodeDecodeError as exc:
251 raise UnicodeBotError
252
253 class Themis(ircbot.SingleServerIRCBot):
254 def __init__(self,serveur,debug=False):
255 temporary_pseudo=config_irc_pseudo+str(random.randrange(10000,100000))
256 ircbot.SingleServerIRCBot.__init__(self, [(serveur, 6667)],
257 temporary_pseudo,"Des[bot]e de #déprime", 10)
258 self.debug=debug
259 self.serveur=serveur
260 self.overops=config_overops
261 self.ops=self.overops+config_ops
262 self.report_bugs_to=config_report_bugs_to
263 self.chanlist=config_chanlist
264 self.kick_channels=config_kick_channels
265 self.stay_channels=config_stay_channels
266 self.quiet_channels=config_quiet_channels
267 self.last_perdu=0
268
269
270 def give_me_my_pseudo(self,serv):
271 serv.privmsg("NickServ","RECOVER %s %s"%(config_irc_pseudo,config_irc_password))
272 serv.privmsg("NickServ","RELEASE %s %s"%(config_irc_pseudo,config_irc_password))
273 time.sleep(0.3)
274 serv.nick(config_irc_pseudo)
275
276 def give_me_my_op_status(self,serv,chan):
277 serv.privmsg("ChanServ","OP %s"%(chan))
278
279 def on_welcome(self, serv, ev):
280 self.serv=serv # ça serv ira
281 self.give_me_my_pseudo(serv)
282 serv.privmsg("NickServ","identify %s"%(config_irc_password))
283 log(self.serveur,"Connected")
284 if self.debug:
285 self.chanlist=["#bot"]
286 self.kick_channels=["#bot"]
287 for c in self.chanlist:
288 log(self.serveur,"JOIN %s"%(c))
289 serv.join(c)
290 self.give_me_my_op_status(serv,c)
291
292
293 def lost(self,serv,channel,forced=False):
294 if self.last_perdu+config_time_between_perdu<time.time() or forced:
295 if not channel in self.quiet_channels or forced:
296 serv.privmsg(channel,"J'ai perdu !")
297 self.last_perdu=time.time()
298 delay=config_time_between_perdu_trigger
299 delta=config_time_between_perdu_trigger_delta
300 serv.execute_delayed(random.randrange(delay-delta,delay+delta),self.lost,(serv,channel))
301
302 def pourmoi(self, serv, message):
303 """renvoie (False,lemessage) ou (True, le message amputé de "pseudo: ")"""
304 pseudo=self.nick
305 size=len(pseudo)
306 if message[:size]==pseudo and len(message)>size and message[size]==":":
307 return (True,message[size+1:].lstrip(" "))
308 else:
309 return (False,message)
310
311 def on_privmsg(self, serv, ev):
312 message=ev.arguments()[0]
313 auteur = irclib.nm_to_n(ev.source())
314 try:
315 test=bot_unicode(message)
316 except UnicodeBotError:
317 if config_utf8_trigger:
318 serv.privmsg(auteur, config_utf8_fail)
319 return
320 message=message.split()
321 cmd=message[0].lower()
322 notunderstood=False
323 if cmd=="help":
324 helpdico={"help":["""HELP <commande>
325 Affiche de l'aide sur la commande""",None,None],
326 "join": [None, """JOIN <channel>
327 Me fait rejoindre le channel""",None],
328 "leave": [None,"""LEAVE <channel>
329 Me fait quitter le channel (sauf s'il est dans ma stay_list).""",None],
330 "quiet": [None,"""QUIET <channel>
331 Me rend silencieux sur le channel.""",None],
332 "noquiet": [None,"""NOQUIET <channel>
333 Me rend la parole sur le channel.""",None],
334 "say": [None,None,"""SAY <channel> <message>
335 Me fait parler sur le channel."""],
336 "do": [None,None,"""DO <channel> <action>
337 Me fait faitre une action (/me) sur le channel."""],
338 "stay": [None,None,"""STAY <channel>
339 Ajoute le channel à ma stay_list."""],
340 "nostay": [None,None,"""NOSTAY <channel>
341 Retire le channel de ma stay_list."""],
342 "ops": [None,None,"""OPS
343 Affiche la liste des ops."""],
344 "overops": [None,None,"""OVEROPS
345 Affiche la liste des overops."""],
346 "kick": [None,None,"""KICK <channel> <pseudo> [<raison>]
347 Kicke <pseudo> du channel (Il faut bien entendu que j'y sois op)."""],
348 "die": [None,None,"""DIE
349 Me déconnecte du serveur IRC."""]
350 }
351 helpmsg_default="Liste des commandes disponibles :\nHELP"
352 helpmsg_ops=" JOIN LEAVE QUIET NOQUIET LOST"
353 helpmsg_overops=" SAY DO STAY NOSTAY OPS OVEROPS KICK DIE"
354 op,overop=auteur in self.ops, auteur in self.overops
355 if len(message)==1:
356 helpmsg=helpmsg_default
357 if op:
358 helpmsg+=helpmsg_ops
359 if overop:
360 helpmsg+=helpmsg_overops
361 else:
362 helpmsgs=helpdico.get(message[1].lower(),["Commande inconnue.",None,None])
363 helpmsg=helpmsgs[0]
364 if op and helpmsgs[1]:
365 if helpmsg:
366 helpmsg+="\n"+helpmsgs[1]
367 else:
368 helpmsg=helpmsgs[1]
369 if overop and helpmsgs[2]:
370 if helpmsg:
371 helpmsg+="\n"+helpmsgs[2]
372 else:
373 helpmsg=helpmsgs[2]
374 for ligne in helpmsg.split("\n"):
375 serv.privmsg(auteur,ligne)
376 elif cmd=="join":
377 if auteur in self.ops:
378 if len(message)>1:
379 if message[1] in self.chanlist:
380 serv.privmsg(auteur,"Je suis déjà sur %s"%(message[1]))
381 else:
382 serv.join(message[1])
383 self.chanlist.append(message[1])
384 serv.privmsg(auteur,"Channels : "+" ".join(self.chanlist))
385 log(self.serveur,"priv",auteur," ".join(message))
386 else:
387 serv.privmsg(auteur,"Channels : "+" ".join(self.chanlist))
388 else:
389 notunderstood=True
390 elif cmd=="leave":
391 if auteur in self.ops and len(message)>1:
392 if message[1] in self.chanlist:
393 if not (message[1] in self.stay_channels) or auteur in self.overops:
394 self.quitter(message[1]," ".join(message[2:]))
395 self.chanlist.remove(message[1])
396 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
397 else:
398 serv.privmsg(auteur,random.choice(config_leave_fail_messages))
399 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
400 else:
401 serv.privmsg(auteur,"Je ne suis pas sur %s"%(message[1]))
402 else:
403 notunderstood=True
404 elif cmd=="stay":
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)+"[failed]")
409 serv.privmsg(auteur,"Je stay déjà sur %s."%(message[1]))
410 else:
411 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
412 self.stay_channels.append(message[1])
413 serv.privmsg(auteur,"Stay channels : "+" ".join(self.stay_channels))
414 else:
415 serv.privmsg(auteur,"Stay channels : "+" ".join(self.stay_channels))
416 else:
417 notunderstood=True
418 elif cmd=="nostay":
419 if auteur in self.overops:
420 if len(message)>1:
421 if message[1] in self.stay_channels:
422 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
423 self.stay_channels.remove(message[1])
424 serv.privmsg(auteur,"Stay channels : "+" ".join(self.stay_channels))
425 else:
426 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
427 serv.privmsg(auteur,"Je ne stay pas sur %s."%(message[1]))
428
429 else:
430 notunderstood=True
431 elif cmd=="die":
432 if auteur in self.overops:
433 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
434 self.mourir()
435 else:
436 notunderstood=True
437 elif cmd=="quiet":
438 if auteur in self.ops:
439 if len(message)>1:
440 if message[1] in self.quiet_channels:
441 serv.privmsg(auteur,"Je me la ferme déjà sur %s"%(message[1]))
442 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
443 else:
444 self.quiet_channels.append(message[1])
445 serv.privmsg(auteur,"Quiet channels : "+" ".join(self.quiet_channels))
446 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
447 else:
448 serv.privmsg(auteur,"Quiet channels : "+" ".join(self.quiet_channels))
449 else:
450 notunderstood=True
451 elif cmd=="noquiet":
452 if auteur in self.ops:
453 if len(message)>1:
454 if message[1] in self.quiet_channels:
455 self.quiet_channels.remove(message[1])
456 serv.privmsg(auteur,"Quiet channels : "+" ".join(self.quiet_channels))
457 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
458 else:
459 serv.privmsg(auteur,"Je ne me la ferme pas sur %s."%(message[1]))
460 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
461 else:
462 notunderstood=True
463 elif cmd=="say":
464 if auteur in self.overops and len(message)>2:
465 serv.privmsg(message[1]," ".join(message[2:]))
466 log(self.serveur,"priv",auteur," ".join(message))
467 elif len(message)<=2:
468 serv.privmsg(auteur,"Syntaxe : SAY <channel> <message>")
469 else:
470 notunderstood=True
471 elif cmd=="do":
472 if auteur in self.overops and len(message)>2:
473 serv.action(message[1]," ".join(message[2:]))
474 log(self.serveur,"priv",auteur," ".join(message))
475 elif len(message)<=2:
476 serv.privmsg(auteur,"Syntaxe : DO <channel> <action>")
477 else:
478 notunderstood=True
479 elif cmd=="kick":
480 if auteur in self.overops and len(message)>2:
481 serv.kick(message[1],message[2]," ".join(message[3:]))
482 log(self.serveur,"priv",auteur," ".join(message))
483 elif len(message)<=2:
484 serv.privmsg(auteur,"Syntaxe : KICK <channel> <pseudo> [<raison>]")
485 else:
486 notunderstood=True
487 elif cmd=="ops":
488 if auteur in self.overops:
489 serv.privmsg(auteur," ".join(self.ops))
490 else:
491 notunderstood=True
492 elif cmd=="overops":
493 if auteur in self.overops:
494 serv.privmsg(auteur," ".join(self.overops))
495 else:
496 notunderstood=True
497 else:
498 notunderstood=True
499 if notunderstood:
500 serv.privmsg(auteur,"Je n'ai pas compris. Essayez HELP…")
501
502 def on_pubmsg(self, serv, ev):
503 auteur = irclib.nm_to_n(ev.source())
504 canal = ev.target()
505 message = ev.arguments()[0]
506 try:
507 test=bot_unicode(message)
508 except UnicodeBotError:
509 if not canal in self.quiet_channels and config_utf8_trigger:
510 serv.privmsg(canal, "%s: %s"%(auteur,config_utf8_fail))
511 return
512 pour_moi,message=self.pourmoi(serv,message)
513 smy=is_smiley(message)
514 if smy:
515 if canal in self.kick_channels:
516 serv.kick(canal,auteur,(u'"%s" ? Ici on déprime !'%(smy.groups()[0])).encode("utf8"))
517 return
518 if pour_moi and message.split()!=[]:
519 cmd=message.split()[0].lower()
520 try:
521 args=" ".join(message.split()[1:])
522 except:
523 args=""
524 if cmd in ["meurs","die","crève"]:
525 if auteur in self.overops:
526 log(self.serveur,canal,auteur,message+"[successful]")
527 self.mourir()
528 else:
529 serv.privmsg(canal,"%s: %s"%(auteur,random.choice(config_quit_fail_messages)))
530 log(self.serveur,canal,auteur,message+"[failed]")
531
532 elif cmd in ["part","leave","dégage","va-t-en"]:
533 if auteur in self.ops and (not (canal in self.stay_channels)
534 or auteur in self.overops):
535 self.quitter(canal)
536 log(self.serveur,canal,auteur,message+"[successful]")
537 if canal in self.chanlist:
538 self.chanlist.remove(canal)
539 else:
540 serv.privmsg(canal,"%s: %s"%(auteur,random.choice(config_leave_fail_messages)))
541 log(self.serveur,canal,auteur,message+"[failed]")
542
543 elif cmd in ["deviens","pseudo"]:
544 if auteur in self.ops:
545 become=args
546 serv.nick(become)
547 log(self.serveur,canal,auteur,message+"[successful]")
548
549 if cmd in ["meur", "meurt","meurre","meurres"] and not canal in self.quiet_channels:
550 serv.privmsg(canal,'%s: Mourir, impératif, 2ème personne du singulier : "meurs" (de rien)'%(auteur))
551 elif cmd in ["ping"] and not canal in self.quiet_channels:
552 serv.privmsg(canal,"%s: pong"%(auteur))
553 # if is_insult(message) and not canal in self.quiet_channels:
554 # if is_not_insult(message):
555 # answer=random.choice(config_compliment_answers)
556 # for ligne in answer.split("\n"):
557 # serv.privmsg(canal,"%s: %s"%(auteur,ligne.encode("utf8")))
558 # else:
559 # answer=random.choice(config_insultes_answers)
560 # for ligne in answer.split("\n"):
561 # serv.privmsg(canal,"%s: %s"%(auteur,ligne.encode("utf8")))
562 # elif is_compliment(message) and not canal in self.quiet_channels:
563 # answer=random.choice(config_compliment_answers)
564 # for ligne in answer.split("\n"):
565 # serv.privmsg(canal,"%s: %s"%(auteur,ligne.encode("utf8")))
566 if is_tesla(message) and not canal in self.quiet_channels:
567 l1,l2=config_tesla_answers,config_tesla_actions
568 n1,n2=len(l1),len(l2)
569 i=random.randrange(n1+n2)
570 if i>=n1:
571 serv.action(canal,l2[i-n1].encode("utf8"))
572 else:
573 serv.privmsg(canal,"%s: %s"%(auteur,l1[i].encode("utf8")))
574 if is_tag(message) and not canal in self.quiet_channels:
575 if auteur in self.ops:
576 action=random.choice(config_tag_actions)
577 serv.action(canal,action.encode("utf8"))
578 self.quiet_channels.append(canal)
579 else:
580 answer=random.choice(config_tag_answers)
581 for ligne in answer.split("\n"):
582 serv.privmsg(canal,"%s: %s"%(auteur,ligne.encode("utf8")))
583 if is_bonjour(message) and not canal in self.quiet_channels:
584 if is_night():
585 answer=random.choice(config_night_answers)
586 elif is_day():
587 answer=random.choice(config_bonjour_answers)
588 else:
589 answer=random.choice(config_bonsoir_answers)
590 serv.privmsg(canal,answer.format(auteur).encode("utf8"))
591 if is_bonne_nuit(message) and not canal in self.quiet_channels:
592 answer=random.choice(config_bonne_nuit_answers)
593 serv.privmsg(canal,answer.format(auteur).encode("utf8"))
594 else:
595 if not canal in self.quiet_channels:
596 mypseudo=self.nick
597 if re.match((u"^("+u"|".join(config_bonjour_triggers)
598 +u")( {}| all| tout le monde|(|à) tous)(\.|( |)!|)$"
599 ).format(mypseudo).lower(), message.strip().lower()):
600 answer=random.choice(config_bonjour_answers)
601 serv.privmsg(canal,answer.format(auteur).encode("utf8"))
602
603 def on_action(self, serv, ev):
604 action = ev.arguments()[0]
605 auteur = irclib.nm_to_n(ev.source())
606 channel = ev.target()
607 try:
608 test=bot_unicode(action)
609 except UnicodeBotError:
610 if not channel in self.quiet_channels and config_utf8_trigger:
611 serv.privmsg(channel, "%s: %s"%(auteur,config_utf8_fail))
612 return
613 mypseudo=self.nick
614
615 # if is_bad_action_trigger(action,mypseudo) and not channel in self.quiet_channels:
616 # l1,l2=config_bad_action_answers,config_bad_action_actions
617 # n1,n2=len(l1),len(l2)
618 # i=random.randrange(n1+n2)
619 # if i>=n1:
620 # serv.action(channel,l2[i-n1].format(auteur).encode("utf8"))
621 # else:
622 # serv.privmsg(channel,l1[i].format(auteur).format(auteur).encode("utf8"))
623 # if is_good_action_trigger(action,mypseudo) and not channel in self.quiet_channels:
624 # l1,l2=config_good_action_answers,config_good_action_actions
625 # n1,n2=len(l1),len(l2)
626 # i=random.randrange(n1+n2)
627 # if i>=n1:
628 # serv.action(channel,l2[i-n1].format(auteur).format(auteur).encode("utf8"))
629 # else:
630 # serv.privmsg(channel,l1[i].format(auteur).format(auteur).encode("utf8"))
631
632 def on_kick(self,serv,ev):
633 auteur = irclib.nm_to_n(ev.source())
634 channel = ev.target()
635 victime = ev.arguments()[0]
636 raison = ev.arguments()[1]
637 if victime==self.nick:
638 log(self.serveur,"%s kické de %s par %s (raison : %s)" %(victime,channel,auteur,raison))
639 time.sleep(2)
640 serv.join(channel)
641
642 def kicker(self, chan, pseudo, raison=None):
643 if raison==None:
644 raison = config_kick_default_reason
645 self.serv.kick(chan,pseudo,raison)
646
647 def quitter(self,chan,leave_message=None):
648 if leave_message==None:
649 leave_message=random.choice(config_leave_messages)
650 self.serv.part(chan,message=leave_message.encode("utf8"))
651
652 def mourir(self):
653 quit_message=random.choice(config_quit_messages)
654 self.die(msg=quit_message.encode("utf8"))
655
656 def _getnick(self):
657 return self.serv.get_nickname()
658 nick=property(_getnick)
659
660
661 if __name__=="__main__":
662 import sys
663 if len(sys.argv)==1:
664 print "Usage : themis.py <serveur> [--debug]"
665 exit(1)
666 serveur=sys.argv[1]
667 if "debug" in sys.argv or "--debug" in sys.argv:
668 debug=True
669 else:
670 debug=False
671 serveurs={"a♡":"acoeur.crans.org","acoeur":"acoeur.crans.org","acoeur.crans.org":"acoeur.crans.org",
672 "irc":"irc.crans.org","crans":"irc.crans.org","irc.crans.org":"irc.crans.org"}
673 try:
674 serveur=serveurs[serveur]
675 except KeyError:
676 print "Server Unknown : %s"%(serveur)
677 exit(404)
678 themis=Themis(serveur,debug)
679 themis.start()