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 !"]
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
=[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
=[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
=[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
=[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
=[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_action_trigger
=[u
"(frappe|cogne|tape)(| sur)",u
"démolit",u
"vomit sur",u
"slap(|s)"]
113 config_action_answers
=[u
"Hey ! Mais qu'est-ce que j'ai fait ?",
116 u
"Mais j'ai rien demandé moi !"]
117 config_action_actions
=[u
"prend de la distance, par précaution…",u
"part en courant"]
119 config_bonjour
=[u
"(s|)(a|'|)lu(t|)",u
"hello",u
"plop",u
"plip",u
"pr(ou|ü)t",u
"bonjour",u
"bonsoir"]
120 config_bonjour_answers
=[u
"Salut {}",u
"Hello {} :)",u
"Bonjour {}",u
"Hello {}",u
"{}: hello",u
"{}: bonjour"]
123 config_thisfile
= os
.path
.realpath( __file__
)
125 return ex("ls -s %s"%(config_thisfile))[1].split()[0]
127 class NKError(Exception):
128 def __init__(self
,msg
):
129 Exception.__init
__(self
)
133 def __unicode__(self
):
134 return unicode(self
.msg
)
136 class NKRefused(NKError
):
139 class NKHelloFailed(NKError
):
142 class NKUnknownError(NKError
):
145 def log(serveur
,channel
,auteur
=None,message
=None):
146 f
=open(get_config_logfile(serveur
),"a")
147 if auteur
==message
==None:
148 # alors c'est que c'est pas un channel mais juste une ligne de log
149 chain
="%s %s"%(time
.strftime("%F %T"),channel
)
151 chain
="%s [%s:%s] %s"%(time
.strftime("%F %T"),channel
,auteur
,message
)
153 if config_debug_stdout
:
160 # On établit la connexion sur port 4242
161 sock
.connect(("127.0.0.1",4242))
163 sock
=ssl
.wrap_socket(sock
,ca_certs
='../keys/ca_.crt')
165 sock
.write('hello "Basile"')
166 # On récupère la réponse du hello
169 except Exception as exc
:
170 # Si on a foiré quelque part, c'est que le serveur est down
171 raise NKRefused(str(exc
))
172 if out
["retcode"]==0:
174 elif out
["retcode"]==11:
175 raise NKHelloFailed(out
["errmsg"])
177 raise NKUnknownError(out
["errmsg"])
179 def login_NK(username
,password
,typ
="bdd"):
181 if typ
=="special": # ça c'est pour Basile lui-même
184 masque
='[["all"],["all"],false]'
186 # Basile a un compte special user
187 commande
='login [%s,%s,"%s",%s]'%(json
.dumps(username
),json
.dumps(password
),typ
,masque
)
190 except Exception as exc
:
191 # Si on a foiré quelque part, c'est que le serveur est down
192 raise NKRefused(str(exc
))
193 # On vérifie ensuite que le login
194 return json
.loads(out
),sock
197 def is_something(chain
,matches
,avant
=u
".*(^| )",apres
=u
"($|\.| |,|;).*",case_sensitive
=False,debug
=False):
199 chain
=unicode(chain
,"utf8")
201 chain
=unicode(chain
,"utf8").lower()
202 allmatches
="("+"|".join(matches
)+")"
203 reg
=(avant
+allmatches
+apres
).lower()
204 if re
.match(reg
,chain
):
208 def is_insult(chain
,debug
=True):
209 return is_something(chain
,config_insultes
,avant
=".*(^| |')")
210 def is_not_insult(chain
):
211 chain
=unicode(chain
,"utf8")
212 insult_regexp
=u
"("+u
"|".join(config_insultes
)+u
")"
213 middle_regexp
=u
"(un(|e) ((putain|enfoiré) d(e |'))*|)(| super )( (gros|petit|grand|énorme) |)"
214 reg
=".*pas %s%s.*"%(middle_regexp
,insult_regexp
)
215 if re
.match(reg
,chain
):
220 return is_something(chain
,config_perdu
)
222 return is_something(chain
,config_tag
)
224 return is_something(chain
,config_gros
)
226 return is_something(chain
,config_tesla
,avant
=u
"^",apres
=u
"$",debug
=True)
228 return is_something(chain
,config_merci
)
229 def is_tamere(chain
):
230 return is_something(chain
,config_tamere
)
231 def is_action_trigger(chain
,pseudo
):
232 return is_something(chain
,config_action_trigger
,avant
=u
"^",apres
=" %s($|\.| |,|;).*"%(pseudo))
234 return re
.match(u
"^(pan|bim|bang)$",unicode(chain
,"utf8").lower().strip())
238 class UnicodeBotError(Exception):
240 def bot_unicode(chain
):
242 unicode(chain
,"utf8")
243 except UnicodeDecodeError as exc
:
244 raise UnicodeBotError
246 class Basile(ircbot
.SingleServerIRCBot
):
247 def __init__(self
,serveur
,debug
=False):
248 temporary_pseudo
=config_irc_pseudo
+str(random
.randrange(10000,100000))
249 ircbot
.SingleServerIRCBot
.__init
__(self
, [(serveur
, 6667)],
250 temporary_pseudo
,"Basile, le bot irc.[Codé par 20-100, fouettez-le]", 10)
253 self
.overops
=config_overops
254 self
.ops
=self
.overops
+config_ops
255 self
.report_bugs_to
=config_report_bugs_to
256 self
.chanlist
=config_chanlist
258 self
.identities
=pickle
.load(open("identities.pickle","r"))
259 self
.stay_channels
=config_stay_channels
260 self
.quiet_channels
=config_quiet_channels
264 def new_connection_NK(self
,serv
,username
,password
,typ
="bdd"):
266 login_result
,sock
=login_NK(username
,password
,typ
)
267 droits
,retcode
,errmsg
=login_result
["msg"],login_result
["retcode"],login_result
["errmsg"]
268 except NKRefused
as exc
:
269 for report
in self
.report_bugs_to
:
270 serv
.privmsg(report
,"Le Serveur NK2015 est down.")
272 except NKHelloFailed
as exc
:
273 for report
in self
.report_bugs_to
:
275 "La version du site utilisée n'est pas supportée par le serveur NK2015.")
277 except NKUnknownError
as exc
:
278 erreurs
=["Une fucking erreur inconnue s'est produite"]
279 erreurs
+=str(exc
).split("\n")
280 for report
in self
.report_bugs_to
:
282 serv
.privmsg(report
,err
)
284 except Exception as exc
:
285 # Exception qui ne vient pas de la communication avec le serveur NK2015
286 log(self
.serveur
,"Erreur dans new_connection_NK\n"+str(exc
))
293 def give_me_my_pseudo(self
,serv
):
294 serv
.privmsg("NickServ","RECOVER %s %s"%(config_irc_pseudo
,config_irc_password
))
295 serv
.privmsg("NickServ","RELEASE %s %s"%(config_irc_pseudo
,config_irc_password
))
297 serv
.nick(config_irc_pseudo
)
299 def on_welcome(self
, serv
, ev
):
300 self
.give_me_my_pseudo(serv
)
301 serv
.privmsg("NickServ","identify %s"%(config_irc_password))
302 log(self
.serveur
,"Connected")
304 self
.chanlist
=["#bot"]
305 for c
in self
.chanlist
:
306 log(self
.serveur
,"JOIN %s"%(c))
308 # on ouvre la connexion note de Basile, special user
309 self
.nk
=self
.new_connection_NK(serv
,config_note_pseudo
,config_note_password
,"special")[1]
311 for report
in self
.report_bugs_to
:
312 serv
.privmsg(report
,"Connection to NK2015 failed, invalid password ?")
314 def lost(self
,serv
,channel
,forced
=False):
315 if self
.last_perdu
+config_time_between_perdu
<time
.time() or forced
:
316 if not channel
in self
.quiet_channels
or forced
:
317 serv
.privmsg(channel
,"J'ai perdu !")
318 self
.last_perdu
=time
.time()
319 delay
=config_time_between_perdu_trigger
320 delta
=config_time_between_perdu_trigger_delta
321 serv
.execute_delayed(random
.randrange(delay
-delta
,delay
+delta
),self
.lost
,(serv
,channel
))
323 def try_tamere(self
,serv
,channel
,auteur
,message
):
324 """Essaye de trigger un ta mère"""
325 #pas à chaque fois quand même
326 if random
.randrange(4)==0:
327 debuts
=u
"("+config_regexp_etre
+u
"|"+config_regexp_etre_avec_c
+u
")"
328 adjectifs
={u
"bon(|ne|s|nes)":u
"bonne",
329 u
"baisable(|s)":u
"baisable",
330 u
"faisable(|s)":u
"faisable",
331 u
"pas ch(ère(|s)|er(|s))":u
"pas chère",
332 u
"facile(|s)":u
"facile",
333 u
"chaud(|e|s|es)":u
"chaude",
334 u
"gratuit(|e|s|es)":u
"gratuite",
335 u
"payant(|e|s|es)":u
"payante",
336 u
"ouvert(|e|s|es)":u
"ouverte",
338 u
"plein(|s|es)":u
"pleine",
339 u
"bien plein(|e|s|es)":u
"bien pleine",
340 u
"innocent(|e|s|es)":u
"innocente"}
341 adj_reg
=u
"(?P<adjectif>"+u
"|".join(adjectifs
.keys())+u
")"
342 reg
=u
".*(^| |')"+debuts
+u
" "+adj_reg
+u
"($|,|;|\.| ).*"
343 matched
=re
.match(reg
,message
)
345 # il faut repasser l'adjectif au féminin singulier
346 found
=matched
.groupdict()["adjectif"]
347 for adj
in adjectifs
.keys():
348 if re
.match(adj
,found
):
349 adjectif
=adjectifs
[adj
]
351 serv
.privmsg(channel
,(u
"%s: c'est ta mère qui est %s !"%(auteur
,adjectif
)).encode("utf8"))
352 elif random
.randrange(5)==0:
353 # deuxième type de trigger, mais moins probable
354 matched
=re
.match(adj_reg
,message
)
356 found
=matched
.groupdict()["adjectif"]
357 for adj
in adjectifs
.keys():
358 if re
.match(adj
,found
):
359 adjectif
=adjectifs
[adj
]
361 fille
=random
.choice([u
"mère",u
"soœur"])
362 serv
.privmsg(channel
,(u
"%s: et ta %s, elle est %s ?"%
363 (auteur
,fille
,adjectif
)).encode("utf8"))
365 # troisième type de trigger
366 cpgt
=config_premier_groupe_terminaisons
367 verbes
={u
"tourn"+cpgt
:u
"tourne",
368 u
"balad"+cpgt
+u
" sur le trottoir":u
"se balade sur le trottoir",
369 u
"prom(e|è)n"+cpgt
+" sur le trottoir":u
"se promène sur le trottoir",
371 vb_reg
=u
".*(^| )(?P<verbe>"+"|".join(verbes
.keys())+")( |,|;|\.|$)"
372 matched
=re
.match(vb_reg
,message
)
374 found
=matched
.groupdict()["verbe"]
375 for vb
in verbes
.keys():
376 if re
.match(vb
,found
):
379 fille
=random
.choice([u
"mère",u
"soœur"])
380 serv
.privmsg(channel
,(u
"%s: et ta %s, elle %s ?"%
381 (auteur
,fille
,verbe
)).encode("utf8"))
382 def pourmoi(self
, serv
, message
):
383 """renvoie (False,lemessage) ou (True, le message amputé de "pseudo: ")"""
384 pseudo
=serv
.get_nickname()
386 if message
[:size
]==pseudo
and len(message
)>size
and message
[size
]==":":
387 return (True,message
[size
+1:].lstrip(" "))
389 return (False,message
)
391 def on_privmsg(self
, serv
, ev
):
392 message
=ev
.arguments()[0]
393 auteur
= irclib
.nm_to_n(ev
.source())
395 test
=bot_unicode(message
)
396 except UnicodeBotError
:
398 "Euh, tu fais de la merde avec ton encodage là, j'ai failli crasher…")
400 message
=message
.split()
401 cmd
=message
[0].lower()
404 if not len(message
) in [2,3]:
405 serv
.privmsg(auteur
,"Syntaxe : CONNECT [<username>] <password>")
409 username
=(message
[1])
410 password
=" ".join(message
[2:])
412 password
=" ".join(message
[1:])
413 success
,sock
=self
.new_connection_NK(serv
,username
,password
)
415 self
.sockets
[username
]=sock
416 serv
.privmsg(auteur
,"Connection successful")
417 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
419 serv
.privmsg(auteur
,"Connection failed")
420 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
423 helpdico
={"connect": """CONNECT [<username>] <password>
424 Ouvre une connexion au serveur NoteKfet.
425 Si <username> n'est pas précisé, j'utiliserais l'identité sous laquelle je te connais, ou, à défaut, ton pseudo.""",
426 "identify": """IDENTIFY <username> <password>
427 Vérifie le mot de passe et me permet de savoir à l'avenir quel est ton pseudo note kfet.
428 Sans paramètre, je réponds sous quel pseudo je te connais.""",
429 "drop":"""DROP <password>
430 Vérifie le mot de passe et me fait d'oublier ton pseudo note kfet."""}
431 helpmsg_default
="""Liste des commandes :
432 HELP Affiche de l'aide sur une commande.
433 CONNECT Ouvre une connection au serveur Note Kfet.
434 IDENTIFY Me permet de savoir qui tu es sur la note kfet.
435 DROP Me fait oublier ton identité.
436 SOLDE Obtenir ton solde"""
438 JOIN Faire rejoindre un chan
439 LEAVE Faire quitter un chan
440 QUIET Se taire sur un chan
441 NOQUIET Opposé de QUIET
442 LOST Perdre sur un chan
443 SOLDE <pseudo> Donner le solde de quelqu'un"""
445 SAY Fais envoyer un message sur un chan ou à une personne
446 STAY Ignorera les prochains LEAVE pour un chan
447 NOSTAY Opposé de STAY
450 helpmsg
=helpmsg_default
451 if auteur
in self
.ops
:
453 if auteur
in self
.overops
:
454 helpmsg
+=helpmsg_overops
456 helpmsg
=helpdico
.get(message
[1].lower(),"Commande inconnue.")
457 for ligne
in helpmsg
.split("\n"):
458 serv
.privmsg(auteur
,ligne
)
459 elif cmd
=="identify":
461 if self
.identities
.has_key(auteur
):
462 serv
.privmsg(auteur
,"Je te connais sous le pseudo note %s."%(
463 self
.identities
[auteur
].encode("utf8")))
465 serv
.privmsg(auteur
,"Je ne connais pas ton pseudo note.")
466 elif len(message
)>=3:
467 username
,password
=message
[1],unicode(" ".join(message
[2:]),"utf8")
468 success
,_
=self
.new_connection_NK(serv
,username
,password
)
470 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
471 serv
.privmsg(auteur
,"Identité enregistrée.")
472 self
.identities
[auteur
]=username
473 pickle
.dump(self
.identities
,open("identities.pickle","w"))
475 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
476 serv
.privmsg(auteur
,"Mot de passe invalide. (ou serveur down)")
478 serv
.privmsg(auteur
,u
"Syntaxe : IDENTIFY [<username> <password>]")
481 if self
.identities
.has_key(auteur
):
482 password
=" ".join(message
[1:])
483 success
,_
=self
.new_connection_NK(serv
,self
.identities
[auteur
],password
)
485 del self
.identities
[auteur
]
486 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
487 pickle
.dump(self
.identities
,open("identities.pickle","w"))
488 serv
.privmsg(auteur
,"Identité oubliée.")
490 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
491 serv
.privmsg(auteur
,"Mot de passe invalide. (ou serveur down)")
493 serv
.privmsg(auteur
,"Je ne connais pas ton pseudo note.")
495 serv
.privmsg(auteur
,"Syntaxe : DROP <password>")
497 if auteur
in self
.ops
:
499 if message
[1] in self
.chanlist
:
500 serv
.privmsg(auteur
,"Je suis déjà sur %s"%(message
[1]))
502 serv
.join(message
[1])
503 self
.chanlist
.append(message
[1])
504 serv
.privmsg(auteur
,"Channels : "+" ".join(self
.chanlist
))
505 log(self
.serveur
,"priv",auteur
," ".join(message
))
507 serv
.privmsg(auteur
,"Channels : "+" ".join(self
.chanlist
))
511 if auteur
in self
.ops
and len(message
)>1:
512 if message
[1] in self
.chanlist
:
513 if not (message
[1] in self
.stay_channels
) or auteur
in self
.overops
:
514 serv
.part(message
[1])
515 self
.chanlist
.remove(message
[1])
516 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
518 serv
.privmsg(auteur
,"Non, je reste !")
519 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
521 serv
.privmsg(auteur
,"Je ne suis pas sur %s"%(message
[1]))
525 if auteur
in self
.overops
:
527 if message
[1] in self
.stay_channels
:
528 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
529 serv
.privmsg(auteur
,"Je stay déjà sur %s."%(message
[1]))
531 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
532 self
.stay_channels
.append(message
[1])
533 serv
.privmsg(auteur
,"Stay channels : "+" ".join(self
.stay_channels
))
535 serv
.privmsg(auteur
,"Stay channels : "+" ".join(self
.stay_channels
))
539 if auteur
in self
.overops
:
541 if message
[1] in self
.stay_channels
:
542 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
543 self
.stay_channels
.remove(message
[1])
544 serv
.privmsg(auteur
,"Stay channels : "+" ".join(self
.stay_channels
))
546 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
547 serv
.privmsg(auteur
,"Je ne stay pas sur %s."%(message
[1]))
552 if auteur
in self
.overops
:
553 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
558 if auteur
in self
.ops
:
560 if message
[1] in self
.quiet_channels
:
561 serv
.privmsg(auteur
,"Je me la ferme déjà sur %s"%(message
[1]))
562 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
564 self
.quiet_channels
.append(message
[1])
565 serv
.privmsg(auteur
,"Quiet channels : "+" ".join(self
.quiet_channels
))
566 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
568 serv
.privmsg(auteur
,"Quiet channels : "+" ".join(self
.quiet_channels
))
572 if auteur
in self
.ops
:
574 if message
[1] in self
.quiet_channels
:
575 self
.quiet_channels
.remove(message
[1])
576 serv
.privmsg(auteur
,"Quiet channels : "+" ".join(self
.quiet_channels
))
577 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
579 serv
.privmsg(auteur
,"Je ne me la ferme pas sur %s."%(message
[1]))
580 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
584 if auteur
in self
.overops
and len(message
)>2:
585 serv
.privmsg(message
[1]," ".join(message
[2:]))
586 log(self
.serveur
,"priv",auteur
," ".join(message
))
587 elif len(message
)<=2:
588 serv
.privmsg(auteur
,"Syntaxe : SAY <channel> <message>")
592 if auteur
in self
.ops
and len(message
)>1:
593 serv
.privmsg(message
[1],"J'ai perdu !")
594 log(self
.serveur
,"priv",auteur
," ".join(message
))
595 elif len(message
)<=1:
596 serv
.privmsg(auteur
,"Syntaxe : LOST <channel>")
601 if self
.identities
.has_key(auteur
):
603 self
.nk
.write('search ["x",["pseudo"],%s]'%(json
.dumps(auteur
)))
604 ret
=json
.loads(self
.nk
.read())
605 solde
=ret
["msg"][0]["solde"]
606 pseudo
=ret
["msg"][0]["pseudo"]
607 except Exception as exc
:
608 serv
.privmsg(auteur
,"failed")
609 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
611 serv
.privmsg(auteur
,"%s (%s)"%(float(solde
)/100,pseudo
.encode("utf8")))
613 serv
.privmsg(canal
,"Je ne connais pas ton pseudo note.")
614 elif auteur
in self
.ops
:
616 self
.nk
.write('search ["x",["pseudo"],%s]'%(json
.dumps(message
[1])))
617 ret
=json
.loads(self
.nk
.read())
618 solde
=ret
["msg"][0]["solde"]
619 pseudo
=ret
["msg"][0]["pseudo"]
620 except Exception as exc
:
621 serv
.privmsg(auteur
,"failed")
622 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
624 serv
.privmsg(auteur
,"%s (%s)"%(float(solde
)/100,pseudo
.encode("utf8")))
628 serv
.privmsg(auteur
,"Je n'ai pas compris. Essaye HELP…")
630 def on_pubmsg(self
, serv
, ev
):
631 auteur
= irclib
.nm_to_n(ev
.source())
633 message
= ev
.arguments()[0]
635 test
=bot_unicode(message
)
636 except UnicodeBotError
:
637 if not canal
in self
.quiet_channels
:
639 "%s: Euh, tu fais de la merde avec ton encodage là, j'ai failli crasher…"%(auteur))
641 pour_moi
,message
=self
.pourmoi(serv
,message
)
642 if pour_moi
and message
.split()!=[]:
643 cmd
=message
.split()[0].lower()
645 args
=" ".join(message
.split()[1:])
648 if cmd
in ["meurs","die","crève"]:
649 if auteur
in self
.overops
:
650 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
653 serv
.privmsg(canal
,"%s: crève !"%(auteur))
654 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
656 elif cmd
in ["part","leave","dégage"]:
657 if auteur
in self
.ops
and (not (canal
in self
.stay_channels
)
658 or auteur
in self
.overops
):
659 serv
.part(canal
,message
="Éjecté par %s"%(auteur))
660 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
662 serv
.privmsg(canal
,"%s: Non, je reste !"%(auteur))
663 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
665 elif cmd
in ["reconnect"]:
666 if auteur
in self
.ops
:
668 self
.nk
=self
.new_connection_NK(serv
,config_note_pseudo
,
669 config_note_password
,"special")[1]
670 except Exception as exc
:
672 log(self
.serveur
,"""Erreur dans on_pubmsg/"cmd in ["reconnect"]\n"""+str(exc
))
674 serv
.privmsg(canal
,"%s: done"%(auteur))
675 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
677 serv
.privmsg(canal
,"%s: failed"%(auteur))
678 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
679 for report
in self
.report_bugs_to
:
680 serv
.privmsg(report
,"Connection to NK2015 failed, invalid password ?")
682 serv
.privmsg(canal
,"%s: crève !"%(auteur))
683 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
685 elif cmd
in ["deviens","pseudo"]:
686 if auteur
in self
.ops
:
689 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
691 elif cmd
in ["coucou"] and not canal
in self
.quiet_channels
:
692 serv
.privmsg(canal
,"%s: coucou"%(auteur))
693 elif cmd
in ["ping"] and not canal
in self
.quiet_channels
:
694 serv
.privmsg(canal
,"%s: pong"%(auteur))
696 elif cmd
in ["solde","!solde"]:
697 if self
.identities
.has_key(auteur
):
698 pseudo
=self
.identities
[auteur
]
700 self
.nk
.write('search ["x",["pseudo"],%s]'%(json
.dumps(pseudo
)))
701 ret
=json
.loads(self
.nk
.read())
702 solde
=ret
["msg"][0]["solde"]
703 pseudo
=ret
["msg"][0]["pseudo"]
704 except Exception as exc
:
705 serv
.privmsg(canal
,"%s: failed"%(auteur))
706 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
708 serv
.privmsg(canal
,"%s: %s (%s)"%(auteur
,float(solde
)/100,pseudo
.encode("utf8")))
709 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
711 serv
.privmsg(canal
,"%s: Je ne connais pas ton pseudo note."%(auteur))
712 log(self
.serveur
,canal
,auteur
,message
+"[unknown]")
713 elif (re
.match("!?(pain au chocolat|chocolatine)",message
.lower())
714 and not canal
in self
.quiet_channels
):
715 serv
.action(canal
,"sert un pain au chocolat à %s"%(auteur))
716 elif re
.match("!?manzana",message
.lower()) and not canal
in self
.quiet_channels
:
717 if auteur
=="[20-100]":
718 serv
.action(canal
,"sert une bouteille de manzana à %s"%(auteur))
720 serv
.action(canal
,"sert un verre de manzana à %s"%(auteur))
721 if is_insult(message
) and not canal
in self
.quiet_channels
:
722 if is_not_insult(message
):
723 answer
=random
.choice(config_compliment_answers
)
724 for ligne
in answer
.split("\n"):
725 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
727 answer
=random
.choice(config_insultes_answers
)
728 for ligne
in answer
.split("\n"):
729 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
730 if is_gros(message
) and not canal
in self
.quiet_channels
:
731 taille
=get_filesize()
732 answer
=u
"Mais non, je ne suis pas gros, %sKo tout au plus…"%(taille)
733 serv
.privmsg(canal
,"%s: %s"%(auteur
,answer
.encode("utf8")))
734 if is_tesla(message
) and not canal
in self
.quiet_channels
:
735 l1
,l2
=config_tesla_answers
,config_tesla_actions
736 n1
,n2
=len(l1
),len(l2
)
737 i
=random
.randrange(n1
+n2
)
739 serv
.action(canal
,l2
[i
-n1
])
741 serv
.privmsg(canal
,"%s: %s"%(auteur
,l1
[i
].encode("utf8")))
742 if is_tamere(message
) and not canal
in self
.quiet_channels
:
743 answer
=random
.choice(config_tamere_answers
)
744 for ligne
in answer
.split("\n"):
745 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
746 if is_tag(message
) and not canal
in self
.quiet_channels
:
747 if auteur
in self
.ops
:
748 action
=random
.choice(config_tag_actions
)
749 serv
.action(canal
,action
.encode("utf8"))
750 self
.quiet_channels
.append(canal
)
752 answer
=random
.choice(config_tag_answers
)
753 for ligne
in answer
.split("\n"):
754 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
755 if is_merci(message
):
756 answer
=random
.choice(config_merci_answers
)
757 for ligne
in answer
.split("\n"):
758 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
759 out
=re
.match(u
"^([A-Z[]|\\|[0-9]+|(¹|²|³|⁴|⁵|⁶|⁷|⁸|⁹|⁰)+)(?:| \?| !)$",
760 unicode(message
.upper(),"utf8"))
761 if out
and not canal
in self
.quiet_channels
:
765 serv
.privmsg(canal
,"%s: %s !"%(auteur
,out
+1))
766 if out
+1>1000 and random
.randrange(4)==0:
767 serv
.privmsg(canal
,"%s: Tu sais, je peux continuer longtemps comme ça…"%(auteur))
769 serv
.privmsg(canal
,"%s: Tu croyais m'avoir sur le maxint ? J'suis en python mon vieux, 'va falloir trouver mieux…"%(auteur))
771 except Exception as exc
:
773 if re
.match("[A-Y]",out
):
774 alphabet
="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
775 serv
.privmsg(canal
,"%s: %s !"%(auteur
,alphabet
[alphabet
.index(out
)+1]))
777 serv
.privmsg(canal
,"%s: pfff, j'ai l'air malin maintenant… [ ?"%(auteur))
779 serv
.privmsg(canal
,"%s: nan mais il faut qu'on arrête, ça va finir par poser des problèmes…"%(auteur))
780 elif re
.match(r
"(¹|²|³|⁴|⁵|⁶|⁷|⁸|⁹|⁰)+",out
):
782 return "".join([{u
"⁰¹²³⁴⁵⁶⁷⁸⁹0123456789"[i
]:u
"0123456789⁰¹²³⁴⁵⁶⁷⁸⁹"[i
]
783 for i
in range(20)}[j
]
785 out
=int(translate(out
))
786 serv
.privmsg(canal
,"%s: %s !"%(auteur
,translate(str(out
+1)).encode("utf8")))
787 if (not canal
in self
.quiet_channels
788 and re
.match((u
"^("+"|".join(config_bonjour
)+").*").lower(),message
.lower()) ):
789 answer
=random
.choice(config_bonjour_answers
)
790 serv
.privmsg(canal
,answer
.format(auteur
).encode("utf8"))
792 serv
.privmsg(canal
,"%s: c'est pas sur moi qu'il faut tirer !"%(auteur))
794 if message
in ["!pain au chocolat","!chocolatine"] and not canal
in self
.quiet_channels
:
795 serv
.action(canal
,"sert un pain au chocolat à %s"%(auteur))
796 if message
in ["!manzana"] and not canal
in self
.quiet_channels
:
797 if auteur
=="[20-100]":
798 serv
.action(canal
,"sert une bouteille de manzana à %s"%(auteur))
800 serv
.action(canal
,"sert un verre de manzana à %s"%(auteur))
801 if re
.match('^(.|§|:|)(w|b) [0-9]+$',message
) and not canal
in self
.quiet_channels
:
802 failanswers
=config_buffer_fail_answers
803 answer
=random
.choice(failanswers
)
804 serv
.privmsg(canal
,"%s: %s"%(auteur
,answer
))
805 if not canal
in self
.quiet_channels
:
806 self
.try_tamere(serv
,canal
,auteur
,message
)
807 mypseudo
=serv
.get_nickname()
808 if re
.match((u
"^("+u
"|".join(config_bonjour
)
809 +u
")( {}| all| tout le monde|(|à) tous)(\.|( |)!|)$"
810 ).format(mypseudo
).lower(), message
.strip().lower()):
811 answer
=random
.choice(config_bonjour_answers
)
812 serv
.privmsg(canal
,answer
.format(auteur
).encode("utf8"))
813 if (is_perdu(message
) and not canal
in self
.quiet_channels
):
814 # proba de perdre sur trigger :
815 # avant 30min (enfin, config) : 0
816 # ensuite, +25%/30min, linéairement
817 deltat
=time
.time()-self
.last_perdu
818 barre
=(deltat
-config_time_between_perdu
)/(2*3600.0)
819 if random
.uniform(0,1)<barre
:
820 serv
.privmsg(canal
,"%s: J'ai perdu !"%(auteur))
821 self
.last_perdu
=time
.time()
823 def on_action(self
, serv
, ev
):
824 action
= ev
.arguments()[0]
825 auteur
= irclib
.nm_to_n(ev
.source())
826 channel
= ev
.target()
827 mypseudo
=serv
.get_nickname()
828 if is_action_trigger(action
,mypseudo
):
829 l1
,l2
=config_action_answers
,config_action_actions
830 n1
,n2
=len(l1
),len(l2
)
831 i
=random
.randrange(n1
+n2
)
833 serv
.action(channel
,l2
[i
-n1
])
835 serv
.privmsg(channel
,"%s: %s"%(auteur
,l1
[i
].encode("utf8")))
837 if __name__
=="__main__":
840 print "Usage : basile.py <serveur> [--debug]"
843 if "debug" in sys
.argv
or "--debug" in sys
.argv
:
847 serveurs
={"a♡":"acoeur.crans.org","acoeur":"acoeur.crans.org","acoeur.crans.org":"acoeur.crans.org",
848 "irc":"irc.crans.org","crans":"irc.crans.org","irc.crans.org":"irc.crans.org"}
850 serveur
=serveurs
[serveur
]
852 print "Server Unknown : %s"%(serveur)
854 basile
=Basile(serveur
,debug
)