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