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
"pl(o|i)p",u
"pr(ou|ü)t",u
"bonjour",u
"bonsoir",u
"coucou"]
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
"^",
234 apres
="( [a-z]*ment)? %s($|\.| |,|;).*"%(pseudo))
236 return re
.match(u
"^(pan|bim|bang) .*$",unicode(chain
,"utf8").lower().strip())
240 class UnicodeBotError(Exception):
242 def bot_unicode(chain
):
244 unicode(chain
,"utf8")
245 except UnicodeDecodeError as exc
:
246 raise UnicodeBotError
248 class Basile(ircbot
.SingleServerIRCBot
):
249 def __init__(self
,serveur
,debug
=False):
250 temporary_pseudo
=config_irc_pseudo
+str(random
.randrange(10000,100000))
251 ircbot
.SingleServerIRCBot
.__init
__(self
, [(serveur
, 6667)],
252 temporary_pseudo
,"Basile, le bot irc.[Codé par 20-100, fouettez-le]", 10)
255 self
.overops
=config_overops
256 self
.ops
=self
.overops
+config_ops
257 self
.report_bugs_to
=config_report_bugs_to
258 self
.chanlist
=config_chanlist
260 self
.identities
=pickle
.load(open("identities.pickle","r"))
261 self
.stay_channels
=config_stay_channels
262 self
.quiet_channels
=config_quiet_channels
266 def new_connection_NK(self
,serv
,username
,password
,typ
="bdd"):
268 login_result
,sock
=login_NK(username
,password
,typ
)
269 droits
,retcode
,errmsg
=login_result
["msg"],login_result
["retcode"],login_result
["errmsg"]
270 except NKRefused
as exc
:
271 for report
in self
.report_bugs_to
:
272 serv
.privmsg(report
,"Le Serveur NK2015 est down.")
274 except NKHelloFailed
as exc
:
275 for report
in self
.report_bugs_to
:
277 "La version du site utilisée n'est pas supportée par le serveur NK2015.")
279 except NKUnknownError
as exc
:
280 erreurs
=["Une fucking erreur inconnue s'est produite"]
281 erreurs
+=str(exc
).split("\n")
282 for report
in self
.report_bugs_to
:
284 serv
.privmsg(report
,err
)
286 except Exception as exc
:
287 # Exception qui ne vient pas de la communication avec le serveur NK2015
288 log(self
.serveur
,"Erreur dans new_connection_NK\n"+str(exc
))
295 def give_me_my_pseudo(self
,serv
):
296 serv
.privmsg("NickServ","RECOVER %s %s"%(config_irc_pseudo
,config_irc_password
))
297 serv
.privmsg("NickServ","RELEASE %s %s"%(config_irc_pseudo
,config_irc_password
))
299 serv
.nick(config_irc_pseudo
)
301 def on_welcome(self
, serv
, ev
):
302 self
.give_me_my_pseudo(serv
)
303 serv
.privmsg("NickServ","identify %s"%(config_irc_password))
304 log(self
.serveur
,"Connected")
306 self
.chanlist
=["#bot"]
307 for c
in self
.chanlist
:
308 log(self
.serveur
,"JOIN %s"%(c))
310 # on ouvre la connexion note de Basile, special user
311 self
.nk
=self
.new_connection_NK(serv
,config_note_pseudo
,config_note_password
,"special")[1]
313 for report
in self
.report_bugs_to
:
314 serv
.privmsg(report
,"Connection to NK2015 failed, invalid password ?")
316 def lost(self
,serv
,channel
,forced
=False):
317 if self
.last_perdu
+config_time_between_perdu
<time
.time() or forced
:
318 if not channel
in self
.quiet_channels
or forced
:
319 serv
.privmsg(channel
,"J'ai perdu !")
320 self
.last_perdu
=time
.time()
321 delay
=config_time_between_perdu_trigger
322 delta
=config_time_between_perdu_trigger_delta
323 serv
.execute_delayed(random
.randrange(delay
-delta
,delay
+delta
),self
.lost
,(serv
,channel
))
325 def try_tamere(self
,serv
,channel
,auteur
,message
):
326 """Essaye de trigger un ta mère"""
327 #pas à chaque fois quand même
328 if random
.randrange(4)==0:
329 debuts
=u
"("+config_regexp_etre
+u
"|"+config_regexp_etre_avec_c
+u
")"
330 adjectifs
={u
"bon(|ne|s|nes)":u
"bonne",
331 u
"baisable(|s)":u
"baisable",
332 u
"faisable(|s)":u
"faisable",
333 u
"pas ch(ère(|s)|er(|s))":u
"pas chère",
334 u
"facile(|s)":u
"facile",
335 u
"chaud(|e|s|es)":u
"chaude",
336 u
"gratuit(|e|s|es)":u
"gratuite",
337 u
"payant(|e|s|es)":u
"payante",
338 u
"ouvert(|e|s|es)":u
"ouverte",
340 u
"plein(|s|es)":u
"pleine",
341 u
"bien plein(|e|s|es)":u
"bien pleine",
342 u
"innocent(|e|s|es)":u
"innocente"}
343 adj_reg
=u
"(?P<adjectif>"+u
"|".join(adjectifs
.keys())+u
")"
344 reg
=u
".*(^| |')"+debuts
+u
" "+adj_reg
+u
"($|,|;|\.| ).*"
345 matched
=re
.match(reg
,message
)
347 # il faut repasser l'adjectif au féminin singulier
348 found
=matched
.groupdict()["adjectif"]
349 for adj
in adjectifs
.keys():
350 if re
.match(adj
,found
):
351 adjectif
=adjectifs
[adj
]
353 serv
.privmsg(channel
,(u
"%s: c'est ta mère qui est %s !"%(auteur
,adjectif
)).encode("utf8"))
354 elif random
.randrange(5)==0:
355 # deuxième type de trigger, mais moins probable
356 matched
=re
.match(adj_reg
,message
)
358 found
=matched
.groupdict()["adjectif"]
359 for adj
in adjectifs
.keys():
360 if re
.match(adj
,found
):
361 adjectif
=adjectifs
[adj
]
363 fille
=random
.choice([u
"mère",u
"soœur"])
364 serv
.privmsg(channel
,(u
"%s: et ta %s, elle est %s ?"%
365 (auteur
,fille
,adjectif
)).encode("utf8"))
367 # troisième type de trigger
368 cpgt
=config_premier_groupe_terminaisons
369 verbes
={u
"tourn"+cpgt
:u
"tourne",
370 u
"balad"+cpgt
+u
" sur le trottoir":u
"se balade sur le trottoir",
371 u
"prom(e|è)n"+cpgt
+" sur le trottoir":u
"se promène sur le trottoir",
373 vb_reg
=u
".*(^| )(?P<verbe>"+"|".join(verbes
.keys())+")( |,|;|\.|$)"
374 matched
=re
.match(vb_reg
,message
)
376 found
=matched
.groupdict()["verbe"]
377 for vb
in verbes
.keys():
378 if re
.match(vb
,found
):
381 fille
=random
.choice([u
"mère",u
"soœur"])
382 serv
.privmsg(channel
,(u
"%s: et ta %s, elle %s ?"%
383 (auteur
,fille
,verbe
)).encode("utf8"))
384 def pourmoi(self
, serv
, message
):
385 """renvoie (False,lemessage) ou (True, le message amputé de "pseudo: ")"""
386 pseudo
=serv
.get_nickname()
388 if message
[:size
]==pseudo
and len(message
)>size
and message
[size
]==":":
389 return (True,message
[size
+1:].lstrip(" "))
391 return (False,message
)
393 def on_privmsg(self
, serv
, ev
):
394 message
=ev
.arguments()[0]
395 auteur
= irclib
.nm_to_n(ev
.source())
397 test
=bot_unicode(message
)
398 except UnicodeBotError
:
400 "Euh, tu fais de la merde avec ton encodage là, j'ai failli crasher…")
402 message
=message
.split()
403 cmd
=message
[0].lower()
406 if not len(message
) in [2,3]:
407 serv
.privmsg(auteur
,"Syntaxe : CONNECT [<username>] <password>")
411 username
=(message
[1])
412 password
=" ".join(message
[2:])
414 password
=" ".join(message
[1:])
415 success
,sock
=self
.new_connection_NK(serv
,username
,password
)
417 self
.sockets
[username
]=sock
418 serv
.privmsg(auteur
,"Connection successful")
419 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
421 serv
.privmsg(auteur
,"Connection failed")
422 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
425 helpdico
={"connect": """CONNECT [<username>] <password>
426 Ouvre une connexion au serveur NoteKfet.
427 Si <username> n'est pas précisé, j'utiliserais l'identité sous laquelle je te connais, ou, à défaut, ton pseudo.""",
428 "identify": """IDENTIFY <username> <password>
429 Vérifie le mot de passe et me permet de savoir à l'avenir quel est ton pseudo note kfet.
430 Sans paramètre, je réponds sous quel pseudo je te connais.""",
431 "drop":"""DROP <password>
432 Vérifie le mot de passe et me fait d'oublier ton pseudo note kfet."""}
433 helpmsg_default
="""Liste des commandes :
434 HELP Affiche de l'aide sur une commande.
435 CONNECT Ouvre une connection au serveur Note Kfet.
436 IDENTIFY Me permet de savoir qui tu es sur la note kfet.
437 DROP Me fait oublier ton identité.
438 SOLDE Obtenir ton solde"""
440 JOIN Faire rejoindre un chan
441 LEAVE Faire quitter un chan
442 QUIET Se taire sur un chan
443 NOQUIET Opposé de QUIET
444 LOST Perdre sur un chan
445 SOLDE <pseudo> Donner le solde de quelqu'un"""
447 SAY Fait envoyer un message sur un chan ou à une personne
448 DO Fait faire une action sur un chan
449 STAY Ignorera les prochains LEAVE pour un chan
450 NOSTAY Opposé de STAY
453 helpmsg
=helpmsg_default
454 if auteur
in self
.ops
:
456 if auteur
in self
.overops
:
457 helpmsg
+=helpmsg_overops
459 helpmsg
=helpdico
.get(message
[1].lower(),"Commande inconnue.")
460 for ligne
in helpmsg
.split("\n"):
461 serv
.privmsg(auteur
,ligne
)
462 elif cmd
=="identify":
464 if self
.identities
.has_key(auteur
):
465 serv
.privmsg(auteur
,"Je te connais sous le pseudo note %s."%(
466 self
.identities
[auteur
].encode("utf8")))
468 serv
.privmsg(auteur
,"Je ne connais pas ton pseudo note.")
469 elif len(message
)>=3:
470 username
,password
=message
[1],unicode(" ".join(message
[2:]),"utf8")
471 success
,_
=self
.new_connection_NK(serv
,username
,password
)
473 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
474 serv
.privmsg(auteur
,"Identité enregistrée.")
475 self
.identities
[auteur
]=username
476 pickle
.dump(self
.identities
,open("identities.pickle","w"))
478 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
479 serv
.privmsg(auteur
,"Mot de passe invalide. (ou serveur down)")
481 serv
.privmsg(auteur
,u
"Syntaxe : IDENTIFY [<username> <password>]")
484 if self
.identities
.has_key(auteur
):
485 password
=" ".join(message
[1:])
486 success
,_
=self
.new_connection_NK(serv
,self
.identities
[auteur
],password
)
488 del self
.identities
[auteur
]
489 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
490 pickle
.dump(self
.identities
,open("identities.pickle","w"))
491 serv
.privmsg(auteur
,"Identité oubliée.")
493 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
494 serv
.privmsg(auteur
,"Mot de passe invalide. (ou serveur down)")
496 serv
.privmsg(auteur
,"Je ne connais pas ton pseudo note.")
498 serv
.privmsg(auteur
,"Syntaxe : DROP <password>")
500 if auteur
in self
.ops
:
502 if message
[1] in self
.chanlist
:
503 serv
.privmsg(auteur
,"Je suis déjà sur %s"%(message
[1]))
505 serv
.join(message
[1])
506 self
.chanlist
.append(message
[1])
507 serv
.privmsg(auteur
,"Channels : "+" ".join(self
.chanlist
))
508 log(self
.serveur
,"priv",auteur
," ".join(message
))
510 serv
.privmsg(auteur
,"Channels : "+" ".join(self
.chanlist
))
514 if auteur
in self
.ops
and len(message
)>1:
515 if message
[1] in self
.chanlist
:
516 if not (message
[1] in self
.stay_channels
) or auteur
in self
.overops
:
517 serv
.part(message
[1])
518 self
.chanlist
.remove(message
[1])
519 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
521 serv
.privmsg(auteur
,"Non, je reste !")
522 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
524 serv
.privmsg(auteur
,"Je ne suis pas sur %s"%(message
[1]))
528 if auteur
in self
.overops
:
530 if message
[1] in self
.stay_channels
:
531 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
532 serv
.privmsg(auteur
,"Je stay déjà sur %s."%(message
[1]))
534 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
535 self
.stay_channels
.append(message
[1])
536 serv
.privmsg(auteur
,"Stay channels : "+" ".join(self
.stay_channels
))
538 serv
.privmsg(auteur
,"Stay channels : "+" ".join(self
.stay_channels
))
542 if auteur
in self
.overops
:
544 if message
[1] in self
.stay_channels
:
545 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
546 self
.stay_channels
.remove(message
[1])
547 serv
.privmsg(auteur
,"Stay channels : "+" ".join(self
.stay_channels
))
549 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
550 serv
.privmsg(auteur
,"Je ne stay pas sur %s."%(message
[1]))
555 if auteur
in self
.overops
:
556 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
561 if auteur
in self
.ops
:
563 if message
[1] in self
.quiet_channels
:
564 serv
.privmsg(auteur
,"Je me la ferme déjà sur %s"%(message
[1]))
565 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
567 self
.quiet_channels
.append(message
[1])
568 serv
.privmsg(auteur
,"Quiet channels : "+" ".join(self
.quiet_channels
))
569 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
571 serv
.privmsg(auteur
,"Quiet channels : "+" ".join(self
.quiet_channels
))
575 if auteur
in self
.ops
:
577 if message
[1] in self
.quiet_channels
:
578 self
.quiet_channels
.remove(message
[1])
579 serv
.privmsg(auteur
,"Quiet channels : "+" ".join(self
.quiet_channels
))
580 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
582 serv
.privmsg(auteur
,"Je ne me la ferme pas sur %s."%(message
[1]))
583 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
587 if auteur
in self
.overops
and len(message
)>2:
588 serv
.privmsg(message
[1]," ".join(message
[2:]))
589 log(self
.serveur
,"priv",auteur
," ".join(message
))
590 elif len(message
)<=2:
591 serv
.privmsg(auteur
,"Syntaxe : SAY <channel> <message>")
595 if auteur
in self
.overops
and len(message
)>2:
596 serv
.action(message
[1]," ".join(message
[2:]))
597 log(self
.serveur
,"priv",auteur
," ".join(message
))
598 elif len(message
)<=2:
599 serv
.privmsg(auteur
,"Syntaxe : DO <channel> <action>")
603 if auteur
in self
.overops
and len(message
)>2:
604 serv
.kick(message
[1],message
[2]," ".join(message
[3:]))
605 log(self
.serveur
,"priv",auteur
," ".join(message
))
606 elif len(message
)<=2:
607 serv
.privmsg(auteur
,"Syntaxe : KICK <channel> <pseudo>")
611 if auteur
in self
.ops
and len(message
)>1:
612 serv
.privmsg(message
[1],"J'ai perdu !")
613 log(self
.serveur
,"priv",auteur
," ".join(message
))
614 elif len(message
)<=1:
615 serv
.privmsg(auteur
,"Syntaxe : LOST <channel>")
620 if self
.identities
.has_key(auteur
):
622 self
.nk
.write('search ["x",["pseudo"],%s]'%(json
.dumps(self
.identities
[auteur
])))
623 ret
=json
.loads(self
.nk
.read())
624 solde
=ret
["msg"][0]["solde"]
625 pseudo
=ret
["msg"][0]["pseudo"]
626 except Exception as exc
:
628 serv
.privmsg(auteur
,"failed")
629 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
631 serv
.privmsg(auteur
,"%s (%s)"%(float(solde
)/100,pseudo
.encode("utf8")))
633 serv
.privmsg(canal
,"Je ne connais pas ton pseudo note.")
634 elif auteur
in self
.ops
:
636 self
.nk
.write('search ["x",["pseudo"],%s]'%(json
.dumps(message
[1])))
637 ret
=json
.loads(self
.nk
.read())
638 solde
=ret
["msg"][0]["solde"]
639 pseudo
=ret
["msg"][0]["pseudo"]
640 except Exception as exc
:
641 serv
.privmsg(auteur
,"failed")
642 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
644 serv
.privmsg(auteur
,"%s (%s)"%(float(solde
)/100,pseudo
.encode("utf8")))
648 serv
.privmsg(auteur
,"Je n'ai pas compris. Essaye HELP…")
650 def on_pubmsg(self
, serv
, ev
):
651 auteur
= irclib
.nm_to_n(ev
.source())
653 message
= ev
.arguments()[0]
655 test
=bot_unicode(message
)
656 except UnicodeBotError
:
657 if not canal
in self
.quiet_channels
:
659 "%s: Euh, tu fais de la merde avec ton encodage là, j'ai failli crasher…"%(auteur))
661 pour_moi
,message
=self
.pourmoi(serv
,message
)
662 if pour_moi
and message
.split()!=[]:
663 cmd
=message
.split()[0].lower()
665 args
=" ".join(message
.split()[1:])
668 if cmd
in ["meurs","die","crève"]:
669 if auteur
in self
.overops
:
670 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
673 serv
.privmsg(canal
,"%s: crève !"%(auteur))
674 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
676 elif cmd
in ["part","leave","dégage"]:
677 if auteur
in self
.ops
and (not (canal
in self
.stay_channels
)
678 or auteur
in self
.overops
):
679 serv
.part(canal
,message
="Éjecté par %s"%(auteur))
680 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
681 if canal
in self
.chanlist
:
682 self
.chanlist
.remove(canal
)
684 serv
.privmsg(canal
,"%s: Non, je reste !"%(auteur))
685 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
687 elif cmd
in ["reconnect"]:
688 if auteur
in self
.ops
:
690 self
.nk
=self
.new_connection_NK(serv
,config_note_pseudo
,
691 config_note_password
,"special")[1]
692 except Exception as exc
:
694 log(self
.serveur
,"""Erreur dans on_pubmsg/"cmd in ["reconnect"]\n"""+str(exc
))
696 serv
.privmsg(canal
,"%s: done"%(auteur))
697 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
699 serv
.privmsg(canal
,"%s: failed"%(auteur))
700 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
701 for report
in self
.report_bugs_to
:
702 serv
.privmsg(report
,"Connection to NK2015 failed, invalid password ?")
704 serv
.privmsg(canal
,"%s: crève !"%(auteur))
705 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
707 elif cmd
in ["deviens","pseudo"]:
708 if auteur
in self
.ops
:
711 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
713 if cmd
in ["meur", "meurt","meurre","meurres"] and not canal
in self
.quiet_channels
:
714 serv
.privmsg(canal
,'%s: Mourir, impératif, 2ème personne du singulier : "meurs" (de rien)'%(auteur))
715 elif cmd
in ["ping"] and not canal
in self
.quiet_channels
:
716 serv
.privmsg(canal
,"%s: pong"%(auteur))
718 elif cmd
in ["solde","!solde"]:
719 if self
.identities
.has_key(auteur
):
720 pseudo
=self
.identities
[auteur
]
722 self
.nk
.write('search ["x",["pseudo"],%s]'%(json
.dumps(pseudo
)))
723 ret
=json
.loads(self
.nk
.read())
724 solde
=ret
["msg"][0]["solde"]
725 pseudo
=ret
["msg"][0]["pseudo"]
726 except Exception as exc
:
727 serv
.privmsg(canal
,"%s: failed"%(auteur))
728 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
730 serv
.privmsg(canal
,"%s: %s (%s)"%(auteur
,float(solde
)/100,pseudo
.encode("utf8")))
731 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
733 serv
.privmsg(canal
,"%s: Je ne connais pas ton pseudo note."%(auteur))
734 log(self
.serveur
,canal
,auteur
,message
+"[unknown]")
735 elif (re
.match("!?(pain au chocolat|chocolatine)",message
.lower())
736 and not canal
in self
.quiet_channels
):
737 serv
.action(canal
,"sert un pain au chocolat à %s"%(auteur))
738 elif re
.match("!?manzana",message
.lower()) and not canal
in self
.quiet_channels
:
739 if auteur
=="[20-100]":
740 serv
.action(canal
,"sert une bouteille de manzana à %s"%(auteur))
742 serv
.action(canal
,"sert un verre de manzana à %s"%(auteur))
743 if is_insult(message
) and not canal
in self
.quiet_channels
:
744 if is_not_insult(message
):
745 answer
=random
.choice(config_compliment_answers
)
746 for ligne
in answer
.split("\n"):
747 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
749 answer
=random
.choice(config_insultes_answers
)
750 for ligne
in answer
.split("\n"):
751 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
752 if is_gros(message
) and not canal
in self
.quiet_channels
:
753 taille
=get_filesize()
754 answer
=u
"Mais non, je ne suis pas gros, %sKo tout au plus…"%(taille)
755 serv
.privmsg(canal
,"%s: %s"%(auteur
,answer
.encode("utf8")))
756 if is_tesla(message
) and not canal
in self
.quiet_channels
:
757 l1
,l2
=config_tesla_answers
,config_tesla_actions
758 n1
,n2
=len(l1
),len(l2
)
759 i
=random
.randrange(n1
+n2
)
761 serv
.action(canal
,l2
[i
-n1
].encode("utf8"))
763 serv
.privmsg(canal
,"%s: %s"%(auteur
,l1
[i
].encode("utf8")))
764 if is_tamere(message
) and not canal
in self
.quiet_channels
:
765 answer
=random
.choice(config_tamere_answers
)
766 for ligne
in answer
.split("\n"):
767 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
768 if is_tag(message
) and not canal
in self
.quiet_channels
:
769 if auteur
in self
.ops
:
770 action
=random
.choice(config_tag_actions
)
771 serv
.action(canal
,action
.encode("utf8"))
772 self
.quiet_channels
.append(canal
)
774 answer
=random
.choice(config_tag_answers
)
775 for ligne
in answer
.split("\n"):
776 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
777 if is_merci(message
):
778 answer
=random
.choice(config_merci_answers
)
779 for ligne
in answer
.split("\n"):
780 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
781 out
=re
.match(ur
"^([A-Z[]|\\|[0-9]+|(¹|²|³|⁴|⁵|⁶|⁷|⁸|⁹|⁰)+)(?:| \?| !)$",
782 unicode(message
.upper(),"utf8"))
783 if out
and not canal
in self
.quiet_channels
:
787 serv
.privmsg(canal
,"%s: %s !"%(auteur
,out
+1))
788 if out
+1>1000 and random
.randrange(4)==0:
789 serv
.privmsg(canal
,"%s: Tu sais, je peux continuer longtemps comme ça…"%(auteur))
791 serv
.privmsg(canal
,"%s: Tu croyais m'avoir sur le maxint ? J'suis en python mon vieux, 'va falloir trouver mieux…"%(auteur))
793 except Exception as exc
:
795 if re
.match("[A-Y]",out
):
796 alphabet
="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
797 serv
.privmsg(canal
,"%s: %s !"%(auteur
,alphabet
[alphabet
.index(out
)+1]))
799 serv
.privmsg(canal
,"%s: pfff, j'ai l'air malin maintenant… [ ?"%(auteur))
801 serv
.privmsg(canal
,"%s: nan mais il faut qu'on arrête, ça va finir par poser des problèmes…"%(auteur))
802 elif re
.match(ur
"(¹|²|³|⁴|⁵|⁶|⁷|⁸|⁹|⁰)+",out
):
804 return "".join([{u
"⁰¹²³⁴⁵⁶⁷⁸⁹0123456789"[i
]:u
"0123456789⁰¹²³⁴⁵⁶⁷⁸⁹"[i
]
805 for i
in range(20)}[j
]
807 out
=int(translate(out
))
808 serv
.privmsg(canal
,"%s: %s !"%(auteur
,translate(str(out
+1)).encode("utf8")))
809 if (not canal
in self
.quiet_channels
810 and re
.match((u
"^("+"|".join(config_bonjour
)+").*").lower(),message
.lower()) ):
811 answer
=random
.choice(config_bonjour_answers
)
812 serv
.privmsg(canal
,answer
.format(auteur
).encode("utf8"))
813 if is_pan(message
) and not canal
in self
.quiet_channels
:
814 serv
.privmsg(canal
,"%s: c'est pas sur moi qu'il faut tirer !"%(auteur))
816 if message
in ["!pain au chocolat","!chocolatine"] and not canal
in self
.quiet_channels
:
817 serv
.action(canal
,"sert un pain au chocolat à %s"%(auteur))
818 if message
in ["!manzana"] and not canal
in self
.quiet_channels
:
819 if auteur
=="[20-100]":
820 serv
.action(canal
,"sert une bouteille de manzana à %s"%(auteur))
822 serv
.action(canal
,"sert un verre de manzana à %s"%(auteur))
823 if re
.match('^(.|§|:|)(w|b) [0-9]+$',message
) and not canal
in self
.quiet_channels
:
824 failanswers
=config_buffer_fail_answers
825 answer
=random
.choice(failanswers
)
826 serv
.privmsg(canal
,"%s: %s"%(auteur
,answer
))
827 if not canal
in self
.quiet_channels
:
828 self
.try_tamere(serv
,canal
,auteur
,message
)
829 mypseudo
=serv
.get_nickname()
830 if re
.match((u
"^("+u
"|".join(config_bonjour
)
831 +u
")( {}| all| tout le monde|(|à) tous)(\.|( |)!|)$"
832 ).format(mypseudo
).lower(), message
.strip().lower()):
833 answer
=random
.choice(config_bonjour_answers
)
834 serv
.privmsg(canal
,answer
.format(auteur
).encode("utf8"))
835 if (is_perdu(message
) and not canal
in self
.quiet_channels
):
836 # proba de perdre sur trigger :
837 # avant 30min (enfin, config) : 0
838 # ensuite, +25%/30min, linéairement
839 deltat
=time
.time()-self
.last_perdu
840 barre
=(deltat
-config_time_between_perdu
)/(2*3600.0)
841 if random
.uniform(0,1)<barre
:
842 serv
.privmsg(canal
,"%s: J'ai perdu !"%(auteur))
843 self
.last_perdu
=time
.time()
845 def on_action(self
, serv
, ev
):
846 action
= ev
.arguments()[0]
847 auteur
= irclib
.nm_to_n(ev
.source())
848 channel
= ev
.target()
850 test
=bot_unicode(action
)
851 except UnicodeBotError
:
852 serv
.privmsg(channel
,
853 "%s : Euh, tu fais de la merde avec ton encodage là, j'ai failli crasher…"%(auteur))
855 mypseudo
=serv
.get_nickname()
857 if is_action_trigger(action
,mypseudo
) and not channel
in self
.quiet_channels
:
858 l1
,l2
=config_action_answers
,config_action_actions
859 n1
,n2
=len(l1
),len(l2
)
860 i
=random
.randrange(n1
+n2
)
862 serv
.action(channel
,l2
[i
-n1
].encode("utf8"))
864 serv
.privmsg(channel
,"%s: %s"%(auteur
,l1
[i
].encode("utf8")))
866 if __name__
=="__main__":
869 print "Usage : basile.py <serveur> [--debug]"
872 if "debug" in sys
.argv
or "--debug" in sys
.argv
:
876 serveurs
={"a♡":"acoeur.crans.org","acoeur":"acoeur.crans.org","acoeur.crans.org":"acoeur.crans.org",
877 "irc":"irc.crans.org","crans":"irc.crans.org","irc.crans.org":"irc.crans.org"}
879 serveur
=serveurs
[serveur
]
881 print "Server Unknown : %s"%(serveur)
883 basile
=Basile(serveur
,debug
)