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|dégomme|fouette|agresse)",
113 u
"vomit sur",u
"slap(|s)"]
114 config_action_answers
=[u
"Hey ! Mais qu'est-ce que j'ai fait ?",
117 u
"Mais j'ai rien demandé moi !"]
118 config_action_actions
=[u
"prend de la distance, par précaution…",u
"part en courant",u
"esquive"]
120 config_bonjour
=[u
"(s|)(a|'|)lu(t|)",u
"hello",u
"plop",u
"plip",u
"pr(ou|ü)t",u
"bonjour",u
"bonsoir"]
121 config_bonjour_answers
=[u
"Salut {}",u
"Hello {} :)",u
"Bonjour {}",u
"Hello {}",u
"{}: hello",u
"{}: bonjour"]
124 config_thisfile
= os
.path
.realpath( __file__
)
126 return ex("ls -s %s"%(config_thisfile))[1].split()[0]
128 class NKError(Exception):
129 def __init__(self
,msg
):
130 Exception.__init
__(self
)
134 def __unicode__(self
):
135 return unicode(self
.msg
)
137 class NKRefused(NKError
):
140 class NKHelloFailed(NKError
):
143 class NKUnknownError(NKError
):
146 def log(serveur
,channel
,auteur
=None,message
=None):
147 f
=open(get_config_logfile(serveur
),"a")
148 if auteur
==message
==None:
149 # alors c'est que c'est pas un channel mais juste une ligne de log
150 chain
="%s %s"%(time
.strftime("%F %T"),channel
)
152 chain
="%s [%s:%s] %s"%(time
.strftime("%F %T"),channel
,auteur
,message
)
154 if config_debug_stdout
:
161 # On établit la connexion sur port 4242
162 sock
.connect(("127.0.0.1",4242))
164 sock
=ssl
.wrap_socket(sock
,ca_certs
='../keys/ca_.crt')
166 sock
.write('hello "Basile"')
167 # On récupère la réponse du hello
170 except Exception as exc
:
171 # Si on a foiré quelque part, c'est que le serveur est down
172 raise NKRefused(str(exc
))
173 if out
["retcode"]==0:
175 elif out
["retcode"]==11:
176 raise NKHelloFailed(out
["errmsg"])
178 raise NKUnknownError(out
["errmsg"])
180 def login_NK(username
,password
,typ
="bdd"):
182 if typ
=="special": # ça c'est pour Basile lui-même
185 masque
='[["all"],["all"],false]'
187 # Basile a un compte special user
188 commande
='login [%s,%s,"%s",%s]'%(json
.dumps(username
),json
.dumps(password
),typ
,masque
)
191 except Exception as exc
:
192 # Si on a foiré quelque part, c'est que le serveur est down
193 raise NKRefused(str(exc
))
194 # On vérifie ensuite que le login
195 return json
.loads(out
),sock
198 def is_something(chain
,matches
,avant
=u
".*(^| )",apres
=u
"($|\.| |,|;).*",case_sensitive
=False,debug
=False):
200 chain
=unicode(chain
,"utf8")
202 chain
=unicode(chain
,"utf8").lower()
203 allmatches
="("+"|".join(matches
)+")"
204 reg
=(avant
+allmatches
+apres
).lower()
205 if re
.match(reg
,chain
):
209 def is_insult(chain
,debug
=True):
210 return is_something(chain
,config_insultes
,avant
=".*(^| |')")
211 def is_not_insult(chain
):
212 chain
=unicode(chain
,"utf8")
213 insult_regexp
=u
"("+u
"|".join(config_insultes
)+u
")"
214 middle_regexp
=u
"(un(|e) ((putain|enfoiré) d(e |'))*|)(| super )( (gros|petit|grand|énorme) |)"
215 reg
=".*pas %s%s.*"%(middle_regexp
,insult_regexp
)
216 if re
.match(reg
,chain
):
221 return is_something(chain
,config_perdu
)
223 return is_something(chain
,config_tag
)
225 return is_something(chain
,config_gros
)
227 return is_something(chain
,config_tesla
,avant
=u
"^",apres
=u
"$",debug
=True)
229 return is_something(chain
,config_merci
)
230 def is_tamere(chain
):
231 return is_something(chain
,config_tamere
)
232 def is_action_trigger(chain
,pseudo
):
233 return is_something(chain
,config_action_trigger
,avant
=u
"^",apres
=" %s($|\.| |,|;).*"%(pseudo))
235 return re
.match(u
"^(pan|bim|bang)$",unicode(chain
,"utf8").lower().strip())
239 class UnicodeBotError(Exception):
241 def bot_unicode(chain
):
243 unicode(chain
,"utf8")
244 except UnicodeDecodeError as exc
:
245 raise UnicodeBotError
247 class Basile(ircbot
.SingleServerIRCBot
):
248 def __init__(self
,serveur
,debug
=False):
249 temporary_pseudo
=config_irc_pseudo
+str(random
.randrange(10000,100000))
250 ircbot
.SingleServerIRCBot
.__init
__(self
, [(serveur
, 6667)],
251 temporary_pseudo
,"Basile, le bot irc.[Codé par 20-100, fouettez-le]", 10)
254 self
.overops
=config_overops
255 self
.ops
=self
.overops
+config_ops
256 self
.report_bugs_to
=config_report_bugs_to
257 self
.chanlist
=config_chanlist
259 self
.identities
=pickle
.load(open("identities.pickle","r"))
260 self
.stay_channels
=config_stay_channels
261 self
.quiet_channels
=config_quiet_channels
265 def new_connection_NK(self
,serv
,username
,password
,typ
="bdd"):
267 login_result
,sock
=login_NK(username
,password
,typ
)
268 droits
,retcode
,errmsg
=login_result
["msg"],login_result
["retcode"],login_result
["errmsg"]
269 except NKRefused
as exc
:
270 for report
in self
.report_bugs_to
:
271 serv
.privmsg(report
,"Le Serveur NK2015 est down.")
273 except NKHelloFailed
as exc
:
274 for report
in self
.report_bugs_to
:
276 "La version du site utilisée n'est pas supportée par le serveur NK2015.")
278 except NKUnknownError
as exc
:
279 erreurs
=["Une fucking erreur inconnue s'est produite"]
280 erreurs
+=str(exc
).split("\n")
281 for report
in self
.report_bugs_to
:
283 serv
.privmsg(report
,err
)
285 except Exception as exc
:
286 # Exception qui ne vient pas de la communication avec le serveur NK2015
287 log(self
.serveur
,"Erreur dans new_connection_NK\n"+str(exc
))
294 def give_me_my_pseudo(self
,serv
):
295 serv
.privmsg("NickServ","RECOVER %s %s"%(config_irc_pseudo
,config_irc_password
))
296 serv
.privmsg("NickServ","RELEASE %s %s"%(config_irc_pseudo
,config_irc_password
))
298 serv
.nick(config_irc_pseudo
)
300 def on_welcome(self
, serv
, ev
):
301 self
.give_me_my_pseudo(serv
)
302 serv
.privmsg("NickServ","identify %s"%(config_irc_password))
303 log(self
.serveur
,"Connected")
305 self
.chanlist
=["#bot"]
306 for c
in self
.chanlist
:
307 log(self
.serveur
,"JOIN %s"%(c))
309 # on ouvre la connexion note de Basile, special user
310 self
.nk
=self
.new_connection_NK(serv
,config_note_pseudo
,config_note_password
,"special")[1]
312 for report
in self
.report_bugs_to
:
313 serv
.privmsg(report
,"Connection to NK2015 failed, invalid password ?")
315 def lost(self
,serv
,channel
,forced
=False):
316 if self
.last_perdu
+config_time_between_perdu
<time
.time() or forced
:
317 if not channel
in self
.quiet_channels
or forced
:
318 serv
.privmsg(channel
,"J'ai perdu !")
319 self
.last_perdu
=time
.time()
320 delay
=config_time_between_perdu_trigger
321 delta
=config_time_between_perdu_trigger_delta
322 serv
.execute_delayed(random
.randrange(delay
-delta
,delay
+delta
),self
.lost
,(serv
,channel
))
324 def try_tamere(self
,serv
,channel
,auteur
,message
):
325 """Essaye de trigger un ta mère"""
326 #pas à chaque fois quand même
327 if random
.randrange(4)==0:
328 debuts
=u
"("+config_regexp_etre
+u
"|"+config_regexp_etre_avec_c
+u
")"
329 adjectifs
={u
"bon(|ne|s|nes)":u
"bonne",
330 u
"baisable(|s)":u
"baisable",
331 u
"faisable(|s)":u
"faisable",
332 u
"pas ch(ère(|s)|er(|s))":u
"pas chère",
333 u
"facile(|s)":u
"facile",
334 u
"chaud(|e|s|es)":u
"chaude",
335 u
"gratuit(|e|s|es)":u
"gratuite",
336 u
"payant(|e|s|es)":u
"payante",
337 u
"ouvert(|e|s|es)":u
"ouverte",
339 u
"plein(|s|es)":u
"pleine",
340 u
"bien plein(|e|s|es)":u
"bien pleine",
341 u
"innocent(|e|s|es)":u
"innocente"}
342 adj_reg
=u
"(?P<adjectif>"+u
"|".join(adjectifs
.keys())+u
")"
343 reg
=u
".*(^| |')"+debuts
+u
" "+adj_reg
+u
"($|,|;|\.| ).*"
344 matched
=re
.match(reg
,message
)
346 # il faut repasser l'adjectif au féminin singulier
347 found
=matched
.groupdict()["adjectif"]
348 for adj
in adjectifs
.keys():
349 if re
.match(adj
,found
):
350 adjectif
=adjectifs
[adj
]
352 serv
.privmsg(channel
,(u
"%s: c'est ta mère qui est %s !"%(auteur
,adjectif
)).encode("utf8"))
353 elif random
.randrange(5)==0:
354 # deuxième type de trigger, mais moins probable
355 matched
=re
.match(adj_reg
,message
)
357 found
=matched
.groupdict()["adjectif"]
358 for adj
in adjectifs
.keys():
359 if re
.match(adj
,found
):
360 adjectif
=adjectifs
[adj
]
362 fille
=random
.choice([u
"mère",u
"soœur"])
363 serv
.privmsg(channel
,(u
"%s: et ta %s, elle est %s ?"%
364 (auteur
,fille
,adjectif
)).encode("utf8"))
366 # troisième type de trigger
367 cpgt
=config_premier_groupe_terminaisons
368 verbes
={u
"tourn"+cpgt
:u
"tourne",
369 u
"balad"+cpgt
+u
" sur le trottoir":u
"se balade sur le trottoir",
370 u
"prom(e|è)n"+cpgt
+" sur le trottoir":u
"se promène sur le trottoir",
372 vb_reg
=u
".*(^| )(?P<verbe>"+"|".join(verbes
.keys())+")( |,|;|\.|$)"
373 matched
=re
.match(vb_reg
,message
)
375 found
=matched
.groupdict()["verbe"]
376 for vb
in verbes
.keys():
377 if re
.match(vb
,found
):
380 fille
=random
.choice([u
"mère",u
"soœur"])
381 serv
.privmsg(channel
,(u
"%s: et ta %s, elle %s ?"%
382 (auteur
,fille
,verbe
)).encode("utf8"))
383 def pourmoi(self
, serv
, message
):
384 """renvoie (False,lemessage) ou (True, le message amputé de "pseudo: ")"""
385 pseudo
=serv
.get_nickname()
387 if message
[:size
]==pseudo
and len(message
)>size
and message
[size
]==":":
388 return (True,message
[size
+1:].lstrip(" "))
390 return (False,message
)
392 def on_privmsg(self
, serv
, ev
):
393 message
=ev
.arguments()[0]
394 auteur
= irclib
.nm_to_n(ev
.source())
396 test
=bot_unicode(message
)
397 except UnicodeBotError
:
399 "Euh, tu fais de la merde avec ton encodage là, j'ai failli crasher…")
401 message
=message
.split()
402 cmd
=message
[0].lower()
405 if not len(message
) in [2,3]:
406 serv
.privmsg(auteur
,"Syntaxe : CONNECT [<username>] <password>")
410 username
=(message
[1])
411 password
=" ".join(message
[2:])
413 password
=" ".join(message
[1:])
414 success
,sock
=self
.new_connection_NK(serv
,username
,password
)
416 self
.sockets
[username
]=sock
417 serv
.privmsg(auteur
,"Connection successful")
418 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
420 serv
.privmsg(auteur
,"Connection failed")
421 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
424 helpdico
={"connect": """CONNECT [<username>] <password>
425 Ouvre une connexion au serveur NoteKfet.
426 Si <username> n'est pas précisé, j'utiliserais l'identité sous laquelle je te connais, ou, à défaut, ton pseudo.""",
427 "identify": """IDENTIFY <username> <password>
428 Vérifie le mot de passe et me permet de savoir à l'avenir quel est ton pseudo note kfet.
429 Sans paramètre, je réponds sous quel pseudo je te connais.""",
430 "drop":"""DROP <password>
431 Vérifie le mot de passe et me fait d'oublier ton pseudo note kfet."""}
432 helpmsg_default
="""Liste des commandes :
433 HELP Affiche de l'aide sur une commande.
434 CONNECT Ouvre une connection au serveur Note Kfet.
435 IDENTIFY Me permet de savoir qui tu es sur la note kfet.
436 DROP Me fait oublier ton identité.
437 SOLDE Obtenir ton solde"""
439 JOIN Faire rejoindre un chan
440 LEAVE Faire quitter un chan
441 QUIET Se taire sur un chan
442 NOQUIET Opposé de QUIET
443 LOST Perdre sur un chan
444 SOLDE <pseudo> Donner le solde de quelqu'un"""
446 SAY Fait envoyer un message sur un chan ou à une personne
447 STAY Ignorera les prochains LEAVE pour un chan
448 NOSTAY Opposé de STAY
451 helpmsg
=helpmsg_default
452 if auteur
in self
.ops
:
454 if auteur
in self
.overops
:
455 helpmsg
+=helpmsg_overops
457 helpmsg
=helpdico
.get(message
[1].lower(),"Commande inconnue.")
458 for ligne
in helpmsg
.split("\n"):
459 serv
.privmsg(auteur
,ligne
)
460 elif cmd
=="identify":
462 if self
.identities
.has_key(auteur
):
463 serv
.privmsg(auteur
,"Je te connais sous le pseudo note %s."%(
464 self
.identities
[auteur
].encode("utf8")))
466 serv
.privmsg(auteur
,"Je ne connais pas ton pseudo note.")
467 elif len(message
)>=3:
468 username
,password
=message
[1],unicode(" ".join(message
[2:]),"utf8")
469 success
,_
=self
.new_connection_NK(serv
,username
,password
)
471 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
472 serv
.privmsg(auteur
,"Identité enregistrée.")
473 self
.identities
[auteur
]=username
474 pickle
.dump(self
.identities
,open("identities.pickle","w"))
476 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
477 serv
.privmsg(auteur
,"Mot de passe invalide. (ou serveur down)")
479 serv
.privmsg(auteur
,u
"Syntaxe : IDENTIFY [<username> <password>]")
482 if self
.identities
.has_key(auteur
):
483 password
=" ".join(message
[1:])
484 success
,_
=self
.new_connection_NK(serv
,self
.identities
[auteur
],password
)
486 del self
.identities
[auteur
]
487 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
488 pickle
.dump(self
.identities
,open("identities.pickle","w"))
489 serv
.privmsg(auteur
,"Identité oubliée.")
491 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
492 serv
.privmsg(auteur
,"Mot de passe invalide. (ou serveur down)")
494 serv
.privmsg(auteur
,"Je ne connais pas ton pseudo note.")
496 serv
.privmsg(auteur
,"Syntaxe : DROP <password>")
498 if auteur
in self
.ops
:
500 if message
[1] in self
.chanlist
:
501 serv
.privmsg(auteur
,"Je suis déjà sur %s"%(message
[1]))
503 serv
.join(message
[1])
504 self
.chanlist
.append(message
[1])
505 serv
.privmsg(auteur
,"Channels : "+" ".join(self
.chanlist
))
506 log(self
.serveur
,"priv",auteur
," ".join(message
))
508 serv
.privmsg(auteur
,"Channels : "+" ".join(self
.chanlist
))
512 if auteur
in self
.ops
and len(message
)>1:
513 if message
[1] in self
.chanlist
:
514 if not (message
[1] in self
.stay_channels
) or auteur
in self
.overops
:
515 serv
.part(message
[1])
516 self
.chanlist
.remove(message
[1])
517 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
519 serv
.privmsg(auteur
,"Non, je reste !")
520 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
522 serv
.privmsg(auteur
,"Je ne suis pas sur %s"%(message
[1]))
526 if auteur
in self
.overops
:
528 if message
[1] in self
.stay_channels
:
529 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
530 serv
.privmsg(auteur
,"Je stay déjà sur %s."%(message
[1]))
532 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
533 self
.stay_channels
.append(message
[1])
534 serv
.privmsg(auteur
,"Stay channels : "+" ".join(self
.stay_channels
))
536 serv
.privmsg(auteur
,"Stay channels : "+" ".join(self
.stay_channels
))
540 if auteur
in self
.overops
:
542 if message
[1] in self
.stay_channels
:
543 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
544 self
.stay_channels
.remove(message
[1])
545 serv
.privmsg(auteur
,"Stay channels : "+" ".join(self
.stay_channels
))
547 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
548 serv
.privmsg(auteur
,"Je ne stay pas sur %s."%(message
[1]))
553 if auteur
in self
.overops
:
554 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
559 if auteur
in self
.ops
:
561 if message
[1] in self
.quiet_channels
:
562 serv
.privmsg(auteur
,"Je me la ferme déjà sur %s"%(message
[1]))
563 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
565 self
.quiet_channels
.append(message
[1])
566 serv
.privmsg(auteur
,"Quiet channels : "+" ".join(self
.quiet_channels
))
567 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
569 serv
.privmsg(auteur
,"Quiet channels : "+" ".join(self
.quiet_channels
))
573 if auteur
in self
.ops
:
575 if message
[1] in self
.quiet_channels
:
576 self
.quiet_channels
.remove(message
[1])
577 serv
.privmsg(auteur
,"Quiet channels : "+" ".join(self
.quiet_channels
))
578 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
580 serv
.privmsg(auteur
,"Je ne me la ferme pas sur %s."%(message
[1]))
581 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
585 if auteur
in self
.overops
and len(message
)>2:
586 serv
.privmsg(message
[1]," ".join(message
[2:]))
587 log(self
.serveur
,"priv",auteur
," ".join(message
))
588 elif len(message
)<=2:
589 serv
.privmsg(auteur
,"Syntaxe : SAY <channel> <message>")
593 if auteur
in self
.ops
and len(message
)>1:
594 serv
.privmsg(message
[1],"J'ai perdu !")
595 log(self
.serveur
,"priv",auteur
," ".join(message
))
596 elif len(message
)<=1:
597 serv
.privmsg(auteur
,"Syntaxe : LOST <channel>")
602 if self
.identities
.has_key(auteur
):
604 self
.nk
.write('search ["x",["pseudo"],%s]'%(json
.dumps(self
.identities
[auteur
])))
605 ret
=json
.loads(self
.nk
.read())
606 solde
=ret
["msg"][0]["solde"]
607 pseudo
=ret
["msg"][0]["pseudo"]
608 except Exception as exc
:
610 serv
.privmsg(auteur
,"failed")
611 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
613 serv
.privmsg(auteur
,"%s (%s)"%(float(solde
)/100,pseudo
.encode("utf8")))
615 serv
.privmsg(canal
,"Je ne connais pas ton pseudo note.")
616 elif auteur
in self
.ops
:
618 self
.nk
.write('search ["x",["pseudo"],%s]'%(json
.dumps(message
[1])))
619 ret
=json
.loads(self
.nk
.read())
620 solde
=ret
["msg"][0]["solde"]
621 pseudo
=ret
["msg"][0]["pseudo"]
622 except Exception as exc
:
623 serv
.privmsg(auteur
,"failed")
624 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
626 serv
.privmsg(auteur
,"%s (%s)"%(float(solde
)/100,pseudo
.encode("utf8")))
630 serv
.privmsg(auteur
,"Je n'ai pas compris. Essaye HELP…")
632 def on_pubmsg(self
, serv
, ev
):
633 auteur
= irclib
.nm_to_n(ev
.source())
635 message
= ev
.arguments()[0]
637 test
=bot_unicode(message
)
638 except UnicodeBotError
:
639 if not canal
in self
.quiet_channels
:
641 "%s: Euh, tu fais de la merde avec ton encodage là, j'ai failli crasher…"%(auteur))
643 pour_moi
,message
=self
.pourmoi(serv
,message
)
644 if pour_moi
and message
.split()!=[]:
645 cmd
=message
.split()[0].lower()
647 args
=" ".join(message
.split()[1:])
650 if cmd
in ["meurs","die","crève"]:
651 if auteur
in self
.overops
:
652 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
655 serv
.privmsg(canal
,"%s: crève !"%(auteur))
656 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
658 elif cmd
in ["part","leave","dégage"]:
659 if auteur
in self
.ops
and (not (canal
in self
.stay_channels
)
660 or auteur
in self
.overops
):
661 serv
.part(canal
,message
="Éjecté par %s"%(auteur))
662 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
664 serv
.privmsg(canal
,"%s: Non, je reste !"%(auteur))
665 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
667 elif cmd
in ["reconnect"]:
668 if auteur
in self
.ops
:
670 self
.nk
=self
.new_connection_NK(serv
,config_note_pseudo
,
671 config_note_password
,"special")[1]
672 except Exception as exc
:
674 log(self
.serveur
,"""Erreur dans on_pubmsg/"cmd in ["reconnect"]\n"""+str(exc
))
676 serv
.privmsg(canal
,"%s: done"%(auteur))
677 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
679 serv
.privmsg(canal
,"%s: failed"%(auteur))
680 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
681 for report
in self
.report_bugs_to
:
682 serv
.privmsg(report
,"Connection to NK2015 failed, invalid password ?")
684 serv
.privmsg(canal
,"%s: crève !"%(auteur))
685 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
687 elif cmd
in ["deviens","pseudo"]:
688 if auteur
in self
.ops
:
691 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
693 elif cmd
in ["coucou"] and not canal
in self
.quiet_channels
:
694 serv
.privmsg(canal
,"%s: coucou"%(auteur))
695 elif cmd
in ["ping"] and not canal
in self
.quiet_channels
:
696 serv
.privmsg(canal
,"%s: pong"%(auteur))
698 elif cmd
in ["solde","!solde"]:
699 if self
.identities
.has_key(auteur
):
700 pseudo
=self
.identities
[auteur
]
702 self
.nk
.write('search ["x",["pseudo"],%s]'%(json
.dumps(pseudo
)))
703 ret
=json
.loads(self
.nk
.read())
704 solde
=ret
["msg"][0]["solde"]
705 pseudo
=ret
["msg"][0]["pseudo"]
706 except Exception as exc
:
707 serv
.privmsg(canal
,"%s: failed"%(auteur))
708 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
710 serv
.privmsg(canal
,"%s: %s (%s)"%(auteur
,float(solde
)/100,pseudo
.encode("utf8")))
711 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
713 serv
.privmsg(canal
,"%s: Je ne connais pas ton pseudo note."%(auteur))
714 log(self
.serveur
,canal
,auteur
,message
+"[unknown]")
715 elif (re
.match("!?(pain au chocolat|chocolatine)",message
.lower())
716 and not canal
in self
.quiet_channels
):
717 serv
.action(canal
,"sert un pain au chocolat à %s"%(auteur))
718 elif re
.match("!?manzana",message
.lower()) and not canal
in self
.quiet_channels
:
719 if auteur
=="[20-100]":
720 serv
.action(canal
,"sert une bouteille de manzana à %s"%(auteur))
722 serv
.action(canal
,"sert un verre de manzana à %s"%(auteur))
723 if is_insult(message
) and not canal
in self
.quiet_channels
:
724 if is_not_insult(message
):
725 answer
=random
.choice(config_compliment_answers
)
726 for ligne
in answer
.split("\n"):
727 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
729 answer
=random
.choice(config_insultes_answers
)
730 for ligne
in answer
.split("\n"):
731 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
732 if is_gros(message
) and not canal
in self
.quiet_channels
:
733 taille
=get_filesize()
734 answer
=u
"Mais non, je ne suis pas gros, %sKo tout au plus…"%(taille)
735 serv
.privmsg(canal
,"%s: %s"%(auteur
,answer
.encode("utf8")))
736 if is_tesla(message
) and not canal
in self
.quiet_channels
:
737 l1
,l2
=config_tesla_answers
,config_tesla_actions
738 n1
,n2
=len(l1
),len(l2
)
739 i
=random
.randrange(n1
+n2
)
741 serv
.action(canal
,l2
[i
-n1
])
743 serv
.privmsg(canal
,"%s: %s"%(auteur
,l1
[i
].encode("utf8")))
744 if is_tamere(message
) and not canal
in self
.quiet_channels
:
745 answer
=random
.choice(config_tamere_answers
)
746 for ligne
in answer
.split("\n"):
747 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
748 if is_tag(message
) and not canal
in self
.quiet_channels
:
749 if auteur
in self
.ops
:
750 action
=random
.choice(config_tag_actions
)
751 serv
.action(canal
,action
.encode("utf8"))
752 self
.quiet_channels
.append(canal
)
754 answer
=random
.choice(config_tag_answers
)
755 for ligne
in answer
.split("\n"):
756 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
757 if is_merci(message
):
758 answer
=random
.choice(config_merci_answers
)
759 for ligne
in answer
.split("\n"):
760 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
761 out
=re
.match(u
"^([A-Z[]|\\|[0-9]+|(¹|²|³|⁴|⁵|⁶|⁷|⁸|⁹|⁰)+)(?:| \?| !)$",
762 unicode(message
.upper(),"utf8"))
763 if out
and not canal
in self
.quiet_channels
:
767 serv
.privmsg(canal
,"%s: %s !"%(auteur
,out
+1))
768 if out
+1>1000 and random
.randrange(4)==0:
769 serv
.privmsg(canal
,"%s: Tu sais, je peux continuer longtemps comme ça…"%(auteur))
771 serv
.privmsg(canal
,"%s: Tu croyais m'avoir sur le maxint ? J'suis en python mon vieux, 'va falloir trouver mieux…"%(auteur))
773 except Exception as exc
:
775 if re
.match("[A-Y]",out
):
776 alphabet
="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
777 serv
.privmsg(canal
,"%s: %s !"%(auteur
,alphabet
[alphabet
.index(out
)+1]))
779 serv
.privmsg(canal
,"%s: pfff, j'ai l'air malin maintenant… [ ?"%(auteur))
781 serv
.privmsg(canal
,"%s: nan mais il faut qu'on arrête, ça va finir par poser des problèmes…"%(auteur))
782 elif re
.match(r
"(¹|²|³|⁴|⁵|⁶|⁷|⁸|⁹|⁰)+",out
):
784 return "".join([{u
"⁰¹²³⁴⁵⁶⁷⁸⁹0123456789"[i
]:u
"0123456789⁰¹²³⁴⁵⁶⁷⁸⁹"[i
]
785 for i
in range(20)}[j
]
787 out
=int(translate(out
))
788 serv
.privmsg(canal
,"%s: %s !"%(auteur
,translate(str(out
+1)).encode("utf8")))
789 if (not canal
in self
.quiet_channels
790 and re
.match((u
"^("+"|".join(config_bonjour
)+").*").lower(),message
.lower()) ):
791 answer
=random
.choice(config_bonjour_answers
)
792 serv
.privmsg(canal
,answer
.format(auteur
).encode("utf8"))
794 serv
.privmsg(canal
,"%s: c'est pas sur moi qu'il faut tirer !"%(auteur))
796 if message
in ["!pain au chocolat","!chocolatine"] and not canal
in self
.quiet_channels
:
797 serv
.action(canal
,"sert un pain au chocolat à %s"%(auteur))
798 if message
in ["!manzana"] and not canal
in self
.quiet_channels
:
799 if auteur
=="[20-100]":
800 serv
.action(canal
,"sert une bouteille de manzana à %s"%(auteur))
802 serv
.action(canal
,"sert un verre de manzana à %s"%(auteur))
803 if re
.match('^(.|§|:|)(w|b) [0-9]+$',message
) and not canal
in self
.quiet_channels
:
804 failanswers
=config_buffer_fail_answers
805 answer
=random
.choice(failanswers
)
806 serv
.privmsg(canal
,"%s: %s"%(auteur
,answer
))
807 if not canal
in self
.quiet_channels
:
808 self
.try_tamere(serv
,canal
,auteur
,message
)
809 mypseudo
=serv
.get_nickname()
810 if re
.match((u
"^("+u
"|".join(config_bonjour
)
811 +u
")( {}| all| tout le monde|(|à) tous)(\.|( |)!|)$"
812 ).format(mypseudo
).lower(), message
.strip().lower()):
813 answer
=random
.choice(config_bonjour_answers
)
814 serv
.privmsg(canal
,answer
.format(auteur
).encode("utf8"))
815 if (is_perdu(message
) and not canal
in self
.quiet_channels
):
816 # proba de perdre sur trigger :
817 # avant 30min (enfin, config) : 0
818 # ensuite, +25%/30min, linéairement
819 deltat
=time
.time()-self
.last_perdu
820 barre
=(deltat
-config_time_between_perdu
)/(2*3600.0)
821 if random
.uniform(0,1)<barre
:
822 serv
.privmsg(canal
,"%s: J'ai perdu !"%(auteur))
823 self
.last_perdu
=time
.time()
825 def on_action(self
, serv
, ev
):
826 action
= ev
.arguments()[0]
827 auteur
= irclib
.nm_to_n(ev
.source())
828 channel
= ev
.target()
830 test
=bot_unicode(message
)
831 except UnicodeBotError
:
832 serv
.privmsg(channel
,
833 "%s : Euh, tu fais de la merde avec ton encodage là, j'ai failli crasher…"%(auteur))
835 mypseudo
=serv
.get_nickname()
837 if is_action_trigger(action
,mypseudo
) and not channel
in self
.quiet_channels
:
838 l1
,l2
=config_action_answers
,config_action_actions
839 n1
,n2
=len(l1
),len(l2
)
840 i
=random
.randrange(n1
+n2
)
842 serv
.action(channel
,l2
[i
-n1
].encode("utf8"))
844 serv
.privmsg(channel
,"%s: %s"%(auteur
,l1
[i
].encode("utf8")))
846 if __name__
=="__main__":
849 print "Usage : basile.py <serveur> [--debug]"
852 if "debug" in sys
.argv
or "--debug" in sys
.argv
:
856 serveurs
={"a♡":"acoeur.crans.org","acoeur":"acoeur.crans.org","acoeur.crans.org":"acoeur.crans.org",
857 "irc":"irc.crans.org","crans":"irc.crans.org","irc.crans.org":"irc.crans.org"}
859 serveur
=serveurs
[serveur
]
861 print "Server Unknown : %s"%(serveur)
863 basile
=Basile(serveur
,debug
)