4 # Codé par 20-100 le 23/04/12
6 # Un test de bot irc, parce que c'est cool
13 import socket
, ssl
, json
17 from commands
import getstatusoutput
as ex
20 config_debug_stdout
=True
21 if "--quiet" in sys
.argv
:
22 config_debug_stdout
=False
24 config_irc_password
="NK2015BasileB0t"
25 config_irc_pseudo
="Basile"
26 config_chanlist
=["#bot","#flood"]
27 config_stay_channels
=["#bot","#flood"]
28 config_quiet_channels
=[]
29 config_note_pseudo
="Basile"
30 config_note_password
="NK2015BasileB0tr4nd0omp4assword]6_+{#]78{"
31 config_logfile_template
="basile.%s.log"
32 def get_config_logfile(serveur
):
33 serveurs
={"acoeur.crans.org":"acoeur","irc.crans.org":"crans"}
34 return config_logfile_template
%(serveurs
[serveur
])
35 config_overops
=["[20-100]","[20-100]_"]
36 config_ops
=["PEB","Nit"]
37 config_report_bugs_to
=["[20-100]"]
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",
52 config_insultes_answers
=[u
"toi-même",
53 u
"Oh non ! Quelle insulte ! Je crois que je ne m'en reléverai jamais…\nAh si, ça y est.",
54 u
"J'entends comme un vague murmure, tu disais ?",
55 u
"Je vais prendre ça pour un compliment.",
56 u
"Tu sais, pour toi c'est peut-être une insulte, mais pour moi ce n'est qu'une suite de 0 et de 1…",
57 u
"Si tu allais voir sur un autre chan si j'y suis ?",
58 u
"Permets-moi de te retourner le compliment.",
59 u
"Mais je ne te permets pas !"]
61 config_gros
=[u
"gros",u
"énorme",u
"lourd"]
63 config_buffer_fail_answers
=["haha !","You type like you drive","encore un effort ;)"]
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)",
74 u
"(gagn|trouv)"+config_premier_groupe_terminaisons
,u
"gagnant(|s|e|es)",u
"gain(|s)",
76 u
"trouvant",u
"trouvaille(|s)",
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
85 config_tag_triggers
=[u
"t(|a)g",u
"ta gueule",u
"la ferme",u
"ferme( |-)la",u
"tais-toi",u
"chut"]
86 config_tag_actions
=[u
"se tait",u
"ferme sa gueule",u
"se la ferme",u
"la ferme"]
87 config_tag_answers
=[u
"J'me tais si j'veux !",
88 u
"Je t'entends pas :°",
90 u
"Non, j'ai pas envie",
91 u
"Peut-être quand toi tu la fermeras, et encore…"]
93 config_tesla_triggers
=[u
"t('|u )es là \?",u
"\?",u
"plop \?",u
"plouf \?"]
94 config_tesla_answers
=[u
"Oui, je suis là",u
"Oui ?",u
"En quoi puis-je me rendre utile ?"]
95 config_tesla_actions
=[u
"est là",u
"attend des instructions",u
"is alive"]
97 config_compliment_triggers
=[u
"gentil",u
"cool",u
"sympa"]
98 config_compliment_answers
=[u
"Merci, c'est gentil :)",u
"Je te retourne le compliment",u
"C'est gentil ça."]
100 config_merci_triggers
=[u
"merci",u
"remercie",u
"thx",u
"thank(|s)"]
101 config_merci_answers
=[u
"Mais de rien.",u
"À ton service ;)",u
"Quand tu veux ^^",
102 u
"Tout le plaisir est pour moi."]
104 config_tamere_triggers
=[u
"ta mère"]
105 config_tamere_answers
=[u
"Laisse ma mère en dehors de ça !",
106 u
"Tu veux qu'on parle de ta soœur ?",
108 u
"Ce que fait ma mère c'est comme ce que tu fais avec ta bite, ça nous regarde pas…",
109 u
"♩ J'ai vu ta mère sur chat rouleeeeeeette ♫",
110 u
"On avait dit \"pas les mamans\""]
112 config_bad_action_triggers
=[u
"(frappe|cogne|tape)(| sur)",u
"(démolit|dégomme|fouette|agresse)",
113 u
"vomit sur",u
"slap(|s)"]
114 config_bad_action_answers
=[u
"Hey ! Mais qu'est-ce que j'ai fait ?",
117 u
"Mais j'ai rien demandé moi !"]
118 config_bad_action_actions
=[u
"prend de la distance, par précaution…",u
"part en courant",u
"esquive"]
120 config_good_action_triggers
=[u
"fait (:?des bisous|un c(?:â|a)lin|des c(?:â|a)lins) à",u
"embrasse",u
"c(?:â|a)line",u
"caresse"]
121 config_good_action_answers
=[u
"owi \o/",u
"c'est gentil ! ♡"]
122 config_good_action_actions
=[u
"ronronne",u
"est content"]
124 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"]
125 config_bonjour_answers
=[u
"Salut {}",u
"Hello {} :)",u
"Bonjour {}",u
"Hello {}",u
"{}: hello",u
"{}: bonjour"]
127 config_bonne_nuit_triggers
=[u
"bonne nuit",u
"'?nite",u
"'?nuit",u
"'?night",u
"good night",u
"'?nunuit"]
128 config_bonne_nuit_answers
=[u
"{}: sweet dreams ;)",u
"Bonne nuit {} !",u
"À demain {}. :)","{}: dors bien ^^"]
130 config_kick_answers
=[u
"Ben qu'est-ce que j'ai fait ? :(",u
"Mais euh, j'ai rien fait de mal…","{} a le /kick facile :)"]
131 config_kick_actions
=[u
"se tiendra à carreaux",u
"essaiera de ne plus provoquer les foudres de {}"]
133 config_thisfile
= os
.path
.realpath( __file__
)
135 return ex("ls -s %s"%(config_thisfile))[1].split()[0]
137 class NKError(Exception):
138 def __init__(self
,msg
):
139 Exception.__init
__(self
)
143 def __unicode__(self
):
144 return unicode(self
.msg
)
146 class NKRefused(NKError
):
149 class NKHelloFailed(NKError
):
152 class NKUnknownError(NKError
):
155 def log(serveur
,channel
,auteur
=None,message
=None):
156 f
=open(get_config_logfile(serveur
),"a")
157 if auteur
==message
==None:
158 # alors c'est que c'est pas un channel mais juste une ligne de log
159 chain
="%s %s"%(time
.strftime("%F %T"),channel
)
161 chain
="%s [%s:%s] %s"%(time
.strftime("%F %T"),channel
,auteur
,message
)
163 if config_debug_stdout
:
170 # On établit la connexion sur port 4242
171 sock
.connect(("127.0.0.1",4242))
173 sock
=ssl
.wrap_socket(sock
,ca_certs
='../keys/ca_.crt')
175 sock
.write('hello "Basile"')
176 # On récupère la réponse du hello
179 except Exception as exc
:
180 # Si on a foiré quelque part, c'est que le serveur est down
181 raise NKRefused(str(exc
))
182 if out
["retcode"]==0:
184 elif out
["retcode"]==11:
185 raise NKHelloFailed(out
["errmsg"])
187 raise NKUnknownError(out
["errmsg"])
189 def login_NK(username
,password
,typ
="bdd"):
191 if typ
=="special": # ça c'est pour Basile lui-même
194 masque
='[["all"],["all"],false]'
196 # Basile a un compte special user
197 commande
='login [%s,%s,"%s",%s]'%(json
.dumps(username
),json
.dumps(password
),typ
,masque
)
200 except Exception as exc
:
201 # Si on a foiré quelque part, c'est que le serveur est down
202 raise NKRefused(str(exc
))
203 # On vérifie ensuite que le login
204 return json
.loads(out
),sock
207 def is_something(chain
,matches
,avant
=u
".*(?:^| )",apres
=u
"(?:$|\.| |,|;).*",case_sensitive
=False,debug
=False):
209 chain
=unicode(chain
,"utf8")
211 chain
=unicode(chain
,"utf8").lower()
212 allmatches
="("+"|".join(matches
)+")"
213 reg
=(avant
+allmatches
+apres
).lower()
214 o
=re
.match(reg
,chain
)
217 def is_insult(chain
,debug
=True):
218 return is_something(chain
,config_insultes
,avant
=".*(?:^| |')")
219 def is_not_insult(chain
):
220 chain
=unicode(chain
,"utf8")
221 insult_regexp
=u
"("+u
"|".join(config_insultes
)+u
")"
222 middle_regexp
=u
"(une? (?:(?:putain|enfoiré) d(?:e |'))*|)(?:| super )(?: (?:gros|petit|grand|énorme) |)"
223 reg
=".*pas %s%s.*"%(middle_regexp
,insult_regexp
)
224 if re
.match(reg
,chain
):
229 return is_something(chain
,config_perdu
)
231 return is_something(chain
,config_tag_triggers
)
233 return is_something(chain
,config_gros
)
235 return is_something(chain
,config_tesla_triggers
,avant
=u
"^",apres
=u
"$",debug
=True)
237 return is_something(chain
,config_merci_triggers
)
238 def is_tamere(chain
):
239 return is_something(chain
,config_tamere_triggers
)
240 def is_bad_action_trigger(chain
,pseudo
):
241 return is_something(chain
,config_bad_action_triggers
,avant
=u
"^",
242 apres
="(?: [a-z]*ment)? %s($|\.| |,|;).*"%(pseudo))
243 def is_good_action_trigger(chain
,pseudo
):
244 return is_something(chain
,config_good_action_triggers
,avant
=u
"^",
245 apres
="(?: [a-z]*ment)? %s($|\.| |,|;).*"%(pseudo))
246 def is_bonjour(chain
):
247 return is_something(chain
,config_bonjour_triggers
,avant
=u
"^")
248 def is_bonne_nuit(chain
):
249 return is_something(chain
,config_bonne_nuit_triggers
,avant
=u
"^")
251 return re
.match(u
"^(pan|bim|bang) .*$",unicode(chain
,"utf8").lower().strip())
255 class UnicodeBotError(Exception):
257 def bot_unicode(chain
):
259 unicode(chain
,"utf8")
260 except UnicodeDecodeError as exc
:
261 raise UnicodeBotError
263 class Basile(ircbot
.SingleServerIRCBot
):
264 def __init__(self
,serveur
,debug
=False):
265 temporary_pseudo
=config_irc_pseudo
+str(random
.randrange(10000,100000))
266 ircbot
.SingleServerIRCBot
.__init
__(self
, [(serveur
, 6667)],
267 temporary_pseudo
,"Basile, le bot irc.[Codé par 20-100, fouettez-le]", 10)
270 self
.overops
=config_overops
271 self
.ops
=self
.overops
+config_ops
272 self
.report_bugs_to
=config_report_bugs_to
273 self
.chanlist
=config_chanlist
275 self
.identities
=pickle
.load(open("identities.pickle","r"))
276 self
.stay_channels
=config_stay_channels
277 self
.quiet_channels
=config_quiet_channels
281 def new_connection_NK(self
,serv
,username
,password
,typ
="bdd"):
283 login_result
,sock
=login_NK(username
,password
,typ
)
284 droits
,retcode
,errmsg
=login_result
["msg"],login_result
["retcode"],login_result
["errmsg"]
285 except NKRefused
as exc
:
286 for report
in self
.report_bugs_to
:
287 serv
.privmsg(report
,"Le Serveur NK2015 est down.")
289 except NKHelloFailed
as exc
:
290 for report
in self
.report_bugs_to
:
292 "La version du site utilisée n'est pas supportée par le serveur NK2015.")
294 except NKUnknownError
as exc
:
295 erreurs
=["Une fucking erreur inconnue s'est produite"]
296 erreurs
+=str(exc
).split("\n")
297 for report
in self
.report_bugs_to
:
299 serv
.privmsg(report
,err
)
301 except Exception as exc
:
302 # Exception qui ne vient pas de la communication avec le serveur NK2015
303 log(self
.serveur
,"Erreur dans new_connection_NK\n"+str(exc
))
310 def give_me_my_pseudo(self
,serv
):
311 serv
.privmsg("NickServ","RECOVER %s %s"%(config_irc_pseudo
,config_irc_password
))
312 serv
.privmsg("NickServ","RELEASE %s %s"%(config_irc_pseudo
,config_irc_password
))
314 serv
.nick(config_irc_pseudo
)
316 def on_welcome(self
, serv
, ev
):
317 self
.serv
=serv
# ça serv ira :)
318 self
.give_me_my_pseudo(serv
)
319 serv
.privmsg("NickServ","identify %s"%(config_irc_password))
320 log(self
.serveur
,"Connected")
322 self
.chanlist
=["#bot"]
323 for c
in self
.chanlist
:
324 log(self
.serveur
,"JOIN %s"%(c))
326 # on ouvre la connexion note de Basile, special user
327 self
.nk
=self
.new_connection_NK(serv
,config_note_pseudo
,config_note_password
,"special")[1]
329 for report
in self
.report_bugs_to
:
330 serv
.privmsg(report
,"Connection to NK2015 failed, invalid password ?")
332 def lost(self
,serv
,channel
,forced
=False):
333 if self
.last_perdu
+config_time_between_perdu
<time
.time() or forced
:
334 if not channel
in self
.quiet_channels
or forced
:
335 serv
.privmsg(channel
,"J'ai perdu !")
336 self
.last_perdu
=time
.time()
337 delay
=config_time_between_perdu_trigger
338 delta
=config_time_between_perdu_trigger_delta
339 serv
.execute_delayed(random
.randrange(delay
-delta
,delay
+delta
),self
.lost
,(serv
,channel
))
341 def try_tamere(self
,serv
,channel
,auteur
,message
):
342 """Essaye de trigger un ta mère"""
343 #pas à chaque fois quand même
344 if random
.randrange(4)==0:
345 debuts
=u
"("+config_regexp_etre
+u
"|"+config_regexp_etre_avec_c
+u
")"
346 adjectifs
={u
"bon(|ne|s|nes)":u
"bonne",
347 u
"baisable(|s)":u
"baisable",
348 u
"faisable(|s)":u
"faisable",
349 u
"pas ch(ère(|s)|er(|s))":u
"pas chère",
350 u
"facile(|s)":u
"facile",
351 u
"chaud(|e|s|es)":u
"chaude",
352 u
"gratuit(|e|s|es)":u
"gratuite",
353 u
"payant(|e|s|es)":u
"payante",
354 u
"ouvert(|e|s|es)":u
"ouverte",
356 u
"plein(|s|es)":u
"pleine",
357 u
"bien plein(|e|s|es)":u
"bien pleine",
358 u
"innocent(|e|s|es)":u
"innocente"}
359 adj_reg
=u
"(?P<adjectif>"+u
"|".join(adjectifs
.keys())+u
")"
360 reg
=u
".*(^| |')"+debuts
+u
" "+adj_reg
+u
"($|,|;|\.| ).*"
361 matched
=re
.match(reg
,message
)
363 # il faut repasser l'adjectif au féminin singulier
364 found
=matched
.groupdict()["adjectif"]
365 for adj
in adjectifs
.keys():
366 if re
.match(adj
,found
):
367 adjectif
=adjectifs
[adj
]
369 serv
.privmsg(channel
,(u
"%s: c'est ta mère qui est %s !"%(auteur
,adjectif
)).encode("utf8"))
370 elif random
.randrange(5)==0:
371 # deuxième type de trigger, mais moins probable
372 matched
=re
.match(adj_reg
,message
)
374 found
=matched
.groupdict()["adjectif"]
375 for adj
in adjectifs
.keys():
376 if re
.match(adj
,found
):
377 adjectif
=adjectifs
[adj
]
379 fille
=random
.choice([u
"mère",u
"soœur"])
380 serv
.privmsg(channel
,(u
"%s: et ta %s, elle est %s ?"%
381 (auteur
,fille
,adjectif
)).encode("utf8"))
383 # troisième type de trigger
384 cpgt
=config_premier_groupe_terminaisons
385 verbes
={u
"tourn"+cpgt
:u
"tourne",
386 u
"balad"+cpgt
+u
" sur le trottoir":u
"se balade sur le trottoir",
387 u
"prom(e|è)n"+cpgt
+" sur le trottoir":u
"se promène sur le trottoir",
389 vb_reg
=u
".*(^| )(?P<verbe>"+"|".join(verbes
.keys())+")( |,|;|\.|$)"
390 matched
=re
.match(vb_reg
,message
)
392 found
=matched
.groupdict()["verbe"]
393 for vb
in verbes
.keys():
394 if re
.match(vb
,found
):
397 fille
=random
.choice([u
"mère",u
"soœur"])
398 serv
.privmsg(channel
,(u
"%s: et ta %s, elle %s ?"%
399 (auteur
,fille
,verbe
)).encode("utf8"))
400 def pourmoi(self
, serv
, message
):
401 """renvoie (False,lemessage) ou (True, le message amputé de "pseudo: ")"""
404 if message
[:size
]==pseudo
and len(message
)>size
and message
[size
]==":":
405 return (True,message
[size
+1:].lstrip(" "))
407 return (False,message
)
409 def on_privmsg(self
, serv
, ev
):
410 message
=ev
.arguments()[0]
411 auteur
= irclib
.nm_to_n(ev
.source())
413 test
=bot_unicode(message
)
414 except UnicodeBotError
:
416 "Euh, tu fais de la merde avec ton encodage là, j'ai failli crasher…")
418 message
=message
.split()
419 cmd
=message
[0].lower()
422 if not len(message
) in [2,3]:
423 serv
.privmsg(auteur
,"Syntaxe : CONNECT [<username>] <password>")
427 username
=(message
[1])
428 password
=" ".join(message
[2:])
430 password
=" ".join(message
[1:])
431 success
,sock
=self
.new_connection_NK(serv
,username
,password
)
433 self
.sockets
[username
]=sock
434 serv
.privmsg(auteur
,"Connection successful")
435 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
437 serv
.privmsg(auteur
,"Connection failed")
438 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
441 helpdico
={"connect": """CONNECT [<username>] <password>
442 Ouvre une connexion au serveur NoteKfet.
443 Si <username> n'est pas précisé, j'utiliserais l'identité sous laquelle je te connais, ou, à défaut, ton pseudo.""",
444 "identify": """IDENTIFY <username> <password>
445 Vérifie le mot de passe et me permet de savoir à l'avenir quel est ton pseudo note kfet.
446 Sans paramètre, je réponds sous quel pseudo je te connais.""",
447 "drop":"""DROP <password>
448 Vérifie le mot de passe et me fait d'oublier ton pseudo note kfet."""}
449 helpmsg_default
="""Liste des commandes :
450 HELP Affiche de l'aide sur une commande.
451 CONNECT Ouvre une connection au serveur Note Kfet.
452 IDENTIFY Me permet de savoir qui tu es sur la note kfet.
453 DROP Me fait oublier ton identité.
454 SOLDE Obtenir ton solde"""
456 JOIN Faire rejoindre un chan
457 LEAVE Faire quitter un chan
458 QUIET Se taire sur un chan
459 NOQUIET Opposé de QUIET
460 LOST Perdre sur un chan
461 SOLDE <pseudo> Donner le solde de quelqu'un"""
463 SAY Fait envoyer un message sur un chan ou à une personne
464 DO Fait faire une action sur un chan
465 STAY Ignorera les prochains LEAVE pour un chan
466 NOSTAY Opposé de STAY
469 helpmsg
=helpmsg_default
470 if auteur
in self
.ops
:
472 if auteur
in self
.overops
:
473 helpmsg
+=helpmsg_overops
475 helpmsg
=helpdico
.get(message
[1].lower(),"Commande inconnue.")
476 for ligne
in helpmsg
.split("\n"):
477 serv
.privmsg(auteur
,ligne
)
478 elif cmd
=="identify":
480 if self
.identities
.has_key(auteur
):
481 serv
.privmsg(auteur
,"Je te connais sous le pseudo note %s."%(
482 self
.identities
[auteur
].encode("utf8")))
484 serv
.privmsg(auteur
,"Je ne connais pas ton pseudo note.")
485 elif len(message
)>=3:
486 username
,password
=message
[1],unicode(" ".join(message
[2:]),"utf8")
487 success
,_
=self
.new_connection_NK(serv
,username
,password
)
489 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
490 serv
.privmsg(auteur
,"Identité enregistrée.")
491 self
.identities
[auteur
]=username
492 pickle
.dump(self
.identities
,open("identities.pickle","w"))
494 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
495 serv
.privmsg(auteur
,"Mot de passe invalide. (ou serveur down)")
497 serv
.privmsg(auteur
,u
"Syntaxe : IDENTIFY [<username> <password>]")
500 if self
.identities
.has_key(auteur
):
501 password
=" ".join(message
[1:])
502 success
,_
=self
.new_connection_NK(serv
,self
.identities
[auteur
],password
)
504 del self
.identities
[auteur
]
505 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
506 pickle
.dump(self
.identities
,open("identities.pickle","w"))
507 serv
.privmsg(auteur
,"Identité oubliée.")
509 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
510 serv
.privmsg(auteur
,"Mot de passe invalide. (ou serveur down)")
512 serv
.privmsg(auteur
,"Je ne connais pas ton pseudo note.")
514 serv
.privmsg(auteur
,"Syntaxe : DROP <password>")
516 if auteur
in self
.ops
:
518 if message
[1] in self
.chanlist
:
519 serv
.privmsg(auteur
,"Je suis déjà sur %s"%(message
[1]))
521 serv
.join(message
[1])
522 self
.chanlist
.append(message
[1])
523 serv
.privmsg(auteur
,"Channels : "+" ".join(self
.chanlist
))
524 log(self
.serveur
,"priv",auteur
," ".join(message
))
526 serv
.privmsg(auteur
,"Channels : "+" ".join(self
.chanlist
))
530 if auteur
in self
.ops
and len(message
)>1:
531 if message
[1] in self
.chanlist
:
532 if not (message
[1] in self
.stay_channels
) or auteur
in self
.overops
:
533 serv
.part(message
[1])
534 self
.chanlist
.remove(message
[1])
535 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
537 serv
.privmsg(auteur
,"Non, je reste !")
538 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
540 serv
.privmsg(auteur
,"Je ne suis pas sur %s"%(message
[1]))
544 if auteur
in self
.overops
:
546 if message
[1] in self
.stay_channels
:
547 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
548 serv
.privmsg(auteur
,"Je stay déjà sur %s."%(message
[1]))
550 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
551 self
.stay_channels
.append(message
[1])
552 serv
.privmsg(auteur
,"Stay channels : "+" ".join(self
.stay_channels
))
554 serv
.privmsg(auteur
,"Stay channels : "+" ".join(self
.stay_channels
))
558 if auteur
in self
.overops
:
560 if message
[1] in self
.stay_channels
:
561 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
562 self
.stay_channels
.remove(message
[1])
563 serv
.privmsg(auteur
,"Stay channels : "+" ".join(self
.stay_channels
))
565 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
566 serv
.privmsg(auteur
,"Je ne stay pas sur %s."%(message
[1]))
571 if auteur
in self
.overops
:
572 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
577 if auteur
in self
.ops
:
579 if message
[1] in self
.quiet_channels
:
580 serv
.privmsg(auteur
,"Je me la ferme déjà sur %s"%(message
[1]))
581 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
583 self
.quiet_channels
.append(message
[1])
584 serv
.privmsg(auteur
,"Quiet channels : "+" ".join(self
.quiet_channels
))
585 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
587 serv
.privmsg(auteur
,"Quiet channels : "+" ".join(self
.quiet_channels
))
591 if auteur
in self
.ops
:
593 if message
[1] in self
.quiet_channels
:
594 self
.quiet_channels
.remove(message
[1])
595 serv
.privmsg(auteur
,"Quiet channels : "+" ".join(self
.quiet_channels
))
596 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
598 serv
.privmsg(auteur
,"Je ne me la ferme pas sur %s."%(message
[1]))
599 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
603 if auteur
in self
.overops
and len(message
)>2:
604 serv
.privmsg(message
[1]," ".join(message
[2:]))
605 log(self
.serveur
,"priv",auteur
," ".join(message
))
606 elif len(message
)<=2:
607 serv
.privmsg(auteur
,"Syntaxe : SAY <channel> <message>")
611 if auteur
in self
.overops
and len(message
)>2:
612 serv
.action(message
[1]," ".join(message
[2:]))
613 log(self
.serveur
,"priv",auteur
," ".join(message
))
614 elif len(message
)<=2:
615 serv
.privmsg(auteur
,"Syntaxe : DO <channel> <action>")
619 if auteur
in self
.overops
and len(message
)>2:
620 serv
.kick(message
[1],message
[2]," ".join(message
[3:]))
621 log(self
.serveur
,"priv",auteur
," ".join(message
))
622 elif len(message
)<=2:
623 serv
.privmsg(auteur
,"Syntaxe : KICK <channel> <pseudo>")
627 if auteur
in self
.ops
and len(message
)>1:
628 serv
.privmsg(message
[1],"J'ai perdu !")
629 log(self
.serveur
,"priv",auteur
," ".join(message
))
630 elif len(message
)<=1:
631 serv
.privmsg(auteur
,"Syntaxe : LOST <channel>")
636 if self
.identities
.has_key(auteur
):
638 self
.nk
.write('search ["x",["pseudo"],%s]'%(json
.dumps(self
.identities
[auteur
])))
639 ret
=json
.loads(self
.nk
.read())
640 solde
=ret
["msg"][0]["solde"]
641 pseudo
=ret
["msg"][0]["pseudo"]
642 except Exception as exc
:
644 serv
.privmsg(auteur
,"failed")
645 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
647 serv
.privmsg(auteur
,"%s (%s)"%(float(solde
)/100,pseudo
.encode("utf8")))
649 serv
.privmsg(canal
,"Je ne connais pas ton pseudo note.")
650 elif auteur
in self
.ops
:
652 self
.nk
.write('search ["x",["pseudo"],%s]'%(json
.dumps(message
[1])))
653 ret
=json
.loads(self
.nk
.read())
654 solde
=ret
["msg"][0]["solde"]
655 pseudo
=ret
["msg"][0]["pseudo"]
656 except Exception as exc
:
657 serv
.privmsg(auteur
,"failed")
658 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
660 serv
.privmsg(auteur
,"%s (%s)"%(float(solde
)/100,pseudo
.encode("utf8")))
664 serv
.privmsg(auteur
,"Je n'ai pas compris. Essaye HELP…")
666 def on_pubmsg(self
, serv
, ev
):
667 auteur
= irclib
.nm_to_n(ev
.source())
669 message
= ev
.arguments()[0]
671 test
=bot_unicode(message
)
672 except UnicodeBotError
:
673 if not canal
in self
.quiet_channels
:
675 "%s: Euh, tu fais de la merde avec ton encodage là, j'ai failli crasher…"%(auteur))
677 pour_moi
,message
=self
.pourmoi(serv
,message
)
678 if pour_moi
and message
.split()!=[]:
679 cmd
=message
.split()[0].lower()
681 args
=" ".join(message
.split()[1:])
684 if cmd
in ["meurs","die","crève"]:
685 if auteur
in self
.overops
:
686 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
689 serv
.privmsg(canal
,"%s: crève !"%(auteur))
690 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
692 elif cmd
in ["part","leave","dégage"]:
693 if auteur
in self
.ops
and (not (canal
in self
.stay_channels
)
694 or auteur
in self
.overops
):
695 serv
.part(canal
,message
="Éjecté par %s"%(auteur))
696 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
697 if canal
in self
.chanlist
:
698 self
.chanlist
.remove(canal
)
700 serv
.privmsg(canal
,"%s: Non, je reste !"%(auteur))
701 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
703 elif cmd
in ["reconnect"]:
704 if auteur
in self
.ops
:
706 self
.nk
=self
.new_connection_NK(serv
,config_note_pseudo
,
707 config_note_password
,"special")[1]
708 except Exception as exc
:
710 log(self
.serveur
,"""Erreur dans on_pubmsg/"cmd in ["reconnect"]\n"""+str(exc
))
712 serv
.privmsg(canal
,"%s: done"%(auteur))
713 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
715 serv
.privmsg(canal
,"%s: failed"%(auteur))
716 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
717 for report
in self
.report_bugs_to
:
718 serv
.privmsg(report
,"Connection to NK2015 failed, invalid password ?")
720 serv
.privmsg(canal
,"%s: crève !"%(auteur))
721 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
723 elif cmd
in ["deviens","pseudo"]:
724 if auteur
in self
.ops
:
727 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
729 if cmd
in ["meur", "meurt","meurre","meurres"] and not canal
in self
.quiet_channels
:
730 serv
.privmsg(canal
,'%s: Mourir, impératif, 2ème personne du singulier : "meurs" (de rien)'%(auteur))
731 elif cmd
in ["ping"] and not canal
in self
.quiet_channels
:
732 serv
.privmsg(canal
,"%s: pong"%(auteur))
734 elif cmd
in ["solde","!solde"]:
735 if self
.identities
.has_key(auteur
):
736 pseudo
=self
.identities
[auteur
]
738 self
.nk
.write('search ["x",["pseudo"],%s]'%(json
.dumps(pseudo
)))
739 ret
=json
.loads(self
.nk
.read())
740 solde
=ret
["msg"][0]["solde"]
741 pseudo
=ret
["msg"][0]["pseudo"]
742 except Exception as exc
:
743 serv
.privmsg(canal
,"%s: failed"%(auteur))
744 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
746 serv
.privmsg(canal
,"%s: %s (%s)"%(auteur
,float(solde
)/100,pseudo
.encode("utf8")))
747 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
749 serv
.privmsg(canal
,"%s: Je ne connais pas ton pseudo note."%(auteur))
750 log(self
.serveur
,canal
,auteur
,message
+"[unknown]")
751 elif (re
.match("!?(pain au chocolat|chocolatine)",message
.lower())
752 and not canal
in self
.quiet_channels
):
753 serv
.action(canal
,"sert un pain au chocolat à %s"%(auteur))
754 elif re
.match("!?manzana",message
.lower()) and not canal
in self
.quiet_channels
:
755 if auteur
=="[20-100]":
756 serv
.action(canal
,"sert une bouteille de manzana à %s"%(auteur))
758 serv
.action(canal
,"sert un verre de manzana à %s"%(auteur))
759 if is_insult(message
) and not canal
in self
.quiet_channels
:
760 if is_not_insult(message
):
761 answer
=random
.choice(config_compliment_answers
)
762 for ligne
in answer
.split("\n"):
763 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
765 answer
=random
.choice(config_insultes_answers
)
766 for ligne
in answer
.split("\n"):
767 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
768 gros_match
=is_gros(message
)
769 if gros_match
and not canal
in self
.quiet_channels
:
770 taille
=get_filesize()
771 answer
=u
"Mais non, je ne suis pas %s, %sKo tout au plus…"%(gros_match
.groups()[0],taille
)
772 serv
.privmsg(canal
,"%s: %s"%(auteur
,answer
.encode("utf8")))
773 if is_tesla(message
) and not canal
in self
.quiet_channels
:
774 l1
,l2
=config_tesla_answers
,config_tesla_actions
775 n1
,n2
=len(l1
),len(l2
)
776 i
=random
.randrange(n1
+n2
)
778 serv
.action(canal
,l2
[i
-n1
].encode("utf8"))
780 serv
.privmsg(canal
,"%s: %s"%(auteur
,l1
[i
].encode("utf8")))
781 if is_tamere(message
) and not canal
in self
.quiet_channels
:
782 answer
=random
.choice(config_tamere_answers
)
783 for ligne
in answer
.split("\n"):
784 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
785 if is_tag(message
) and not canal
in self
.quiet_channels
:
786 if auteur
in self
.ops
:
787 action
=random
.choice(config_tag_actions
)
788 serv
.action(canal
,action
.encode("utf8"))
789 self
.quiet_channels
.append(canal
)
791 answer
=random
.choice(config_tag_answers
)
792 for ligne
in answer
.split("\n"):
793 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
794 if is_merci(message
):
795 answer
=random
.choice(config_merci_answers
)
796 for ligne
in answer
.split("\n"):
797 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
798 out
=re
.match(ur
"^([A-Z[]|\\|[0-9]+|(¹|²|³|⁴|⁵|⁶|⁷|⁸|⁹|⁰)+)(?:| \?| !)$",
799 unicode(message
.upper(),"utf8"))
800 if out
and not canal
in self
.quiet_channels
:
804 serv
.privmsg(canal
,"%s: %s !"%(auteur
,out
+1))
805 if out
+1>1000 and random
.randrange(4)==0:
806 serv
.privmsg(canal
,"%s: Tu sais, je peux continuer longtemps comme ça…"%(auteur))
808 serv
.privmsg(canal
,"%s: Tu croyais m'avoir sur le maxint ? J'suis en python mon vieux, 'va falloir trouver mieux…"%(auteur))
810 except Exception as exc
:
812 if re
.match("[A-Y]",out
):
813 alphabet
="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
814 serv
.privmsg(canal
,"%s: %s !"%(auteur
,alphabet
[alphabet
.index(out
)+1]))
816 serv
.privmsg(canal
,"%s: pfff, j'ai l'air malin maintenant… [ ?"%(auteur))
818 serv
.privmsg(canal
,"%s: nan mais il faut qu'on arrête, ça va finir par poser des problèmes…"%(auteur))
819 elif re
.match(ur
"(¹|²|³|⁴|⁵|⁶|⁷|⁸|⁹|⁰)+",out
):
821 return "".join([{u
"⁰¹²³⁴⁵⁶⁷⁸⁹0123456789"[i
]:u
"0123456789⁰¹²³⁴⁵⁶⁷⁸⁹"[i
]
822 for i
in range(20)}[j
]
824 out
=int(translate(out
))
825 serv
.privmsg(canal
,"%s: %s !"%(auteur
,translate(str(out
+1)).encode("utf8")))
826 if is_bonjour(message
) and not canal
in self
.quiet_channels
:
827 answer
=random
.choice(config_bonjour_answers
)
828 serv
.privmsg(canal
,answer
.format(auteur
).encode("utf8"))
829 if is_bonne_nuit(message
) and not canal
in self
.quiet_channels
:
830 answer
=random
.choice(config_bonne_nuit_answers
)
831 serv
.privmsg(canal
,answer
.format(auteur
).encode("utf8"))
832 if is_pan(message
) and not canal
in self
.quiet_channels
:
833 serv
.privmsg(canal
,"%s: c'est pas sur moi qu'il faut tirer !"%(auteur))
835 if message
in ["!pain au chocolat","!chocolatine"] and not canal
in self
.quiet_channels
:
836 serv
.action(canal
,"sert un pain au chocolat à %s"%(auteur))
837 if message
in ["!manzana"] and not canal
in self
.quiet_channels
:
838 if auteur
=="[20-100]":
839 serv
.action(canal
,"sert une bouteille de manzana à %s"%(auteur))
841 serv
.action(canal
,"sert un verre de manzana à %s"%(auteur))
842 if re
.match('^(.|§|:|)(w|b) [0-9]+$',message
) and not canal
in self
.quiet_channels
:
843 failanswers
=config_buffer_fail_answers
844 answer
=random
.choice(failanswers
)
845 serv
.privmsg(canal
,"%s: %s"%(auteur
,answer
))
846 if not canal
in self
.quiet_channels
:
847 self
.try_tamere(serv
,canal
,auteur
,message
)
849 if re
.match((u
"^("+u
"|".join(config_bonjour_triggers
)
850 +u
")( {}| all| tout le monde|(|à) tous)(\.|( |)!|)$"
851 ).format(mypseudo
).lower(), message
.strip().lower()):
852 answer
=random
.choice(config_bonjour_answers
)
853 serv
.privmsg(canal
,answer
.format(auteur
).encode("utf8"))
854 if (is_perdu(message
) and not canal
in self
.quiet_channels
):
855 # proba de perdre sur trigger :
856 # avant 30min (enfin, config) : 0
857 # ensuite, +25%/30min, linéairement
858 deltat
=time
.time()-self
.last_perdu
859 barre
=(deltat
-config_time_between_perdu
)/(2*3600.0)
860 if random
.uniform(0,1)<barre
:
861 serv
.privmsg(canal
,"%s: J'ai perdu !"%(auteur))
862 self
.last_perdu
=time
.time()
864 def on_action(self
, serv
, ev
):
865 action
= ev
.arguments()[0]
866 auteur
= irclib
.nm_to_n(ev
.source())
867 channel
= ev
.target()
869 test
=bot_unicode(action
)
870 except UnicodeBotError
:
871 serv
.privmsg(channel
,
872 "%s : Euh, tu fais de la merde avec ton encodage là, j'ai failli crasher…"%(auteur))
876 if is_bad_action_trigger(action
,mypseudo
) and not channel
in self
.quiet_channels
:
877 l1
,l2
=config_bad_action_answers
,config_bad_action_actions
878 n1
,n2
=len(l1
),len(l2
)
879 i
=random
.randrange(n1
+n2
)
881 serv
.action(channel
,l2
[i
-n1
].encode("utf8"))
883 serv
.privmsg(channel
,"%s: %s"%(auteur
,l1
[i
].encode("utf8")))
884 if is_good_action_trigger(action
,mypseudo
) and not channel
in self
.quiet_channels
:
885 l1
,l2
=config_good_action_answers
,config_good_action_actions
886 n1
,n2
=len(l1
),len(l2
)
887 i
=random
.randrange(n1
+n2
)
889 serv
.action(channel
,l2
[i
-n1
].encode("utf8"))
891 serv
.privmsg(channel
,"%s: %s"%(auteur
,l1
[i
].encode("utf8")))
893 def on_kick(self
,serv
,ev
):
894 auteur
= irclib
.nm_to_n(ev
.source())
895 channel
= ev
.target()
896 victime
= ev
.arguments()[0]
897 raison
= ev
.arguments()[1]
898 if victime
==self
.nick
:
899 log(self
.serveur
,"%s kické par %s (raison : %s)" %(victime
,auteur
,raison
))
902 l1
,l2
=config_kick_answers
,config_kick_actions
903 n1
,n2
=len(l1
),len(l2
)
904 i
=random
.randrange(n1
+n2
)
906 serv
.action(channel
,l2
[i
-n1
].format(auteur
).encode("utf8"))
908 serv
.privmsg(channel
,"%s: %s"%(auteur
,l1
[i
].format(auteur
).encode("utf8")))
911 return self
.serv
.get_nickname()
912 nick
=property(_getnick
)
915 if __name__
=="__main__":
918 print "Usage : basile.py <serveur> [--debug]"
921 if "debug" in sys
.argv
or "--debug" in sys
.argv
:
925 serveurs
={"a♡":"acoeur.crans.org","acoeur":"acoeur.crans.org","acoeur.crans.org":"acoeur.crans.org",
926 "irc":"irc.crans.org","crans":"irc.crans.org","irc.crans.org":"irc.crans.org"}
928 serveur
=serveurs
[serveur
]
930 print "Server Unknown : %s"%(serveur)
932 basile
=Basile(serveur
,debug
)