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]_", "PEB"]
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
=[
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, vous disiez ?",
55 u
"Je vais prendre ça pour un compliment.",
56 u
"Vous savez, pour vous c'est peut-être une insulte, mais pour moi ce n'est qu'une suite de 0 et de 1…",
57 u
"Permettez-moi de vous retourner le compliment.",
58 u
"Mais je ne vous permets pas !"]
60 config_gros
=[u
"gros",u
"énorme",u
"lourd"]
62 config_buffer_fail_answers
=["haha !","You type like you drive","encore un effort ;)"]
64 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))"
65 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)"
66 config_regexp_etre_avec_c
=u
"c'(e(s|st)|étai(t|ent))"
67 config_regexp_faire
=u
"fais"
68 config_perdu
=[u
"perd(|s|ons|ez|ent|r(e|ai|as|a|ons|ez|ont)|(|r)(ais|ait|ions|iez|aient))"
69 u
"perd(i(s|t|rent)|î(mes|tes|t))", # oui, j'ai inclus qu'il perdît
70 u
"perdiss(e(|s|nt)|i(ons|ez))",
71 u
"perdu(|s|e|es)",u
"perdant(|s|e|es)",u
"perte(|s)",
73 u
"(gagn|trouv)"+config_premier_groupe_terminaisons
,u
"gagnant(|s|e|es)",u
"gain(|s)",
75 u
"trouvant",u
"trouvaille(|s)",
77 u
"victoire(|s)",u
"vaincu(|s|e|es)",
78 u
"loose",u
"lost",u
"looser(|s)",u
"win(|ner)(|s)",
79 u
"jeu(|x)",u
"game(|s)"]
80 config_time_between_perdu_trigger
=3600*3 #temps moyen pour perdre en l'absence de trigger
81 config_time_between_perdu_trigger_delta
= 30*60 #marge autorisée autour de ^^^
82 config_time_between_perdu
=30*60 #temps pendant lequel on ne peut pas perdre
84 config_tag_triggers
=[u
"t(|a)g",u
"ta gueule",u
"la ferme",u
"ferme( |-)la",u
"tais-toi",u
"chut"]
85 config_tag_actions
=[u
"se tait",u
"se tient coi"]
86 config_tag_answers
=[u
"J'me tais si j'veux !",
87 u
"Je t'entends pas :°",
89 u
"Non, j'ai pas envie",
90 u
"Peut-être quand toi tu la fermeras, et encore…"]
92 config_tesla_triggers
=[u
"t('|u )es là \?",u
"\?",u
"plop \?",u
"plouf \?"]
93 config_tesla_answers
=[u
"Oui, je suis là",u
"Oui ?",u
"En quoi puis-je me rendre utile ?"]
94 config_tesla_actions
=[u
"est là",u
"attend des instructions",u
"is alive"]
96 config_compliment_triggers
=[u
"gentil",u
"cool",u
"sympa"]
97 config_compliment_answers
=[u
"Merci, c'est gentil :)",u
"Je te retourne le compliment",u
"C'est gentil ça."]
99 config_merci_triggers
=[u
"merci",u
"remercie",u
"thx",u
"thank(|s)"]
100 config_merci_answers
=[u
"Mais de rien.",u
"À ton service ;)",u
"Quand tu veux ^^",
101 u
"Tout le plaisir est pour moi."]
103 config_tamere_triggers
=[u
"ta mère"]
104 config_tamere_answers
=[u
"Laisse ma mère en dehors de ça !",
105 u
"Tu veux qu'on parle de ta soœur ?",
107 u
"Ce que fait ma mère c'est comme ce que tu fais avec ta bite, ça nous regarde pas…",
108 u
"♩ J'ai vu ta mère sur chat rouleeeeeeette ♫",
109 u
"On avait dit \"pas les mamans\""]
111 config_bad_action_triggers
=[u
"(frappe|cogne|tape)(| sur)",u
"(démolit|dégomme|fouette|agresse)",
112 u
"vomit sur",u
"slap(|s)"]
113 config_bad_action_answers
=[u
"Hey ! Mais qu'est-ce que j'ai fait ?",
116 u
"Mais j'ai rien demandé moi !"]
117 config_bad_action_actions
=[u
"prend de la distance, par précaution…",u
"part en courant",u
"esquive"]
119 config_good_action_triggers
=[u
"fait (:?des bisous|un c(?:â|a)lin|des c(?:â|a)lins) à",u
"embrasse",u
"c(?:â|a)line",u
"caresse"]
120 config_good_action_answers
=[u
"owi \o/",u
"c'est gentil ! ♡"]
121 config_good_action_actions
=[u
"ronronne",u
"est content"]
123 config_bonjour_triggers
=[u
"(s|)(a|'|)lu(t|)",u
"hello",u
"pl(o|i)p",u
"pr(ou|ü)t",u
"bonjour",u
"bonsoir",u
"coucou"]
124 config_bonjour_answers
=[u
"Salut {}",u
"Hello {} :)",u
"Bonjour {}",u
"Hello {}",u
"{}: hello",u
"{}: bonjour"]
126 config_bonne_nuit_triggers
=[u
"bonne nuit",u
"'?nite",u
"'?nuit",u
"'?night",u
"good night",u
"'?nunuit"]
127 config_bonne_nuit_answers
=[u
"{}: sweet dreams ;)",u
"Bonne nuit {} !",u
"À demain {}. :)","{}: dors bien ^^"]
129 config_kick_answers
=[u
"Ben qu'est-ce que j'ai fait ? :(",u
"Mais euh, j'ai rien fait de mal…","{} a le /kick facile :)"]
130 config_kick_actions
=[u
"se tiendra à carreaux",u
"essaiera de ne plus provoquer les foudres de {}"]
132 config_thisfile
= os
.path
.realpath( __file__
)
134 return ex("ls -s %s"%(config_thisfile))[1].split()[0]
136 class NKError(Exception):
137 def __init__(self
,msg
):
138 Exception.__init
__(self
)
142 def __unicode__(self
):
143 return unicode(self
.msg
)
145 class NKRefused(NKError
):
148 class NKHelloFailed(NKError
):
151 class NKUnknownError(NKError
):
154 def log(serveur
,channel
,auteur
=None,message
=None):
155 f
=open(get_config_logfile(serveur
),"a")
156 if auteur
==message
==None:
157 # alors c'est que c'est pas un channel mais juste une ligne de log
158 chain
="%s %s"%(time
.strftime("%F %T"),channel
)
160 chain
="%s [%s:%s] %s"%(time
.strftime("%F %T"),channel
,auteur
,message
)
162 if config_debug_stdout
:
169 # On établit la connexion sur port 4242
170 sock
.connect(("127.0.0.1",4242))
172 sock
=ssl
.wrap_socket(sock
,ca_certs
='../keys/ca_.crt')
174 sock
.write('hello "Basile"')
175 # On récupère la réponse du hello
178 except Exception as exc
:
179 # Si on a foiré quelque part, c'est que le serveur est down
180 raise NKRefused(str(exc
))
181 if out
["retcode"]==0:
183 elif out
["retcode"]==11:
184 raise NKHelloFailed(out
["errmsg"])
186 raise NKUnknownError(out
["errmsg"])
188 def login_NK(username
,password
,typ
="bdd"):
190 if typ
=="special": # ça c'est pour Basile lui-même
193 masque
='[["all"],["all"],false]'
195 # Basile a un compte special user
196 commande
='login [%s,%s,"%s",%s]'%(json
.dumps(username
),json
.dumps(password
),typ
,masque
)
199 except Exception as exc
:
200 # Si on a foiré quelque part, c'est que le serveur est down
201 raise NKRefused(str(exc
))
202 # On vérifie ensuite que le login
203 return json
.loads(out
),sock
206 def is_something(chain
,matches
,avant
=u
".*(?:^| )",apres
=u
"(?:$|\.| |,|;).*",case_sensitive
=False,debug
=False):
208 chain
=unicode(chain
,"utf8")
210 chain
=unicode(chain
,"utf8").lower()
211 allmatches
="("+"|".join(matches
)+")"
212 reg
=(avant
+allmatches
+apres
).lower()
213 o
=re
.match(reg
,chain
)
216 def is_insult(chain
,debug
=True):
217 return is_something(chain
,config_insultes
,avant
=".*(?:^| |')")
218 def is_not_insult(chain
):
219 chain
=unicode(chain
,"utf8")
220 insult_regexp
=u
"("+u
"|".join(config_insultes
)+u
")"
221 middle_regexp
=u
"(une? (?:(?:putain|enfoiré) d(?:e |'))*|)(?:| super )(?: (?:gros|petit|grand|énorme) |)"
222 reg
=".*pas %s%s.*"%(middle_regexp
,insult_regexp
)
223 if re
.match(reg
,chain
):
228 return is_something(chain
,config_perdu
)
230 return is_something(chain
,config_tag_triggers
)
232 return is_something(chain
,config_gros
)
234 return is_something(chain
,config_tesla_triggers
,avant
=u
"^",apres
=u
"$",debug
=True)
236 return is_something(chain
,config_merci_triggers
)
237 def is_tamere(chain
):
238 return is_something(chain
,config_tamere_triggers
)
239 def is_bad_action_trigger(chain
,pseudo
):
240 return is_something(chain
,config_bad_action_triggers
,avant
=u
"^",
241 apres
="(?: [a-z]*ment)? %s($|\.| |,|;).*"%(pseudo))
242 def is_good_action_trigger(chain
,pseudo
):
243 return is_something(chain
,config_good_action_triggers
,avant
=u
"^",
244 apres
="(?: [a-z]*ment)? %s($|\.| |,|;).*"%(pseudo))
245 def is_bonjour(chain
):
246 return is_something(chain
,config_bonjour_triggers
,avant
=u
"^")
247 def is_bonne_nuit(chain
):
248 return is_something(chain
,config_bonne_nuit_triggers
,avant
=u
"^")
250 return re
.match(u
"^(pan|bim|bang) .*$",unicode(chain
,"utf8").lower().strip())
254 class UnicodeBotError(Exception):
256 def bot_unicode(chain
):
258 unicode(chain
,"utf8")
259 except UnicodeDecodeError as exc
:
260 raise UnicodeBotError
262 class Basile(ircbot
.SingleServerIRCBot
):
263 def __init__(self
,serveur
,debug
=False):
264 temporary_pseudo
=config_irc_pseudo
+str(random
.randrange(10000,100000))
265 ircbot
.SingleServerIRCBot
.__init
__(self
, [(serveur
, 6667)],
266 temporary_pseudo
,"Basile, le bot irc.[Codé par 20-100, fouettez-le]", 10)
269 self
.overops
=config_overops
270 self
.ops
=self
.overops
+config_ops
271 self
.report_bugs_to
=config_report_bugs_to
272 self
.chanlist
=config_chanlist
274 self
.identities
=pickle
.load(open("identities.pickle","r"))
275 self
.stay_channels
=config_stay_channels
276 self
.quiet_channels
=config_quiet_channels
280 def new_connection_NK(self
,serv
,username
,password
,typ
="bdd"):
282 login_result
,sock
=login_NK(username
,password
,typ
)
283 droits
,retcode
,errmsg
=login_result
["msg"],login_result
["retcode"],login_result
["errmsg"]
284 except NKRefused
as exc
:
285 for report
in self
.report_bugs_to
:
286 serv
.privmsg(report
,"Le Serveur NK2015 est down.")
288 except NKHelloFailed
as exc
:
289 for report
in self
.report_bugs_to
:
291 "La version du site utilisée n'est pas supportée par le serveur NK2015.")
293 except NKUnknownError
as exc
:
294 erreurs
=["Une fucking erreur inconnue s'est produite"]
295 erreurs
+=str(exc
).split("\n")
296 for report
in self
.report_bugs_to
:
298 serv
.privmsg(report
,err
)
300 except Exception as exc
:
301 # Exception qui ne vient pas de la communication avec le serveur NK2015
302 log(self
.serveur
,"Erreur dans new_connection_NK\n"+str(exc
))
309 def give_me_my_pseudo(self
,serv
):
310 serv
.privmsg("NickServ","RECOVER %s %s"%(config_irc_pseudo
,config_irc_password
))
311 serv
.privmsg("NickServ","RELEASE %s %s"%(config_irc_pseudo
,config_irc_password
))
313 serv
.nick(config_irc_pseudo
)
315 def on_welcome(self
, serv
, ev
):
316 self
.serv
=serv
# ça serv ira :)
317 self
.give_me_my_pseudo(serv
)
318 serv
.privmsg("NickServ","identify %s"%(config_irc_password))
319 log(self
.serveur
,"Connected")
321 self
.chanlist
=["#bot"]
322 for c
in self
.chanlist
:
323 log(self
.serveur
,"JOIN %s"%(c))
325 # on ouvre la connexion note de Basile, special user
326 self
.nk
=self
.new_connection_NK(serv
,config_note_pseudo
,config_note_password
,"special")[1]
328 for report
in self
.report_bugs_to
:
329 serv
.privmsg(report
,"Connection to NK2015 failed, invalid password ?")
331 def lost(self
,serv
,channel
,forced
=False):
332 if self
.last_perdu
+config_time_between_perdu
<time
.time() or forced
:
333 if not channel
in self
.quiet_channels
or forced
:
334 serv
.privmsg(channel
,"J'ai perdu !")
335 self
.last_perdu
=time
.time()
336 delay
=config_time_between_perdu_trigger
337 delta
=config_time_between_perdu_trigger_delta
338 serv
.execute_delayed(random
.randrange(delay
-delta
,delay
+delta
),self
.lost
,(serv
,channel
))
340 def try_tamere(self
,serv
,channel
,auteur
,message
):
341 """Essaye de trigger un ta mère"""
342 #pas à chaque fois quand même
343 if random
.randrange(4)==0:
344 debuts
=u
"("+config_regexp_etre
+u
"|"+config_regexp_etre_avec_c
+u
")"
345 adjectifs
={u
"bon(|ne|s|nes)":u
"bonne",
346 u
"baisable(|s)":u
"baisable",
347 u
"faisable(|s)":u
"faisable",
348 u
"pas ch(ère(|s)|er(|s))":u
"pas chère",
349 u
"facile(|s)":u
"facile",
350 u
"chaud(|e|s|es)":u
"chaude",
351 u
"gratuit(|e|s|es)":u
"gratuite",
352 u
"payant(|e|s|es)":u
"payante",
353 u
"ouvert(|e|s|es)":u
"ouverte",
355 u
"plein(|s|es)":u
"pleine",
356 u
"bien plein(|e|s|es)":u
"bien pleine",
357 u
"innocent(|e|s|es)":u
"innocente"}
358 adj_reg
=u
"(?P<adjectif>"+u
"|".join(adjectifs
.keys())+u
")"
359 reg
=u
".*(^| |')"+debuts
+u
" "+adj_reg
+u
"($|,|;|\.| ).*"
360 matched
=re
.match(reg
,message
)
362 # il faut repasser l'adjectif au féminin singulier
363 found
=matched
.groupdict()["adjectif"]
364 for adj
in adjectifs
.keys():
365 if re
.match(adj
,found
):
366 adjectif
=adjectifs
[adj
]
368 serv
.privmsg(channel
,(u
"%s: c'est ta mère qui est %s !"%(auteur
,adjectif
)).encode("utf8"))
369 elif random
.randrange(5)==0:
370 # deuxième type de trigger, mais moins probable
371 matched
=re
.match(adj_reg
,message
)
373 found
=matched
.groupdict()["adjectif"]
374 for adj
in adjectifs
.keys():
375 if re
.match(adj
,found
):
376 adjectif
=adjectifs
[adj
]
378 fille
=random
.choice([u
"mère",u
"soœur"])
379 serv
.privmsg(channel
,(u
"%s: et ta %s, elle est %s ?"%
380 (auteur
,fille
,adjectif
)).encode("utf8"))
382 # troisième type de trigger
383 cpgt
=config_premier_groupe_terminaisons
384 verbes
={u
"tourn"+cpgt
:u
"tourne",
385 u
"balad"+cpgt
+u
" sur le trottoir":u
"se balade sur le trottoir",
386 u
"prom(e|è)n"+cpgt
+" sur le trottoir":u
"se promène sur le trottoir",
388 vb_reg
=u
".*(^| )(?P<verbe>"+"|".join(verbes
.keys())+")( |,|;|\.|$)"
389 matched
=re
.match(vb_reg
,message
)
391 found
=matched
.groupdict()["verbe"]
392 for vb
in verbes
.keys():
393 if re
.match(vb
,found
):
396 fille
=random
.choice([u
"mère",u
"soœur"])
397 serv
.privmsg(channel
,(u
"%s: et ta %s, elle %s ?"%
398 (auteur
,fille
,verbe
)).encode("utf8"))
399 def pourmoi(self
, serv
, message
):
400 """renvoie (False,lemessage) ou (True, le message amputé de "pseudo: ")"""
403 if message
[:size
]==pseudo
and len(message
)>size
and message
[size
]==":":
404 return (True,message
[size
+1:].lstrip(" "))
406 return (False,message
)
408 def on_privmsg(self
, serv
, ev
):
409 message
=ev
.arguments()[0]
410 auteur
= irclib
.nm_to_n(ev
.source())
412 test
=bot_unicode(message
)
413 except UnicodeBotError
:
415 "Euh, tu fais de la merde avec ton encodage là, j'ai failli crasher…")
417 message
=message
.split()
418 cmd
=message
[0].lower()
421 if not len(message
) in [2,3]:
422 serv
.privmsg(auteur
,"Syntaxe : CONNECT [<username>] <password>")
426 username
=(message
[1])
427 password
=" ".join(message
[2:])
429 password
=" ".join(message
[1:])
430 success
,sock
=self
.new_connection_NK(serv
,username
,password
)
432 self
.sockets
[username
]=sock
433 serv
.privmsg(auteur
,"Connection successful")
434 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
436 serv
.privmsg(auteur
,"Connection failed")
437 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
440 helpdico
={"connect": """CONNECT [<username>] <password>
441 Ouvre une connexion au serveur NoteKfet.
442 Si <username> n'est pas précisé, j'utiliserais l'identité sous laquelle je te connais, ou, à défaut, ton pseudo.""",
443 "identify": """IDENTIFY <username> <password>
444 Vérifie le mot de passe et me permet de savoir à l'avenir quel est ton pseudo note kfet.
445 Sans paramètre, je réponds sous quel pseudo je te connais.""",
446 "drop":"""DROP <password>
447 Vérifie le mot de passe et me fait d'oublier ton pseudo note kfet."""}
448 helpmsg_default
="""Liste des commandes :
449 HELP Affiche de l'aide sur une commande.
450 CONNECT Ouvre une connection au serveur Note Kfet.
451 IDENTIFY Me permet de savoir qui tu es sur la note kfet.
452 DROP Me fait oublier ton identité.
453 SOLDE Obtenir ton solde"""
455 JOIN Faire rejoindre un chan
456 LEAVE Faire quitter un chan
457 QUIET Se taire sur un chan
458 NOQUIET Opposé de QUIET
459 LOST Perdre sur un chan
460 SOLDE <pseudo> Donner le solde de quelqu'un"""
462 SAY Fait envoyer un message sur un chan ou à une personne
463 DO Fait faire une action sur un chan
464 STAY Ignorera les prochains LEAVE pour un chan
465 NOSTAY Opposé de STAY
468 helpmsg
=helpmsg_default
469 if auteur
in self
.ops
:
471 if auteur
in self
.overops
:
472 helpmsg
+=helpmsg_overops
474 helpmsg
=helpdico
.get(message
[1].lower(),"Commande inconnue.")
475 for ligne
in helpmsg
.split("\n"):
476 serv
.privmsg(auteur
,ligne
)
477 elif cmd
=="identify":
479 if self
.identities
.has_key(auteur
):
480 serv
.privmsg(auteur
,"Je te connais sous le pseudo note %s."%(
481 self
.identities
[auteur
].encode("utf8")))
483 serv
.privmsg(auteur
,"Je ne connais pas ton pseudo note.")
484 elif len(message
)>=3:
485 username
,password
=message
[1],unicode(" ".join(message
[2:]),"utf8")
486 success
,_
=self
.new_connection_NK(serv
,username
,password
)
488 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
489 serv
.privmsg(auteur
,"Identité enregistrée.")
490 self
.identities
[auteur
]=username
491 pickle
.dump(self
.identities
,open("identities.pickle","w"))
493 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
494 serv
.privmsg(auteur
,"Mot de passe invalide. (ou serveur down)")
496 serv
.privmsg(auteur
,u
"Syntaxe : IDENTIFY [<username> <password>]")
499 if self
.identities
.has_key(auteur
):
500 password
=" ".join(message
[1:])
501 success
,_
=self
.new_connection_NK(serv
,self
.identities
[auteur
],password
)
503 del self
.identities
[auteur
]
504 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
505 pickle
.dump(self
.identities
,open("identities.pickle","w"))
506 serv
.privmsg(auteur
,"Identité oubliée.")
508 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
509 serv
.privmsg(auteur
,"Mot de passe invalide. (ou serveur down)")
511 serv
.privmsg(auteur
,"Je ne connais pas ton pseudo note.")
513 serv
.privmsg(auteur
,"Syntaxe : DROP <password>")
515 if auteur
in self
.ops
:
517 if message
[1] in self
.chanlist
:
518 serv
.privmsg(auteur
,"Je suis déjà sur %s"%(message
[1]))
520 serv
.join(message
[1])
521 self
.chanlist
.append(message
[1])
522 serv
.privmsg(auteur
,"Channels : "+" ".join(self
.chanlist
))
523 log(self
.serveur
,"priv",auteur
," ".join(message
))
525 serv
.privmsg(auteur
,"Channels : "+" ".join(self
.chanlist
))
529 if auteur
in self
.ops
and len(message
)>1:
530 if message
[1] in self
.chanlist
:
531 if not (message
[1] in self
.stay_channels
) or auteur
in self
.overops
:
532 serv
.part(message
[1])
533 self
.chanlist
.remove(message
[1])
534 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
536 serv
.privmsg(auteur
,"Non, je reste !")
537 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
539 serv
.privmsg(auteur
,"Je ne suis pas sur %s"%(message
[1]))
543 if auteur
in self
.overops
:
545 if message
[1] in self
.stay_channels
:
546 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
547 serv
.privmsg(auteur
,"Je stay déjà sur %s."%(message
[1]))
549 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
550 self
.stay_channels
.append(message
[1])
551 serv
.privmsg(auteur
,"Stay channels : "+" ".join(self
.stay_channels
))
553 serv
.privmsg(auteur
,"Stay channels : "+" ".join(self
.stay_channels
))
557 if auteur
in self
.overops
:
559 if message
[1] in self
.stay_channels
:
560 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
561 self
.stay_channels
.remove(message
[1])
562 serv
.privmsg(auteur
,"Stay channels : "+" ".join(self
.stay_channels
))
564 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
565 serv
.privmsg(auteur
,"Je ne stay pas sur %s."%(message
[1]))
570 if auteur
in self
.overops
:
571 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
576 if auteur
in self
.ops
:
578 if message
[1] in self
.quiet_channels
:
579 serv
.privmsg(auteur
,"Je me la ferme déjà sur %s"%(message
[1]))
580 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
582 self
.quiet_channels
.append(message
[1])
583 serv
.privmsg(auteur
,"Quiet channels : "+" ".join(self
.quiet_channels
))
584 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
586 serv
.privmsg(auteur
,"Quiet channels : "+" ".join(self
.quiet_channels
))
590 if auteur
in self
.ops
:
592 if message
[1] in self
.quiet_channels
:
593 self
.quiet_channels
.remove(message
[1])
594 serv
.privmsg(auteur
,"Quiet channels : "+" ".join(self
.quiet_channels
))
595 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
597 serv
.privmsg(auteur
,"Je ne me la ferme pas sur %s."%(message
[1]))
598 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
602 if auteur
in self
.overops
and len(message
)>2:
603 serv
.privmsg(message
[1]," ".join(message
[2:]))
604 log(self
.serveur
,"priv",auteur
," ".join(message
))
605 elif len(message
)<=2:
606 serv
.privmsg(auteur
,"Syntaxe : SAY <channel> <message>")
610 if auteur
in self
.overops
and len(message
)>2:
611 serv
.action(message
[1]," ".join(message
[2:]))
612 log(self
.serveur
,"priv",auteur
," ".join(message
))
613 elif len(message
)<=2:
614 serv
.privmsg(auteur
,"Syntaxe : DO <channel> <action>")
618 if auteur
in self
.overops
and len(message
)>2:
619 serv
.kick(message
[1],message
[2]," ".join(message
[3:]))
620 log(self
.serveur
,"priv",auteur
," ".join(message
))
621 elif len(message
)<=2:
622 serv
.privmsg(auteur
,"Syntaxe : KICK <channel> <pseudo>")
626 if auteur
in self
.ops
and len(message
)>1:
627 serv
.privmsg(message
[1],"J'ai perdu !")
628 log(self
.serveur
,"priv",auteur
," ".join(message
))
629 elif len(message
)<=1:
630 serv
.privmsg(auteur
,"Syntaxe : LOST <channel>")
635 if self
.identities
.has_key(auteur
):
637 self
.nk
.write('search ["x",["pseudo"],%s]'%(json
.dumps(self
.identities
[auteur
])))
638 ret
=json
.loads(self
.nk
.read())
639 solde
=ret
["msg"][0]["solde"]
640 pseudo
=ret
["msg"][0]["pseudo"]
641 except Exception as exc
:
643 serv
.privmsg(auteur
,"failed")
644 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
646 serv
.privmsg(auteur
,"%s (%s)"%(float(solde
)/100,pseudo
.encode("utf8")))
648 serv
.privmsg(canal
,"Je ne connais pas ton pseudo note.")
649 elif auteur
in self
.ops
:
651 self
.nk
.write('search ["x",["pseudo"],%s]'%(json
.dumps(message
[1])))
652 ret
=json
.loads(self
.nk
.read())
653 solde
=ret
["msg"][0]["solde"]
654 pseudo
=ret
["msg"][0]["pseudo"]
655 except Exception as exc
:
656 serv
.privmsg(auteur
,"failed")
657 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
659 serv
.privmsg(auteur
,"%s (%s)"%(float(solde
)/100,pseudo
.encode("utf8")))
663 serv
.privmsg(auteur
,"Je n'ai pas compris. Essaye HELP…")
665 def on_pubmsg(self
, serv
, ev
):
666 auteur
= irclib
.nm_to_n(ev
.source())
668 message
= ev
.arguments()[0]
670 test
=bot_unicode(message
)
671 except UnicodeBotError
:
672 if not canal
in self
.quiet_channels
:
674 "%s: Euh, tu fais de la merde avec ton encodage là, j'ai failli crasher…"%(auteur))
676 pour_moi
,message
=self
.pourmoi(serv
,message
)
677 if pour_moi
and message
.split()!=[]:
678 cmd
=message
.split()[0].lower()
680 args
=" ".join(message
.split()[1:])
683 if cmd
in ["meurs","die","crève"]:
684 if auteur
in self
.overops
:
685 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
688 serv
.privmsg(canal
,"%s: crève !"%(auteur))
689 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
691 elif cmd
in ["part","leave","dégage"]:
692 if auteur
in self
.ops
and (not (canal
in self
.stay_channels
)
693 or auteur
in self
.overops
):
694 serv
.part(canal
,message
="Éjecté par %s"%(auteur))
695 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
696 if canal
in self
.chanlist
:
697 self
.chanlist
.remove(canal
)
699 serv
.privmsg(canal
,"%s: Non, je reste !"%(auteur))
700 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
702 elif cmd
in ["reconnect"]:
703 if auteur
in self
.ops
:
705 self
.nk
=self
.new_connection_NK(serv
,config_note_pseudo
,
706 config_note_password
,"special")[1]
707 except Exception as exc
:
709 log(self
.serveur
,"""Erreur dans on_pubmsg/"cmd in ["reconnect"]\n"""+str(exc
))
711 serv
.privmsg(canal
,"%s: done"%(auteur))
712 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
714 serv
.privmsg(canal
,"%s: failed"%(auteur))
715 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
716 for report
in self
.report_bugs_to
:
717 serv
.privmsg(report
,"Connection to NK2015 failed, invalid password ?")
719 serv
.privmsg(canal
,"%s: crève !"%(auteur))
720 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
722 elif cmd
in ["deviens","pseudo"]:
723 if auteur
in self
.ops
:
726 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
728 if cmd
in ["meur", "meurt","meurre","meurres"] and not canal
in self
.quiet_channels
:
729 serv
.privmsg(canal
,'%s: Mourir, impératif, 2ème personne du singulier : "meurs" (de rien)'%(auteur))
730 elif cmd
in ["ping"] and not canal
in self
.quiet_channels
:
731 serv
.privmsg(canal
,"%s: pong"%(auteur))
733 elif cmd
in ["solde","!solde"]:
734 if self
.identities
.has_key(auteur
):
735 pseudo
=self
.identities
[auteur
]
737 self
.nk
.write('search ["x",["pseudo"],%s]'%(json
.dumps(pseudo
)))
738 ret
=json
.loads(self
.nk
.read())
739 solde
=ret
["msg"][0]["solde"]
740 pseudo
=ret
["msg"][0]["pseudo"]
741 except Exception as exc
:
742 serv
.privmsg(canal
,"%s: failed"%(auteur))
743 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
745 serv
.privmsg(canal
,"%s: %s (%s)"%(auteur
,float(solde
)/100,pseudo
.encode("utf8")))
746 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
748 serv
.privmsg(canal
,"%s: Je ne connais pas ton pseudo note."%(auteur))
749 log(self
.serveur
,canal
,auteur
,message
+"[unknown]")
750 elif (re
.match("!?(pain au chocolat|chocolatine)",message
.lower())
751 and not canal
in self
.quiet_channels
):
752 serv
.action(canal
,"sert un pain au chocolat à %s"%(auteur))
753 elif re
.match("!?manzana",message
.lower()) and not canal
in self
.quiet_channels
:
754 if auteur
=="[20-100]":
755 serv
.action(canal
,"sert une bouteille de manzana à %s"%(auteur))
757 serv
.action(canal
,"sert un verre de manzana à %s"%(auteur))
758 if is_insult(message
) and not canal
in self
.quiet_channels
:
759 if is_not_insult(message
):
760 answer
=random
.choice(config_compliment_answers
)
761 for ligne
in answer
.split("\n"):
762 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
764 answer
=random
.choice(config_insultes_answers
)
765 for ligne
in answer
.split("\n"):
766 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
767 gros_match
=is_gros(message
)
768 if gros_match
and not canal
in self
.quiet_channels
:
769 taille
=get_filesize()
770 answer
=u
"Mais non, je ne suis pas %s, %sKo tout au plus…"%(gros_match
.groups()[0],taille
)
771 serv
.privmsg(canal
,"%s: %s"%(auteur
,answer
.encode("utf8")))
772 if is_tesla(message
) and not canal
in self
.quiet_channels
:
773 l1
,l2
=config_tesla_answers
,config_tesla_actions
774 n1
,n2
=len(l1
),len(l2
)
775 i
=random
.randrange(n1
+n2
)
777 serv
.action(canal
,l2
[i
-n1
].encode("utf8"))
779 serv
.privmsg(canal
,"%s: %s"%(auteur
,l1
[i
].encode("utf8")))
780 if is_tamere(message
) and not canal
in self
.quiet_channels
:
781 answer
=random
.choice(config_tamere_answers
)
782 for ligne
in answer
.split("\n"):
783 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
784 if is_tag(message
) and not canal
in self
.quiet_channels
:
785 if auteur
in self
.ops
:
786 action
=random
.choice(config_tag_actions
)
787 serv
.action(canal
,action
.encode("utf8"))
788 self
.quiet_channels
.append(canal
)
790 answer
=random
.choice(config_tag_answers
)
791 for ligne
in answer
.split("\n"):
792 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
793 if is_merci(message
):
794 answer
=random
.choice(config_merci_answers
)
795 for ligne
in answer
.split("\n"):
796 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
797 out
=re
.match(ur
"^([A-Z[]|\\|[0-9]+|(¹|²|³|⁴|⁵|⁶|⁷|⁸|⁹|⁰)+)(?:| \?| !)$",
798 unicode(message
.upper(),"utf8"))
799 if out
and not canal
in self
.quiet_channels
:
803 serv
.privmsg(canal
,"%s: %s !"%(auteur
,out
+1))
804 if out
+1>1000 and random
.randrange(4)==0:
805 serv
.privmsg(canal
,"%s: Tu sais, je peux continuer longtemps comme ça…"%(auteur))
807 serv
.privmsg(canal
,"%s: Tu croyais m'avoir sur le maxint ? J'suis en python mon vieux, 'va falloir trouver mieux…"%(auteur))
809 except Exception as exc
:
811 if re
.match("[A-Y]",out
):
812 alphabet
="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
813 serv
.privmsg(canal
,"%s: %s !"%(auteur
,alphabet
[alphabet
.index(out
)+1]))
815 serv
.privmsg(canal
,"%s: pfff, j'ai l'air malin maintenant… [ ?"%(auteur))
817 serv
.privmsg(canal
,"%s: nan mais il faut qu'on arrête, ça va finir par poser des problèmes…"%(auteur))
818 elif re
.match(ur
"(¹|²|³|⁴|⁵|⁶|⁷|⁸|⁹|⁰)+",out
):
820 return "".join([{u
"⁰¹²³⁴⁵⁶⁷⁸⁹0123456789"[i
]:u
"0123456789⁰¹²³⁴⁵⁶⁷⁸⁹"[i
]
821 for i
in range(20)}[j
]
823 out
=int(translate(out
))
824 serv
.privmsg(canal
,"%s: %s !"%(auteur
,translate(str(out
+1)).encode("utf8")))
825 if is_bonjour(message
) and not canal
in self
.quiet_channels
:
826 answer
=random
.choice(config_bonjour_answers
)
827 serv
.privmsg(canal
,answer
.format(auteur
).encode("utf8"))
828 if is_bonne_nuit(message
) and not canal
in self
.quiet_channels
:
829 answer
=random
.choice(config_bonne_nuit_answers
)
830 serv
.privmsg(canal
,answer
.format(auteur
).encode("utf8"))
831 if is_pan(message
) and not canal
in self
.quiet_channels
:
832 serv
.privmsg(canal
,"%s: c'est pas sur moi qu'il faut tirer !"%(auteur))
834 if message
in ["!pain au chocolat","!chocolatine"] and not canal
in self
.quiet_channels
:
835 serv
.action(canal
,"sert un pain au chocolat à %s"%(auteur))
836 if message
in ["!manzana"] and not canal
in self
.quiet_channels
:
837 if auteur
=="[20-100]":
838 serv
.action(canal
,"sert une bouteille de manzana à %s"%(auteur))
840 serv
.action(canal
,"sert un verre de manzana à %s"%(auteur))
841 if re
.match('^(.|§|:|)(w|b) [0-9]+$',message
) and not canal
in self
.quiet_channels
:
842 failanswers
=config_buffer_fail_answers
843 answer
=random
.choice(failanswers
)
844 serv
.privmsg(canal
,"%s: %s"%(auteur
,answer
))
845 if not canal
in self
.quiet_channels
:
846 self
.try_tamere(serv
,canal
,auteur
,message
)
848 if re
.match((u
"^("+u
"|".join(config_bonjour_triggers
)
849 +u
")( {}| all| tout le monde|(|à) tous)(\.|( |)!|)$"
850 ).format(mypseudo
).lower(), message
.strip().lower()):
851 answer
=random
.choice(config_bonjour_answers
)
852 serv
.privmsg(canal
,answer
.format(auteur
).encode("utf8"))
853 if (is_perdu(message
) and not canal
in self
.quiet_channels
):
854 # proba de perdre sur trigger :
855 # avant 30min (enfin, config) : 0
856 # ensuite, +25%/30min, linéairement
857 deltat
=time
.time()-self
.last_perdu
858 barre
=(deltat
-config_time_between_perdu
)/(2*3600.0)
859 if random
.uniform(0,1)<barre
:
860 serv
.privmsg(canal
,"%s: J'ai perdu !"%(auteur))
861 self
.last_perdu
=time
.time()
863 def on_action(self
, serv
, ev
):
864 action
= ev
.arguments()[0]
865 auteur
= irclib
.nm_to_n(ev
.source())
866 channel
= ev
.target()
868 test
=bot_unicode(action
)
869 except UnicodeBotError
:
870 serv
.privmsg(channel
,
871 "%s : Euh, tu fais de la merde avec ton encodage là, j'ai failli crasher…"%(auteur))
875 if is_bad_action_trigger(action
,mypseudo
) and not channel
in self
.quiet_channels
:
876 l1
,l2
=config_bad_action_answers
,config_bad_action_actions
877 n1
,n2
=len(l1
),len(l2
)
878 i
=random
.randrange(n1
+n2
)
880 serv
.action(channel
,l2
[i
-n1
].encode("utf8"))
882 serv
.privmsg(channel
,"%s: %s"%(auteur
,l1
[i
].encode("utf8")))
883 if is_good_action_trigger(action
,mypseudo
) and not channel
in self
.quiet_channels
:
884 l1
,l2
=config_good_action_answers
,config_good_action_actions
885 n1
,n2
=len(l1
),len(l2
)
886 i
=random
.randrange(n1
+n2
)
888 serv
.action(channel
,l2
[i
-n1
].encode("utf8"))
890 serv
.privmsg(channel
,"%s: %s"%(auteur
,l1
[i
].encode("utf8")))
892 def on_kick(self
,serv
,ev
):
893 auteur
= irclib
.nm_to_n(ev
.source())
894 channel
= ev
.target()
895 victime
= ev
.arguments()[0]
896 raison
= ev
.arguments()[1]
897 if victime
==self
.nick
:
898 log(self
.serveur
,"%s kické par %s (raison : %s)" %(victime
,auteur
,raison
))
901 l1
,l2
=config_kick_answers
,config_kick_actions
902 n1
,n2
=len(l1
),len(l2
)
903 i
=random
.randrange(n1
+n2
)
905 serv
.action(channel
,l2
[i
-n1
].format(auteur
).encode("utf8"))
907 serv
.privmsg(channel
,"%s: %s"%(auteur
,l1
[i
].format(auteur
).encode("utf8")))
910 return self
.serv
.get_nickname()
911 nick
=property(_getnick
)
914 if __name__
=="__main__":
917 print "Usage : basile.py <serveur> [--debug]"
920 if "debug" in sys
.argv
or "--debug" in sys
.argv
:
924 serveurs
={"a♡":"acoeur.crans.org","acoeur":"acoeur.crans.org","acoeur.crans.org":"acoeur.crans.org",
925 "irc":"irc.crans.org","crans":"irc.crans.org","irc.crans.org":"irc.crans.org"}
927 serveur
=serveurs
[serveur
]
929 print "Server Unknown : %s"%(serveur)
931 basile
=Basile(serveur
,debug
)