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"]
123 config_kick_answer
=[u
"Ben qu'est-ce que j'ai fait ? :(",u
"Mais euh, j'ai rien fait de mal…","{} a le /kick facile :)"]
124 config_kick_action
=[u
"se tiendra à carreaux",u
"essaiera de ne plus provoquer les foudres de {}"
126 config_thisfile
= os
.path
.realpath( __file__
)
128 return ex("ls -s %s"%(config_thisfile))[1].split()[0]
130 class NKError(Exception):
131 def __init__(self
,msg
):
132 Exception.__init
__(self
)
136 def __unicode__(self
):
137 return unicode(self
.msg
)
139 class NKRefused(NKError
):
142 class NKHelloFailed(NKError
):
145 class NKUnknownError(NKError
):
148 def log(serveur
,channel
,auteur
=None,message
=None):
149 f
=open(get_config_logfile(serveur
),"a")
150 if auteur
==message
==None:
151 # alors c'est que c'est pas un channel mais juste une ligne de log
152 chain
="%s %s"%(time
.strftime("%F %T"),channel
)
154 chain
="%s [%s:%s] %s"%(time
.strftime("%F %T"),channel
,auteur
,message
)
156 if config_debug_stdout
:
163 # On établit la connexion sur port 4242
164 sock
.connect(("127.0.0.1",4242))
166 sock
=ssl
.wrap_socket(sock
,ca_certs
='../keys/ca_.crt')
168 sock
.write('hello "Basile"')
169 # On récupère la réponse du hello
172 except Exception as exc
:
173 # Si on a foiré quelque part, c'est que le serveur est down
174 raise NKRefused(str(exc
))
175 if out
["retcode"]==0:
177 elif out
["retcode"]==11:
178 raise NKHelloFailed(out
["errmsg"])
180 raise NKUnknownError(out
["errmsg"])
182 def login_NK(username
,password
,typ
="bdd"):
184 if typ
=="special": # ça c'est pour Basile lui-même
187 masque
='[["all"],["all"],false]'
189 # Basile a un compte special user
190 commande
='login [%s,%s,"%s",%s]'%(json
.dumps(username
),json
.dumps(password
),typ
,masque
)
193 except Exception as exc
:
194 # Si on a foiré quelque part, c'est que le serveur est down
195 raise NKRefused(str(exc
))
196 # On vérifie ensuite que le login
197 return json
.loads(out
),sock
200 def is_something(chain
,matches
,avant
=u
".*(^| )",apres
=u
"($|\.| |,|;).*",case_sensitive
=False,debug
=False):
202 chain
=unicode(chain
,"utf8")
204 chain
=unicode(chain
,"utf8").lower()
205 allmatches
="("+"|".join(matches
)+")"
206 reg
=(avant
+allmatches
+apres
).lower()
207 if re
.match(reg
,chain
):
211 def is_insult(chain
,debug
=True):
212 return is_something(chain
,config_insultes
,avant
=".*(^| |')")
213 def is_not_insult(chain
):
214 chain
=unicode(chain
,"utf8")
215 insult_regexp
=u
"("+u
"|".join(config_insultes
)+u
")"
216 middle_regexp
=u
"(un(|e) ((putain|enfoiré) d(e |'))*|)(| super )( (gros|petit|grand|énorme) |)"
217 reg
=".*pas %s%s.*"%(middle_regexp
,insult_regexp
)
218 if re
.match(reg
,chain
):
223 return is_something(chain
,config_perdu
)
225 return is_something(chain
,config_tag
)
227 return is_something(chain
,config_gros
)
229 return is_something(chain
,config_tesla
,avant
=u
"^",apres
=u
"$",debug
=True)
231 return is_something(chain
,config_merci
)
232 def is_tamere(chain
):
233 return is_something(chain
,config_tamere
)
234 def is_action_trigger(chain
,pseudo
):
235 return is_something(chain
,config_action_trigger
,avant
=u
"^",
236 apres
="( [a-z]*ment)? %s($|\.| |,|;).*"%(pseudo))
238 return re
.match(u
"^(pan|bim|bang) .*$",unicode(chain
,"utf8").lower().strip())
242 class UnicodeBotError(Exception):
244 def bot_unicode(chain
):
246 unicode(chain
,"utf8")
247 except UnicodeDecodeError as exc
:
248 raise UnicodeBotError
250 class Basile(ircbot
.SingleServerIRCBot
):
251 def __init__(self
,serveur
,debug
=False):
252 temporary_pseudo
=config_irc_pseudo
+str(random
.randrange(10000,100000))
253 ircbot
.SingleServerIRCBot
.__init
__(self
, [(serveur
, 6667)],
254 temporary_pseudo
,"Basile, le bot irc.[Codé par 20-100, fouettez-le]", 10)
257 self
.overops
=config_overops
258 self
.ops
=self
.overops
+config_ops
259 self
.report_bugs_to
=config_report_bugs_to
260 self
.chanlist
=config_chanlist
262 self
.identities
=pickle
.load(open("identities.pickle","r"))
263 self
.stay_channels
=config_stay_channels
264 self
.quiet_channels
=config_quiet_channels
268 def new_connection_NK(self
,serv
,username
,password
,typ
="bdd"):
270 login_result
,sock
=login_NK(username
,password
,typ
)
271 droits
,retcode
,errmsg
=login_result
["msg"],login_result
["retcode"],login_result
["errmsg"]
272 except NKRefused
as exc
:
273 for report
in self
.report_bugs_to
:
274 serv
.privmsg(report
,"Le Serveur NK2015 est down.")
276 except NKHelloFailed
as exc
:
277 for report
in self
.report_bugs_to
:
279 "La version du site utilisée n'est pas supportée par le serveur NK2015.")
281 except NKUnknownError
as exc
:
282 erreurs
=["Une fucking erreur inconnue s'est produite"]
283 erreurs
+=str(exc
).split("\n")
284 for report
in self
.report_bugs_to
:
286 serv
.privmsg(report
,err
)
288 except Exception as exc
:
289 # Exception qui ne vient pas de la communication avec le serveur NK2015
290 log(self
.serveur
,"Erreur dans new_connection_NK\n"+str(exc
))
297 def give_me_my_pseudo(self
,serv
):
298 serv
.privmsg("NickServ","RECOVER %s %s"%(config_irc_pseudo
,config_irc_password
))
299 serv
.privmsg("NickServ","RELEASE %s %s"%(config_irc_pseudo
,config_irc_password
))
301 serv
.nick(config_irc_pseudo
)
303 def on_welcome(self
, serv
, ev
):
304 self
.serv
=serv
# ça serv ira :)
305 self
.give_me_my_pseudo(serv
)
306 serv
.privmsg("NickServ","identify %s"%(config_irc_password))
307 log(self
.serveur
,"Connected")
309 self
.chanlist
=["#bot"]
310 for c
in self
.chanlist
:
311 log(self
.serveur
,"JOIN %s"%(c))
313 # on ouvre la connexion note de Basile, special user
314 self
.nk
=self
.new_connection_NK(serv
,config_note_pseudo
,config_note_password
,"special")[1]
316 for report
in self
.report_bugs_to
:
317 serv
.privmsg(report
,"Connection to NK2015 failed, invalid password ?")
319 def lost(self
,serv
,channel
,forced
=False):
320 if self
.last_perdu
+config_time_between_perdu
<time
.time() or forced
:
321 if not channel
in self
.quiet_channels
or forced
:
322 serv
.privmsg(channel
,"J'ai perdu !")
323 self
.last_perdu
=time
.time()
324 delay
=config_time_between_perdu_trigger
325 delta
=config_time_between_perdu_trigger_delta
326 serv
.execute_delayed(random
.randrange(delay
-delta
,delay
+delta
),self
.lost
,(serv
,channel
))
328 def try_tamere(self
,serv
,channel
,auteur
,message
):
329 """Essaye de trigger un ta mère"""
330 #pas à chaque fois quand même
331 if random
.randrange(4)==0:
332 debuts
=u
"("+config_regexp_etre
+u
"|"+config_regexp_etre_avec_c
+u
")"
333 adjectifs
={u
"bon(|ne|s|nes)":u
"bonne",
334 u
"baisable(|s)":u
"baisable",
335 u
"faisable(|s)":u
"faisable",
336 u
"pas ch(ère(|s)|er(|s))":u
"pas chère",
337 u
"facile(|s)":u
"facile",
338 u
"chaud(|e|s|es)":u
"chaude",
339 u
"gratuit(|e|s|es)":u
"gratuite",
340 u
"payant(|e|s|es)":u
"payante",
341 u
"ouvert(|e|s|es)":u
"ouverte",
343 u
"plein(|s|es)":u
"pleine",
344 u
"bien plein(|e|s|es)":u
"bien pleine",
345 u
"innocent(|e|s|es)":u
"innocente"}
346 adj_reg
=u
"(?P<adjectif>"+u
"|".join(adjectifs
.keys())+u
")"
347 reg
=u
".*(^| |')"+debuts
+u
" "+adj_reg
+u
"($|,|;|\.| ).*"
348 matched
=re
.match(reg
,message
)
350 # il faut repasser l'adjectif au féminin singulier
351 found
=matched
.groupdict()["adjectif"]
352 for adj
in adjectifs
.keys():
353 if re
.match(adj
,found
):
354 adjectif
=adjectifs
[adj
]
356 serv
.privmsg(channel
,(u
"%s: c'est ta mère qui est %s !"%(auteur
,adjectif
)).encode("utf8"))
357 elif random
.randrange(5)==0:
358 # deuxième type de trigger, mais moins probable
359 matched
=re
.match(adj_reg
,message
)
361 found
=matched
.groupdict()["adjectif"]
362 for adj
in adjectifs
.keys():
363 if re
.match(adj
,found
):
364 adjectif
=adjectifs
[adj
]
366 fille
=random
.choice([u
"mère",u
"soœur"])
367 serv
.privmsg(channel
,(u
"%s: et ta %s, elle est %s ?"%
368 (auteur
,fille
,adjectif
)).encode("utf8"))
370 # troisième type de trigger
371 cpgt
=config_premier_groupe_terminaisons
372 verbes
={u
"tourn"+cpgt
:u
"tourne",
373 u
"balad"+cpgt
+u
" sur le trottoir":u
"se balade sur le trottoir",
374 u
"prom(e|è)n"+cpgt
+" sur le trottoir":u
"se promène sur le trottoir",
376 vb_reg
=u
".*(^| )(?P<verbe>"+"|".join(verbes
.keys())+")( |,|;|\.|$)"
377 matched
=re
.match(vb_reg
,message
)
379 found
=matched
.groupdict()["verbe"]
380 for vb
in verbes
.keys():
381 if re
.match(vb
,found
):
384 fille
=random
.choice([u
"mère",u
"soœur"])
385 serv
.privmsg(channel
,(u
"%s: et ta %s, elle %s ?"%
386 (auteur
,fille
,verbe
)).encode("utf8"))
387 def pourmoi(self
, serv
, message
):
388 """renvoie (False,lemessage) ou (True, le message amputé de "pseudo: ")"""
391 if message
[:size
]==pseudo
and len(message
)>size
and message
[size
]==":":
392 return (True,message
[size
+1:].lstrip(" "))
394 return (False,message
)
396 def on_privmsg(self
, serv
, ev
):
397 message
=ev
.arguments()[0]
398 auteur
= irclib
.nm_to_n(ev
.source())
400 test
=bot_unicode(message
)
401 except UnicodeBotError
:
403 "Euh, tu fais de la merde avec ton encodage là, j'ai failli crasher…")
405 message
=message
.split()
406 cmd
=message
[0].lower()
409 if not len(message
) in [2,3]:
410 serv
.privmsg(auteur
,"Syntaxe : CONNECT [<username>] <password>")
414 username
=(message
[1])
415 password
=" ".join(message
[2:])
417 password
=" ".join(message
[1:])
418 success
,sock
=self
.new_connection_NK(serv
,username
,password
)
420 self
.sockets
[username
]=sock
421 serv
.privmsg(auteur
,"Connection successful")
422 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
424 serv
.privmsg(auteur
,"Connection failed")
425 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
428 helpdico
={"connect": """CONNECT [<username>] <password>
429 Ouvre une connexion au serveur NoteKfet.
430 Si <username> n'est pas précisé, j'utiliserais l'identité sous laquelle je te connais, ou, à défaut, ton pseudo.""",
431 "identify": """IDENTIFY <username> <password>
432 Vérifie le mot de passe et me permet de savoir à l'avenir quel est ton pseudo note kfet.
433 Sans paramètre, je réponds sous quel pseudo je te connais.""",
434 "drop":"""DROP <password>
435 Vérifie le mot de passe et me fait d'oublier ton pseudo note kfet."""}
436 helpmsg_default
="""Liste des commandes :
437 HELP Affiche de l'aide sur une commande.
438 CONNECT Ouvre une connection au serveur Note Kfet.
439 IDENTIFY Me permet de savoir qui tu es sur la note kfet.
440 DROP Me fait oublier ton identité.
441 SOLDE Obtenir ton solde"""
443 JOIN Faire rejoindre un chan
444 LEAVE Faire quitter un chan
445 QUIET Se taire sur un chan
446 NOQUIET Opposé de QUIET
447 LOST Perdre sur un chan
448 SOLDE <pseudo> Donner le solde de quelqu'un"""
450 SAY Fait envoyer un message sur un chan ou à une personne
451 DO Fait faire une action sur un chan
452 STAY Ignorera les prochains LEAVE pour un chan
453 NOSTAY Opposé de STAY
456 helpmsg
=helpmsg_default
457 if auteur
in self
.ops
:
459 if auteur
in self
.overops
:
460 helpmsg
+=helpmsg_overops
462 helpmsg
=helpdico
.get(message
[1].lower(),"Commande inconnue.")
463 for ligne
in helpmsg
.split("\n"):
464 serv
.privmsg(auteur
,ligne
)
465 elif cmd
=="identify":
467 if self
.identities
.has_key(auteur
):
468 serv
.privmsg(auteur
,"Je te connais sous le pseudo note %s."%(
469 self
.identities
[auteur
].encode("utf8")))
471 serv
.privmsg(auteur
,"Je ne connais pas ton pseudo note.")
472 elif len(message
)>=3:
473 username
,password
=message
[1],unicode(" ".join(message
[2:]),"utf8")
474 success
,_
=self
.new_connection_NK(serv
,username
,password
)
476 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
477 serv
.privmsg(auteur
,"Identité enregistrée.")
478 self
.identities
[auteur
]=username
479 pickle
.dump(self
.identities
,open("identities.pickle","w"))
481 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
482 serv
.privmsg(auteur
,"Mot de passe invalide. (ou serveur down)")
484 serv
.privmsg(auteur
,u
"Syntaxe : IDENTIFY [<username> <password>]")
487 if self
.identities
.has_key(auteur
):
488 password
=" ".join(message
[1:])
489 success
,_
=self
.new_connection_NK(serv
,self
.identities
[auteur
],password
)
491 del self
.identities
[auteur
]
492 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
493 pickle
.dump(self
.identities
,open("identities.pickle","w"))
494 serv
.privmsg(auteur
,"Identité oubliée.")
496 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
497 serv
.privmsg(auteur
,"Mot de passe invalide. (ou serveur down)")
499 serv
.privmsg(auteur
,"Je ne connais pas ton pseudo note.")
501 serv
.privmsg(auteur
,"Syntaxe : DROP <password>")
503 if auteur
in self
.ops
:
505 if message
[1] in self
.chanlist
:
506 serv
.privmsg(auteur
,"Je suis déjà sur %s"%(message
[1]))
508 serv
.join(message
[1])
509 self
.chanlist
.append(message
[1])
510 serv
.privmsg(auteur
,"Channels : "+" ".join(self
.chanlist
))
511 log(self
.serveur
,"priv",auteur
," ".join(message
))
513 serv
.privmsg(auteur
,"Channels : "+" ".join(self
.chanlist
))
517 if auteur
in self
.ops
and len(message
)>1:
518 if message
[1] in self
.chanlist
:
519 if not (message
[1] in self
.stay_channels
) or auteur
in self
.overops
:
520 serv
.part(message
[1])
521 self
.chanlist
.remove(message
[1])
522 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
524 serv
.privmsg(auteur
,"Non, je reste !")
525 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
527 serv
.privmsg(auteur
,"Je ne suis pas sur %s"%(message
[1]))
531 if auteur
in self
.overops
:
533 if message
[1] in self
.stay_channels
:
534 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
535 serv
.privmsg(auteur
,"Je stay déjà sur %s."%(message
[1]))
537 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
538 self
.stay_channels
.append(message
[1])
539 serv
.privmsg(auteur
,"Stay channels : "+" ".join(self
.stay_channels
))
541 serv
.privmsg(auteur
,"Stay channels : "+" ".join(self
.stay_channels
))
545 if auteur
in self
.overops
:
547 if message
[1] in self
.stay_channels
:
548 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
549 self
.stay_channels
.remove(message
[1])
550 serv
.privmsg(auteur
,"Stay channels : "+" ".join(self
.stay_channels
))
552 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
553 serv
.privmsg(auteur
,"Je ne stay pas sur %s."%(message
[1]))
558 if auteur
in self
.overops
:
559 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
564 if auteur
in self
.ops
:
566 if message
[1] in self
.quiet_channels
:
567 serv
.privmsg(auteur
,"Je me la ferme déjà sur %s"%(message
[1]))
568 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
570 self
.quiet_channels
.append(message
[1])
571 serv
.privmsg(auteur
,"Quiet channels : "+" ".join(self
.quiet_channels
))
572 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
574 serv
.privmsg(auteur
,"Quiet channels : "+" ".join(self
.quiet_channels
))
578 if auteur
in self
.ops
:
580 if message
[1] in self
.quiet_channels
:
581 self
.quiet_channels
.remove(message
[1])
582 serv
.privmsg(auteur
,"Quiet channels : "+" ".join(self
.quiet_channels
))
583 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
585 serv
.privmsg(auteur
,"Je ne me la ferme pas sur %s."%(message
[1]))
586 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
590 if auteur
in self
.overops
and len(message
)>2:
591 serv
.privmsg(message
[1]," ".join(message
[2:]))
592 log(self
.serveur
,"priv",auteur
," ".join(message
))
593 elif len(message
)<=2:
594 serv
.privmsg(auteur
,"Syntaxe : SAY <channel> <message>")
598 if auteur
in self
.overops
and len(message
)>2:
599 serv
.action(message
[1]," ".join(message
[2:]))
600 log(self
.serveur
,"priv",auteur
," ".join(message
))
601 elif len(message
)<=2:
602 serv
.privmsg(auteur
,"Syntaxe : DO <channel> <action>")
606 if auteur
in self
.overops
and len(message
)>2:
607 serv
.kick(message
[1],message
[2]," ".join(message
[3:]))
608 log(self
.serveur
,"priv",auteur
," ".join(message
))
609 elif len(message
)<=2:
610 serv
.privmsg(auteur
,"Syntaxe : KICK <channel> <pseudo>")
614 if auteur
in self
.ops
and len(message
)>1:
615 serv
.privmsg(message
[1],"J'ai perdu !")
616 log(self
.serveur
,"priv",auteur
," ".join(message
))
617 elif len(message
)<=1:
618 serv
.privmsg(auteur
,"Syntaxe : LOST <channel>")
623 if self
.identities
.has_key(auteur
):
625 self
.nk
.write('search ["x",["pseudo"],%s]'%(json
.dumps(self
.identities
[auteur
])))
626 ret
=json
.loads(self
.nk
.read())
627 solde
=ret
["msg"][0]["solde"]
628 pseudo
=ret
["msg"][0]["pseudo"]
629 except Exception as exc
:
631 serv
.privmsg(auteur
,"failed")
632 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
634 serv
.privmsg(auteur
,"%s (%s)"%(float(solde
)/100,pseudo
.encode("utf8")))
636 serv
.privmsg(canal
,"Je ne connais pas ton pseudo note.")
637 elif auteur
in self
.ops
:
639 self
.nk
.write('search ["x",["pseudo"],%s]'%(json
.dumps(message
[1])))
640 ret
=json
.loads(self
.nk
.read())
641 solde
=ret
["msg"][0]["solde"]
642 pseudo
=ret
["msg"][0]["pseudo"]
643 except Exception as exc
:
644 serv
.privmsg(auteur
,"failed")
645 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
647 serv
.privmsg(auteur
,"%s (%s)"%(float(solde
)/100,pseudo
.encode("utf8")))
651 serv
.privmsg(auteur
,"Je n'ai pas compris. Essaye HELP…")
653 def on_pubmsg(self
, serv
, ev
):
654 auteur
= irclib
.nm_to_n(ev
.source())
656 message
= ev
.arguments()[0]
658 test
=bot_unicode(message
)
659 except UnicodeBotError
:
660 if not canal
in self
.quiet_channels
:
662 "%s: Euh, tu fais de la merde avec ton encodage là, j'ai failli crasher…"%(auteur))
664 pour_moi
,message
=self
.pourmoi(serv
,message
)
665 if pour_moi
and message
.split()!=[]:
666 cmd
=message
.split()[0].lower()
668 args
=" ".join(message
.split()[1:])
671 if cmd
in ["meurs","die","crève"]:
672 if auteur
in self
.overops
:
673 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
676 serv
.privmsg(canal
,"%s: crève !"%(auteur))
677 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
679 elif cmd
in ["part","leave","dégage"]:
680 if auteur
in self
.ops
and (not (canal
in self
.stay_channels
)
681 or auteur
in self
.overops
):
682 serv
.part(canal
,message
="Éjecté par %s"%(auteur))
683 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
684 if canal
in self
.chanlist
:
685 self
.chanlist
.remove(canal
)
687 serv
.privmsg(canal
,"%s: Non, je reste !"%(auteur))
688 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
690 elif cmd
in ["reconnect"]:
691 if auteur
in self
.ops
:
693 self
.nk
=self
.new_connection_NK(serv
,config_note_pseudo
,
694 config_note_password
,"special")[1]
695 except Exception as exc
:
697 log(self
.serveur
,"""Erreur dans on_pubmsg/"cmd in ["reconnect"]\n"""+str(exc
))
699 serv
.privmsg(canal
,"%s: done"%(auteur))
700 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
702 serv
.privmsg(canal
,"%s: failed"%(auteur))
703 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
704 for report
in self
.report_bugs_to
:
705 serv
.privmsg(report
,"Connection to NK2015 failed, invalid password ?")
707 serv
.privmsg(canal
,"%s: crève !"%(auteur))
708 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
710 elif cmd
in ["deviens","pseudo"]:
711 if auteur
in self
.ops
:
714 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
716 if cmd
in ["meur", "meurt","meurre","meurres"] and not canal
in self
.quiet_channels
:
717 serv
.privmsg(canal
,'%s: Mourir, impératif, 2ème personne du singulier : "meurs" (de rien)'%(auteur))
718 elif cmd
in ["ping"] and not canal
in self
.quiet_channels
:
719 serv
.privmsg(canal
,"%s: pong"%(auteur))
721 elif cmd
in ["solde","!solde"]:
722 if self
.identities
.has_key(auteur
):
723 pseudo
=self
.identities
[auteur
]
725 self
.nk
.write('search ["x",["pseudo"],%s]'%(json
.dumps(pseudo
)))
726 ret
=json
.loads(self
.nk
.read())
727 solde
=ret
["msg"][0]["solde"]
728 pseudo
=ret
["msg"][0]["pseudo"]
729 except Exception as exc
:
730 serv
.privmsg(canal
,"%s: failed"%(auteur))
731 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
733 serv
.privmsg(canal
,"%s: %s (%s)"%(auteur
,float(solde
)/100,pseudo
.encode("utf8")))
734 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
736 serv
.privmsg(canal
,"%s: Je ne connais pas ton pseudo note."%(auteur))
737 log(self
.serveur
,canal
,auteur
,message
+"[unknown]")
738 elif (re
.match("!?(pain au chocolat|chocolatine)",message
.lower())
739 and not canal
in self
.quiet_channels
):
740 serv
.action(canal
,"sert un pain au chocolat à %s"%(auteur))
741 elif re
.match("!?manzana",message
.lower()) and not canal
in self
.quiet_channels
:
742 if auteur
=="[20-100]":
743 serv
.action(canal
,"sert une bouteille de manzana à %s"%(auteur))
745 serv
.action(canal
,"sert un verre de manzana à %s"%(auteur))
746 if is_insult(message
) and not canal
in self
.quiet_channels
:
747 if is_not_insult(message
):
748 answer
=random
.choice(config_compliment_answers
)
749 for ligne
in answer
.split("\n"):
750 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
752 answer
=random
.choice(config_insultes_answers
)
753 for ligne
in answer
.split("\n"):
754 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
755 if is_gros(message
) and not canal
in self
.quiet_channels
:
756 taille
=get_filesize()
757 answer
=u
"Mais non, je ne suis pas gros, %sKo tout au plus…"%(taille)
758 serv
.privmsg(canal
,"%s: %s"%(auteur
,answer
.encode("utf8")))
759 if is_tesla(message
) and not canal
in self
.quiet_channels
:
760 l1
,l2
=config_tesla_answers
,config_tesla_actions
761 n1
,n2
=len(l1
),len(l2
)
762 i
=random
.randrange(n1
+n2
)
764 serv
.action(canal
,l2
[i
-n1
].encode("utf8"))
766 serv
.privmsg(canal
,"%s: %s"%(auteur
,l1
[i
].encode("utf8")))
767 if is_tamere(message
) and not canal
in self
.quiet_channels
:
768 answer
=random
.choice(config_tamere_answers
)
769 for ligne
in answer
.split("\n"):
770 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
771 if is_tag(message
) and not canal
in self
.quiet_channels
:
772 if auteur
in self
.ops
:
773 action
=random
.choice(config_tag_actions
)
774 serv
.action(canal
,action
.encode("utf8"))
775 self
.quiet_channels
.append(canal
)
777 answer
=random
.choice(config_tag_answers
)
778 for ligne
in answer
.split("\n"):
779 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
780 if is_merci(message
):
781 answer
=random
.choice(config_merci_answers
)
782 for ligne
in answer
.split("\n"):
783 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
784 out
=re
.match(ur
"^([A-Z[]|\\|[0-9]+|(¹|²|³|⁴|⁵|⁶|⁷|⁸|⁹|⁰)+)(?:| \?| !)$",
785 unicode(message
.upper(),"utf8"))
786 if out
and not canal
in self
.quiet_channels
:
790 serv
.privmsg(canal
,"%s: %s !"%(auteur
,out
+1))
791 if out
+1>1000 and random
.randrange(4)==0:
792 serv
.privmsg(canal
,"%s: Tu sais, je peux continuer longtemps comme ça…"%(auteur))
794 serv
.privmsg(canal
,"%s: Tu croyais m'avoir sur le maxint ? J'suis en python mon vieux, 'va falloir trouver mieux…"%(auteur))
796 except Exception as exc
:
798 if re
.match("[A-Y]",out
):
799 alphabet
="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
800 serv
.privmsg(canal
,"%s: %s !"%(auteur
,alphabet
[alphabet
.index(out
)+1]))
802 serv
.privmsg(canal
,"%s: pfff, j'ai l'air malin maintenant… [ ?"%(auteur))
804 serv
.privmsg(canal
,"%s: nan mais il faut qu'on arrête, ça va finir par poser des problèmes…"%(auteur))
805 elif re
.match(ur
"(¹|²|³|⁴|⁵|⁶|⁷|⁸|⁹|⁰)+",out
):
807 return "".join([{u
"⁰¹²³⁴⁵⁶⁷⁸⁹0123456789"[i
]:u
"0123456789⁰¹²³⁴⁵⁶⁷⁸⁹"[i
]
808 for i
in range(20)}[j
]
810 out
=int(translate(out
))
811 serv
.privmsg(canal
,"%s: %s !"%(auteur
,translate(str(out
+1)).encode("utf8")))
812 if (not canal
in self
.quiet_channels
813 and re
.match((u
"^("+"|".join(config_bonjour
)+").*").lower(),message
.lower()) ):
814 answer
=random
.choice(config_bonjour_answers
)
815 serv
.privmsg(canal
,answer
.format(auteur
).encode("utf8"))
816 if is_pan(message
) and not canal
in self
.quiet_channels
:
817 serv
.privmsg(canal
,"%s: c'est pas sur moi qu'il faut tirer !"%(auteur))
819 if message
in ["!pain au chocolat","!chocolatine"] and not canal
in self
.quiet_channels
:
820 serv
.action(canal
,"sert un pain au chocolat à %s"%(auteur))
821 if message
in ["!manzana"] and not canal
in self
.quiet_channels
:
822 if auteur
=="[20-100]":
823 serv
.action(canal
,"sert une bouteille de manzana à %s"%(auteur))
825 serv
.action(canal
,"sert un verre de manzana à %s"%(auteur))
826 if re
.match('^(.|§|:|)(w|b) [0-9]+$',message
) and not canal
in self
.quiet_channels
:
827 failanswers
=config_buffer_fail_answers
828 answer
=random
.choice(failanswers
)
829 serv
.privmsg(canal
,"%s: %s"%(auteur
,answer
))
830 if not canal
in self
.quiet_channels
:
831 self
.try_tamere(serv
,canal
,auteur
,message
)
833 if re
.match((u
"^("+u
"|".join(config_bonjour
)
834 +u
")( {}| all| tout le monde|(|à) tous)(\.|( |)!|)$"
835 ).format(mypseudo
).lower(), message
.strip().lower()):
836 answer
=random
.choice(config_bonjour_answers
)
837 serv
.privmsg(canal
,answer
.format(auteur
).encode("utf8"))
838 if (is_perdu(message
) and not canal
in self
.quiet_channels
):
839 # proba de perdre sur trigger :
840 # avant 30min (enfin, config) : 0
841 # ensuite, +25%/30min, linéairement
842 deltat
=time
.time()-self
.last_perdu
843 barre
=(deltat
-config_time_between_perdu
)/(2*3600.0)
844 if random
.uniform(0,1)<barre
:
845 serv
.privmsg(canal
,"%s: J'ai perdu !"%(auteur))
846 self
.last_perdu
=time
.time()
848 def on_action(self
, serv
, ev
):
849 action
= ev
.arguments()[0]
850 auteur
= irclib
.nm_to_n(ev
.source())
851 channel
= ev
.target()
853 test
=bot_unicode(action
)
854 except UnicodeBotError
:
855 serv
.privmsg(channel
,
856 "%s : Euh, tu fais de la merde avec ton encodage là, j'ai failli crasher…"%(auteur))
860 if is_action_trigger(action
,mypseudo
) and not channel
in self
.quiet_channels
:
861 l1
,l2
=config_action_answers
,config_action_actions
862 n1
,n2
=len(l1
),len(l2
)
863 i
=random
.randrange(n1
+n2
)
865 serv
.action(channel
,l2
[i
-n1
].encode("utf8"))
867 serv
.privmsg(channel
,"%s: %s"%(auteur
,l1
[i
].encode("utf8")))
869 def on_kick(self
,serv
,ev
):
870 auteur
= irclib
.nm_to_n(ev
.source())
871 channel
= ev
.target()
872 victime
= ev
.arguments()[0]
873 raison
= ev
.arguments()[1]
874 if victime
==self
.nick
:
875 log(self
.serveur
,"%s kické par %s (raison : %s)" %(victime
,auteur
,raison
))
878 l1
,l2
=config_kick_action
,config_kick_answer
879 n1
,n2
=len(l1
),len(l2
)
880 i
=random
.randrange(n1
+n2
)
882 serv
.action(channel
,l2
[i
-n1
].encode("utf8"))
884 serv
.privmsg(channel
,"%s: %s"%(auteur
,l1
[i
].encode("utf8")))
887 return self
.serv
.get_nickname()
888 nick
=property(_getnick
)
891 if __name__
=="__main__":
894 print "Usage : basile.py <serveur> [--debug]"
897 if "debug" in sys
.argv
or "--debug" in sys
.argv
:
901 serveurs
={"a♡":"acoeur.crans.org","acoeur":"acoeur.crans.org","acoeur.crans.org":"acoeur.crans.org",
902 "irc":"irc.crans.org","crans":"irc.crans.org","irc.crans.org":"irc.crans.org"}
904 serveur
=serveurs
[serveur
]
906 print "Server Unknown : %s"%(serveur)
908 basile
=Basile(serveur
,debug
)