]> gitweb.pimeys.fr Git - bots/themis.git/blob - themis.py
Config de Themis, v1.1
[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"Bye."]
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 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|\(|\[)(:|=)']
170
171 def log(serveur,channel,auteur=None,message=None):
172 f=open(get_config_logfile(serveur),"a")
173 if auteur==message==None:
174 # alors c'est que c'est pas un channel mais juste une ligne de log
175 chain="%s %s"%(time.strftime("%F %T"),channel)
176 else:
177 chain="%s [%s:%s] %s"%(time.strftime("%F %T"),channel,auteur,message)
178 f.write(chain+"\n")
179 if config_debug_stdout:
180 print chain
181 f.close()
182
183 reg_is_smiley=re.compile(u".*("+u"|".join(config_smileys)+u")")
184 def is_smiley(chain):
185 chain=unicode(chain,"utf8")
186 o=re.match(reg_is_smiley,chain)
187 return o
188 def is_something(chain,matches,avant=u".*(?:^| )",apres=u"(?:$|\.| |,|;).*",case_sensitive=False,debug=False):
189 if case_sensitive:
190 chain=unicode(chain,"utf8")
191 else:
192 chain=unicode(chain,"utf8").lower()
193 allmatches="("+"|".join(matches)+")"
194 reg=(avant+allmatches+apres).lower()
195 o=re.match(reg,chain)
196 return o
197
198 def is_insult(chain,debug=True):
199 return is_something(chain,config_insultes,avant=".*(?:^| |')")
200 def is_not_insult(chain):
201 chain=unicode(chain,"utf8")
202 insult_regexp=u"("+u"|".join(config_insultes)+u")"
203 middle_regexp=u"(une? (?:(?:putain|enfoiré) d(?:e |'))*|)(?:| super )(?: (?:gros|petit|grand|énorme) |)"
204 reg=".*pas %s%s.*"%(middle_regexp,insult_regexp)
205 if re.match(reg,chain):
206 return True
207 else:
208 return False
209 def is_compliment(chain,debug=True):
210 return is_something(chain,config_compliment_triggers,avant=".*(?:^| |')")
211 def is_perdu(chain):
212 return is_something(chain,config_perdu)
213 def is_tag(chain):
214 return is_something(chain,config_tag_triggers)
215 def is_tesla(chain):
216 return is_something(chain,config_tesla_triggers,avant=u"^",apres=u"$",debug=True)
217 def is_merci(chain):
218 return is_something(chain,config_merci_triggers)
219 def is_tamere(chain):
220 return is_something(chain,config_tamere_triggers)
221 def is_bad_action_trigger(chain,pseudo):
222 return is_something(chain,config_bad_action_triggers,avant=u"^",
223 apres="(?: [a-z]*ment)? %s($|\.| |,|;).*"%(pseudo))
224 def is_good_action_trigger(chain,pseudo):
225 return is_something(chain,config_good_action_triggers,avant=u"^",
226 apres="(?: [a-z]*ment)? %s($|\.| |,|;).*"%(pseudo))
227 def is_bonjour(chain):
228 return is_something(chain,config_bonjour_triggers,avant=u"^")
229 def is_bonne_nuit(chain):
230 return is_something(chain,config_bonne_nuit_triggers,avant=u"^")
231 def is_pan(chain):
232 return re.match(u"^(pan|bim|bang)( .*)?$",unicode(chain,"utf8").lower().strip())
233
234 def is_time(conf):
235 _,_,_,h,m,s,_,_,_=time.localtime()
236 return (conf[0],0,0)<(h,m,s)<(conf[1],0,0)
237 def is_day():
238 return is_time(config_daytime)
239 def is_night():
240 return is_time(config_nighttime)
241
242
243 class UnicodeBotError(Exception):
244 pass
245 def bot_unicode(chain):
246 try:
247 unicode(chain,"utf8")
248 except UnicodeDecodeError as exc:
249 raise UnicodeBotError
250
251 class Themis(ircbot.SingleServerIRCBot):
252 def __init__(self,serveur,debug=False):
253 temporary_pseudo=config_irc_pseudo+str(random.randrange(10000,100000))
254 ircbot.SingleServerIRCBot.__init__(self, [(serveur, 6667)],
255 temporary_pseudo,"Des[bot]e de #déprime", 10)
256 self.debug=debug
257 self.serveur=serveur
258 self.overops=config_overops
259 self.ops=self.overops+config_ops
260 self.report_bugs_to=config_report_bugs_to
261 self.chanlist=config_chanlist
262 self.kick_channels=config_kick_channels
263 self.stay_channels=config_stay_channels
264 self.quiet_channels=config_quiet_channels
265 self.last_perdu=0
266
267
268 def give_me_my_pseudo(self,serv):
269 serv.privmsg("NickServ","RECOVER %s %s"%(config_irc_pseudo,config_irc_password))
270 serv.privmsg("NickServ","RELEASE %s %s"%(config_irc_pseudo,config_irc_password))
271 time.sleep(0.3)
272 serv.nick(config_irc_pseudo)
273
274 def give_me_my_op_status(self,serv,chan):
275 serv.privmsg("ChanServ","OP %s"%(chan))
276
277 def on_welcome(self, serv, ev):
278 self.serv=serv # ça serv ira
279 self.give_me_my_pseudo(serv)
280 serv.privmsg("NickServ","identify %s"%(config_irc_password))
281 log(self.serveur,"Connected")
282 if self.debug:
283 self.chanlist=["#bot"]
284 self.kick_channels=["#bot"]
285 for c in self.chanlist:
286 log(self.serveur,"JOIN %s"%(c))
287 serv.join(c)
288 self.give_me_my_op_status(serv,c)
289
290
291 def lost(self,serv,channel,forced=False):
292 if self.last_perdu+config_time_between_perdu<time.time() or forced:
293 if not channel in self.quiet_channels or forced:
294 serv.privmsg(channel,"J'ai perdu !")
295 self.last_perdu=time.time()
296 delay=config_time_between_perdu_trigger
297 delta=config_time_between_perdu_trigger_delta
298 serv.execute_delayed(random.randrange(delay-delta,delay+delta),self.lost,(serv,channel))
299
300 def pourmoi(self, serv, message):
301 """renvoie (False,lemessage) ou (True, le message amputé de "pseudo: ")"""
302 pseudo=self.nick
303 size=len(pseudo)
304 if message[:size]==pseudo and len(message)>size and message[size]==":":
305 return (True,message[size+1:].lstrip(" "))
306 else:
307 return (False,message)
308
309 def on_privmsg(self, serv, ev):
310 message=ev.arguments()[0]
311 auteur = irclib.nm_to_n(ev.source())
312 try:
313 test=bot_unicode(message)
314 except UnicodeBotError:
315 if config_utf8_trigger:
316 serv.privmsg(auteur, config_utf8_fail)
317 return
318 message=message.split()
319 cmd=message[0].lower()
320 notunderstood=False
321 if cmd=="help":
322 helpdico={"help":["""HELP <commande>
323 Affiche de l'aide sur la commande""",None,None],
324 "join": [None, """JOIN <channel>
325 Me fait rejoindre le channel""",None],
326 "leave": [None,"""LEAVE <channel>
327 Me fait quitter le channel (sauf s'il est dans ma stay_list).""",None],
328 "quiet": [None,"""QUIET <channel>
329 Me rend silencieux sur le channel.""",None],
330 "noquiet": [None,"""NOQUIET <channel>
331 Me rend la parole sur le channel.""",None],
332 "say": [None,None,"""SAY <channel> <message>
333 Me fait parler sur le channel."""],
334 "do": [None,None,"""DO <channel> <action>
335 Me fait faitre une action (/me) sur le channel."""],
336 "stay": [None,None,"""STAY <channel>
337 Ajoute le channel à ma stay_list."""],
338 "nostay": [None,None,"""NOSTAY <channel>
339 Retire le channel de ma stay_list."""],
340 "ops": [None,None,"""OPS
341 Affiche la liste des ops."""],
342 "overops": [None,None,"""OVEROPS
343 Affiche la liste des overops."""],
344 "kick": [None,None,"""KICK <channel> <pseudo> [<raison>]
345 Kicke <pseudo> du channel (Il faut bien entendu que j'y sois op)."""],
346 "die": [None,None,"""DIE
347 Me déconnecte du serveur IRC."""]
348 }
349 helpmsg_default="Liste des commandes disponibles :\nHELP"
350 helpmsg_ops=" JOIN LEAVE QUIET NOQUIET LOST"
351 helpmsg_overops=" SAY DO STAY NOSTAY OPS OVEROPS KICK DIE"
352 op,overop=auteur in self.ops, auteur in self.overops
353 if len(message)==1:
354 helpmsg=helpmsg_default
355 if op:
356 helpmsg+=helpmsg_ops
357 if overop:
358 helpmsg+=helpmsg_overops
359 else:
360 helpmsgs=helpdico.get(message[1].lower(),["Commande inconnue.",None,None])
361 helpmsg=helpmsgs[0]
362 if op and helpmsgs[1]:
363 if helpmsg:
364 helpmsg+="\n"+helpmsgs[1]
365 else:
366 helpmsg=helpmsgs[1]
367 if overop and helpmsgs[2]:
368 if helpmsg:
369 helpmsg+="\n"+helpmsgs[2]
370 else:
371 helpmsg=helpmsgs[2]
372 for ligne in helpmsg.split("\n"):
373 serv.privmsg(auteur,ligne)
374 elif cmd=="join":
375 if auteur in self.ops:
376 if len(message)>1:
377 if message[1] in self.chanlist:
378 serv.privmsg(auteur,"Je suis déjà sur %s"%(message[1]))
379 else:
380 serv.join(message[1])
381 self.chanlist.append(message[1])
382 serv.privmsg(auteur,"Channels : "+" ".join(self.chanlist))
383 log(self.serveur,"priv",auteur," ".join(message))
384 else:
385 serv.privmsg(auteur,"Channels : "+" ".join(self.chanlist))
386 else:
387 notunderstood=True
388 elif cmd=="leave":
389 if auteur in self.ops and len(message)>1:
390 if message[1] in self.chanlist:
391 if not (message[1] in self.stay_channels) or auteur in self.overops:
392 self.quitter(message[1]," ".join(message[2:]))
393 self.chanlist.remove(message[1])
394 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
395 else:
396 serv.privmsg(auteur,random.choice(config_leave_fail_messages))
397 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
398 else:
399 serv.privmsg(auteur,"Je ne suis pas sur %s"%(message[1]))
400 else:
401 notunderstood=True
402 elif cmd=="stay":
403 if auteur in self.overops:
404 if len(message)>1:
405 if message[1] in self.stay_channels:
406 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
407 serv.privmsg(auteur,"Je stay déjà sur %s."%(message[1]))
408 else:
409 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
410 self.stay_channels.append(message[1])
411 serv.privmsg(auteur,"Stay channels : "+" ".join(self.stay_channels))
412 else:
413 serv.privmsg(auteur,"Stay channels : "+" ".join(self.stay_channels))
414 else:
415 notunderstood=True
416 elif cmd=="nostay":
417 if auteur in self.overops:
418 if len(message)>1:
419 if message[1] in self.stay_channels:
420 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
421 self.stay_channels.remove(message[1])
422 serv.privmsg(auteur,"Stay channels : "+" ".join(self.stay_channels))
423 else:
424 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
425 serv.privmsg(auteur,"Je ne stay pas sur %s."%(message[1]))
426
427 else:
428 notunderstood=True
429 elif cmd=="die":
430 if auteur in self.overops:
431 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
432 self.mourir()
433 else:
434 notunderstood=True
435 elif cmd=="quiet":
436 if auteur in self.ops:
437 if len(message)>1:
438 if message[1] in self.quiet_channels:
439 serv.privmsg(auteur,"Je me la ferme déjà sur %s"%(message[1]))
440 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
441 else:
442 self.quiet_channels.append(message[1])
443 serv.privmsg(auteur,"Quiet channels : "+" ".join(self.quiet_channels))
444 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
445 else:
446 serv.privmsg(auteur,"Quiet channels : "+" ".join(self.quiet_channels))
447 else:
448 notunderstood=True
449 elif cmd=="noquiet":
450 if auteur in self.ops:
451 if len(message)>1:
452 if message[1] in self.quiet_channels:
453 self.quiet_channels.remove(message[1])
454 serv.privmsg(auteur,"Quiet channels : "+" ".join(self.quiet_channels))
455 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
456 else:
457 serv.privmsg(auteur,"Je ne me la ferme pas sur %s."%(message[1]))
458 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
459 else:
460 notunderstood=True
461 elif cmd=="say":
462 if auteur in self.overops and len(message)>2:
463 serv.privmsg(message[1]," ".join(message[2:]))
464 log(self.serveur,"priv",auteur," ".join(message))
465 elif len(message)<=2:
466 serv.privmsg(auteur,"Syntaxe : SAY <channel> <message>")
467 else:
468 notunderstood=True
469 elif cmd=="do":
470 if auteur in self.overops and len(message)>2:
471 serv.action(message[1]," ".join(message[2:]))
472 log(self.serveur,"priv",auteur," ".join(message))
473 elif len(message)<=2:
474 serv.privmsg(auteur,"Syntaxe : DO <channel> <action>")
475 else:
476 notunderstood=True
477 elif cmd=="kick":
478 if auteur in self.overops and len(message)>2:
479 serv.kick(message[1],message[2]," ".join(message[3:]))
480 log(self.serveur,"priv",auteur," ".join(message))
481 elif len(message)<=2:
482 serv.privmsg(auteur,"Syntaxe : KICK <channel> <pseudo> [<raison>]")
483 else:
484 notunderstood=True
485 elif cmd=="ops":
486 if auteur in self.overops:
487 serv.privmsg(auteur," ".join(self.ops))
488 else:
489 notunderstood=True
490 elif cmd=="overops":
491 if auteur in self.overops:
492 serv.privmsg(auteur," ".join(self.overops))
493 else:
494 notunderstood=True
495 else:
496 notunderstood=True
497 if notunderstood:
498 serv.privmsg(auteur,"Je n'ai pas compris. Essayez HELP…")
499
500 def on_pubmsg(self, serv, ev):
501 auteur = irclib.nm_to_n(ev.source())
502 canal = ev.target()
503 message = ev.arguments()[0]
504 try:
505 test=bot_unicode(message)
506 except UnicodeBotError:
507 if not canal in self.quiet_channels and config_utf8_trigger:
508 serv.privmsg(canal, "%s: %s"%(auteur,config_utf8_fail))
509 return
510 pour_moi,message=self.pourmoi(serv,message)
511 smy=is_smiley(message)
512 if smy:
513 if canal in self.kick_channels:
514 serv.kick(canal,auteur,(u'"%s" ? Ici on déprime.'%(smy.groups()[0])).encode("utf8"))
515 return
516 if pour_moi and message.split()!=[]:
517 cmd=message.split()[0].lower()
518 try:
519 args=" ".join(message.split()[1:])
520 except:
521 args=""
522 if cmd in ["meurs","die","crève"]:
523 if auteur in self.overops:
524 log(self.serveur,canal,auteur,message+"[successful]")
525 self.mourir()
526 else:
527 serv.privmsg(canal,"%s: %s"%(auteur,random.choice(config_quit_fail_messages)))
528 log(self.serveur,canal,auteur,message+"[failed]")
529
530 elif cmd in ["part","leave","dégage","va-t-en"]:
531 if auteur in self.ops and (not (canal in self.stay_channels)
532 or auteur in self.overops):
533 self.quitter(canal)
534 log(self.serveur,canal,auteur,message+"[successful]")
535 if canal in self.chanlist:
536 self.chanlist.remove(canal)
537 else:
538 serv.privmsg(canal,"%s: %s"%(auteur,random.choice(config_leave_fail_messages)))
539 log(self.serveur,canal,auteur,message+"[failed]")
540
541 elif cmd in ["deviens","pseudo"]:
542 if auteur in self.ops:
543 become=args
544 serv.nick(become)
545 log(self.serveur,canal,auteur,message+"[successful]")
546
547 if cmd in ["meur", "meurt","meurre","meurres"] and not canal in self.quiet_channels:
548 serv.privmsg(canal,'%s: Mourir, impératif, 2ème personne du singulier : "meurs" (de rien)'%(auteur))
549 elif cmd in ["ping"] and not canal in self.quiet_channels:
550 serv.privmsg(canal,"%s: pong"%(auteur))
551 # if is_insult(message) and not canal in self.quiet_channels:
552 # if is_not_insult(message):
553 # answer=random.choice(config_compliment_answers)
554 # for ligne in answer.split("\n"):
555 # serv.privmsg(canal,"%s: %s"%(auteur,ligne.encode("utf8")))
556 # else:
557 # answer=random.choice(config_insultes_answers)
558 # for ligne in answer.split("\n"):
559 # serv.privmsg(canal,"%s: %s"%(auteur,ligne.encode("utf8")))
560 # elif is_compliment(message) and not canal in self.quiet_channels:
561 # answer=random.choice(config_compliment_answers)
562 # for ligne in answer.split("\n"):
563 # serv.privmsg(canal,"%s: %s"%(auteur,ligne.encode("utf8")))
564 if is_tesla(message) and not canal in self.quiet_channels:
565 l1,l2=config_tesla_answers,config_tesla_actions
566 n1,n2=len(l1),len(l2)
567 i=random.randrange(n1+n2)
568 if i>=n1:
569 serv.action(canal,l2[i-n1].encode("utf8"))
570 else:
571 serv.privmsg(canal,"%s: %s"%(auteur,l1[i].encode("utf8")))
572 if is_tag(message) and not canal in self.quiet_channels:
573 if auteur in self.ops:
574 action=random.choice(config_tag_actions)
575 serv.action(canal,action.encode("utf8"))
576 self.quiet_channels.append(canal)
577 else:
578 answer=random.choice(config_tag_answers)
579 for ligne in answer.split("\n"):
580 serv.privmsg(canal,"%s: %s"%(auteur,ligne.encode("utf8")))
581 if is_bonjour(message) and not canal in self.quiet_channels:
582 if is_night():
583 answer=random.choice(config_night_answers)
584 elif is_day():
585 answer=random.choice(config_bonjour_answers)
586 else:
587 answer=random.choice(config_bonsoir_answers)
588 serv.privmsg(canal,answer.format(auteur).encode("utf8"))
589 if is_bonne_nuit(message) and not canal in self.quiet_channels:
590 answer=random.choice(config_bonne_nuit_answers)
591 serv.privmsg(canal,answer.format(auteur).encode("utf8"))
592 else:
593 if not canal in self.quiet_channels:
594 mypseudo=self.nick
595 if re.match((u"^("+u"|".join(config_bonjour_triggers)
596 +u")( {}| all| tout le monde|(|à) tous)(\.|( |)!|)$"
597 ).format(mypseudo).lower(), message.strip().lower()):
598 answer=random.choice(config_bonjour_answers)
599 serv.privmsg(canal,answer.format(auteur).encode("utf8"))
600
601 def on_action(self, serv, ev):
602 action = ev.arguments()[0]
603 auteur = irclib.nm_to_n(ev.source())
604 channel = ev.target()
605 try:
606 test=bot_unicode(action)
607 except UnicodeBotError:
608 if not channel in self.quiet_channels and config_utf8_trigger:
609 serv.privmsg(channel, "%s: %s"%(auteur,config_utf8_fail))
610 return
611 mypseudo=self.nick
612
613 # if is_bad_action_trigger(action,mypseudo) and not channel in self.quiet_channels:
614 # l1,l2=config_bad_action_answers,config_bad_action_actions
615 # n1,n2=len(l1),len(l2)
616 # i=random.randrange(n1+n2)
617 # if i>=n1:
618 # serv.action(channel,l2[i-n1].format(auteur).encode("utf8"))
619 # else:
620 # serv.privmsg(channel,l1[i].format(auteur).format(auteur).encode("utf8"))
621 # if is_good_action_trigger(action,mypseudo) and not channel in self.quiet_channels:
622 # l1,l2=config_good_action_answers,config_good_action_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).format(auteur).encode("utf8"))
627 # else:
628 # serv.privmsg(channel,l1[i].format(auteur).format(auteur).encode("utf8"))
629
630 def on_kick(self,serv,ev):
631 auteur = irclib.nm_to_n(ev.source())
632 channel = ev.target()
633 victime = ev.arguments()[0]
634 raison = ev.arguments()[1]
635 if victime==self.nick:
636 log(self.serveur,"%s kické de %s par %s (raison : %s)" %(victime,channel,auteur,raison))
637 time.sleep(2)
638 serv.join(channel)
639
640 def kicker(self, chan, pseudo, raison=None):
641 if raison==None:
642 raison = config_kick_default_reason
643 self.serv.kick(chan,pseudo,raison)
644
645 def quitter(self,chan,leave_message=None):
646 if leave_message==None:
647 leave_message=random.choice(config_leave_messages)
648 self.serv.part(chan,message=leave_message.encode("utf8"))
649
650 def mourir(self):
651 quit_message=random.choice(config_quit_messages)
652 self.die(msg=quit_message.encode("utf8"))
653
654 def _getnick(self):
655 return self.serv.get_nickname()
656 nick=property(_getnick)
657
658
659 if __name__=="__main__":
660 import sys
661 if len(sys.argv)==1:
662 print "Usage : themis.py <serveur> [--debug]"
663 exit(1)
664 serveur=sys.argv[1]
665 if "debug" in sys.argv or "--debug" in sys.argv:
666 debug=True
667 else:
668 debug=False
669 serveurs={"a♡":"acoeur.crans.org","acoeur":"acoeur.crans.org","acoeur.crans.org":"acoeur.crans.org",
670 "irc":"irc.crans.org","crans":"irc.crans.org","irc.crans.org":"irc.crans.org"}
671 try:
672 serveur=serveurs[serveur]
673 except KeyError:
674 print "Server Unknown : %s"%(serveur)
675 exit(404)
676 themis=Themis(serveur,debug)
677 themis.start()