4 # Codé par 20-100 le 23/04/12
6 # Un test de bot irc, parce que c'est cool
13 import socket
, ssl
, json
17 from commands
import getstatusoutput
as ex
20 config_debug_stdout
=True
21 if "--quiet" in sys
.argv
:
22 config_debug_stdout
=False
24 config_irc_password
="NK2015BasileB0t"
25 config_irc_pseudo
="Basile"
26 config_chanlist
=["#bot","#flood"]
27 config_stay_channels
=["#bot","#flood"]
28 config_quiet_channels
=[]
29 config_note_pseudo
="Basile"
30 config_note_password
="NK2015BasileB0tr4nd0omp4assword]6_+{#]78{"
31 config_logfile_template
="basile.%s.log"
32 def get_config_logfile(serveur
):
33 serveurs
={"acoeur.crans.org":"acoeur","irc.crans.org":"crans"}
34 return config_logfile_template
%(serveurs
[serveur
])
35 config_overops
=["[20-100]","[20-100]_"]
36 config_ops
=["PEB","Nit"]
37 config_report_bugs_to
=["[20-100]"]
39 config_insultes
=[u
"conna(rd|sse)",u
"pute",u
"con(|ne)",u
"enf(oiré|lure)",
40 u
"sal(op(|e(|rie)|ard)|aud)",u
"p(e|')tite bite",u
"imbécile",u
"idiot",u
"stupid(|e)",u
"débile",u
"crétin",
41 u
"pétasse",u
"enculé",u
"chagasse",u
"cagole",u
"abruti",u
"ahuri",u
"analphabète",u
"andouille",
42 u
"atardé",u
"avorton",u
"bachibouzouk",u
"(balais|brosse) (de|à) chiotte(|s)",
43 u
"batard",u
"blaireau",u
"bouffon",u
"branque",u
"bouseux",u
"branleur",u
"catin",u
"chacal",
44 u
"charogne",u
"chiant(|e)",u
"chieur",u
"cochon",u
"coprophage",u
"couillon",u
"crapule",u
"crevard",
45 u
"cruche",u
"cuistre",u
"ducon",u
"décérébré",
46 u
"emmerdeur",u
"feignasse",u
"fainéant",u
"fourbe",u
"freluquet",u
"frigide",
47 u
"garce",u
"glandu",u
"gogol",u
"goujat",u
"gourdasse",u
"gredin",u
"gringalet",u
"grognasse",
48 u
"naze",u
"truie",u
"iconoclaste",
49 u
"peigne(-|)cul",u
"ignare",u
"illétré",u
"lèche(|-)cul",u
"malotru",u
"motherfucker",u
"nabot",u
"nigaud",
50 u
"nul",u
"escroc",u
"pouffiasse",u
"pourriture",u
"raclure",u
"relou",u
"sagouin",u
"putain",
52 config_insultes_answers
=[u
"toi-même",
53 u
"Oh non ! Quelle insulte ! Je crois que je ne m'en reléverai jamais…\nAh si, ça y est.",
54 u
"J'entends comme un vague murmure, tu disais ?",
55 u
"Je vais prendre ça pour un compliment.",
56 u
"Tu sais, pour toi c'est peut-être une insulte, mais pour moi ce n'est qu'une suite de 0 et de 1…",
57 u
"Si tu allais voir sur un autre chan si j'y suis ?",
58 u
"Permets-moi de te retourner le compliment.",
59 u
"Mais je ne te permets pas !"]
63 config_buffer_fail_answers
=["haha !","You type like you drive","encore un effort ;)"]
65 config_premier_groupe_terminaisons
=u
"(e|es|ons|ez|ent|er(|ai|as|a|ons|ez|ont)|(|er)(ais|ait|ions|iez|aient)|(a(i|s|)|â(mes|tes|t)|èrent)|ass(e(|s|nt)|i(ons|ez))|é(|s|e|es))"
66 config_regexp_etre
=u
"(être|suis|e(s|t)|so(mmes|nt)|êtes|(ét|ser)(ai(s|t|ent)|i(ons|ent)|)|ser(ai|as|a|ons|ez|ont)|so(i(s|t|ent)|y(ons|ez))|f(u(s|t|rent)|û(mes|tes|t))|fuss(e(|s|nt)|i(ons|ez))|étant)"
67 config_regexp_etre_avec_c
=u
"c'(e(s|st)|étai(t|ent))"
68 config_regexp_faire
=u
"fais"
69 config_perdu
=[u
"perd(|s|ons|ez|ent|r(e|ai|as|a|ons|ez|ont)|(|r)(ais|ait|ions|iez|aient))"
70 u
"perd(i(s|t|rent)|î(mes|tes|t))", # oui, j'ai inclus qu'il perdît
71 u
"perdiss(e(|s|nt)|i(ons|ez))",
72 u
"perdu(|s|e|es)",u
"perdant(|s|e|es)",u
"perte(|s)",
74 u
"(gagn|trouv)"+config_premier_groupe_terminaisons
,u
"gagnant(|s|e|es)",u
"gain(|s)",
76 u
"trouvant",u
"trouvaille(|s)",
78 u
"victoire(|s)",u
"vaincu(|s|e|es)",
79 u
"loose",u
"lost",u
"looser(|s)",u
"win(|ner)(|s)",
80 u
"jeu(|x)",u
"game(|s)"]
81 config_time_between_perdu_trigger
=3600*3 #temps moyen pour perdre en l'absence de trigger
82 config_time_between_perdu_trigger_delta
= 30*60 #marge autorisée autour de ^^^
83 config_time_between_perdu
=30*60 #temps pendant lequel on ne peut pas perdre
85 config_tag
=[u
"t(|a)g",u
"ta gueule",u
"la ferme",u
"ferme( |-)la",u
"tais-toi",u
"chut"]
86 config_tag_actions
=[u
"se tait",u
"ferme sa gueule",u
"se la ferme",u
"la ferme"]
87 config_tag_answers
=[u
"J'me tais si j'veux !",
88 u
"Je t'entends pas :°",
90 u
"Non, j'ai pas envie",
91 u
"Peut-être quand toi tu la fermeras, et encore…"]
93 config_tesla
=[u
"t('|u )es là \?",u
"\?",u
"plop \?",u
"plouf \?"]
94 config_tesla_answers
=[u
"Oui, je suis là",u
"Oui ?",u
"En quoi puis-je me rendre utile ?"]
95 config_tesla_actions
=[u
"est là",u
"attend des instructions",u
"is alive"]
97 config_compliment
=[u
"gentil",u
"cool",u
"sympa"]
98 config_compliment_answers
=[u
"Merci, c'est gentil :)",u
"Je te retourne le compliment",u
"C'est gentil ça."]
100 config_merci
=[u
"merci",u
"remercie",u
"thx",u
"thank(|s)"]
101 config_merci_answers
=[u
"Mais de rien.",u
"À ton service ;)",u
"Quand tu veux ^^",
102 u
"Tout le plaisir est pour moi."]
104 config_tamere
=[u
"ta mère"]
105 config_tamere_answers
=[u
"Laisse ma mère en dehors de ça !",
106 u
"Tu veux qu'on parle de ta soœur ?",
108 u
"Ce que fait ma mère c'est comme ce que tu fais avec ta bite, ça nous regarde pas…",
109 u
"♩ J'ai vu ta mère sur chat rouleeeeeeette ♫"
110 u
"On avait dit \"pas les mamans\""]
112 config_action_trigger
=[u
"(frappe|cogne|tape)(| sur)",u
"démolit",u
"vomit sur",u
"slap(|s)"]
113 config_action_answers
=[u
"Hey ! Mais qu'est-ce que j'ai fait ?",
116 u
"Mais j'ai rien demandé moi !"]
117 config_action_actions
=[u
"prend de la distance, par précaution…",u
"part en courant"]
119 config_bonjour
=[u
"(s|)(a|'|)lu(t|)",u
"hello",u
"plop",u
"plip",u
"pr(ou|ü)t",u
"bonjour",u
"bonsoir"]
120 config_bonjour_answers
=[u
"Salut {}",u
"Hello {} :)",u
"Bonjour {}",u
"Hello {}",u
"{}: hello",u
"{}: bonjour"]
123 config_thisfile
= os
.path
.realpath( __file__
)
125 return ex("ls -s %s"%(config_thisfile))[1].split()[0]
127 class NKError(Exception):
128 def __init__(self
,msg
):
129 Exception.__init
__(self
)
133 def __unicode__(self
):
134 return unicode(self
.msg
)
136 class NKRefused(NKError
):
139 class NKHelloFailed(NKError
):
142 class NKUnknownError(NKError
):
145 def log(serveur
,channel
,auteur
=None,message
=None):
146 f
=open(get_config_logfile(serveur
),"a")
147 if auteur
==message
==None:
148 # alors c'est que c'est pas un channel mais juste une ligne de log
149 chain
="%s %s"%(time
.strftime("%F %T"),channel
)
151 chain
="%s [%s:%s] %s"%(time
.strftime("%F %T"),channel
,auteur
,message
)
153 if config_debug_stdout
:
160 # On établit la connexion sur port 4242
161 sock
.connect(("127.0.0.1",4242))
163 sock
=ssl
.wrap_socket(sock
,ca_certs
='../keys/ca_.crt')
165 sock
.write('hello "Basile"')
166 # On récupère la réponse du hello
169 except Exception as exc
:
170 # Si on a foiré quelque part, c'est que le serveur est down
171 raise NKRefused(str(exc
))
172 if out
["retcode"]==0:
174 elif out
["retcode"]==11:
175 raise NKHelloFailed(out
["errmsg"])
177 raise NKUnknownError(out
["errmsg"])
179 def login_NK(username
,password
,typ
="bdd"):
182 # Basile a un compte special user
183 commande
='login [%s,%s,"%s"]'%(json
.dumps(username
),json
.dumps(password
),typ
)
186 except Exception as exc
:
187 # Si on a foiré quelque part, c'est que le serveur est down
188 raise NKRefused(str(exc
))
189 # On vérifie ensuite que le login
190 return json
.loads(out
),sock
193 def is_something(chain
,matches
,avant
=u
".*(^| )",apres
=u
"($|\.| |,|;).*",case_sensitive
=False,debug
=False):
195 chain
=unicode(chain
,"utf8")
197 chain
=unicode(chain
,"utf8").lower()
198 allmatches
="("+"|".join(matches
)+")"
199 reg
=(avant
+allmatches
+apres
).lower()
200 if re
.match(reg
,chain
):
204 def is_insult(chain
,debug
=True):
205 return is_something(chain
,config_insultes
,avant
=".*(^| |')")
206 def is_not_insult(chain
):
207 chain
=unicode(chain
,"utf8")
208 insult_regexp
=u
"("+u
"|".join(config_insultes
)+u
")"
209 middle_regexp
=u
"(un(|e) ((putain|enfoiré) d(e |'))*|)(| super )( (gros|petit|grand|énorme) |)"
210 reg
=".*pas %s%s.*"%(middle_regexp
,insult_regexp
)
211 if re
.match(reg
,chain
):
216 return is_something(chain
,config_perdu
)
218 return is_something(chain
,config_tag
)
220 return is_something(chain
,config_gros
)
222 return is_something(chain
,config_tesla
,avant
=u
"^",apres
=u
"$",debug
=True)
224 return is_something(chain
,config_merci
)
225 def is_tamere(chain
):
226 return is_something(chain
,config_tamere
)
227 def is_action_trigger(chain
,pseudo
):
228 return is_something(chain
,config_action_trigger
,avant
=u
"^",apres
=" %s($|\.| |,|;).*"%(pseudo))
230 return re
.match(u
"^(pan|bim|bang)$",unicode(chain
,"utf8").lower().strip())
234 class UnicodeBotError(Exception):
236 def bot_unicode(chain
):
238 unicode(chain
,"utf8")
239 except UnicodeDecodeError as exc
:
240 raise UnicodeBotError
242 class Basile(ircbot
.SingleServerIRCBot
):
243 def __init__(self
,serveur
,debug
=False):
244 temporary_pseudo
=config_irc_pseudo
+str(random
.randrange(10000,100000))
245 ircbot
.SingleServerIRCBot
.__init
__(self
, [(serveur
, 6667)],
246 temporary_pseudo
,"Basile, le bot irc.[Codé par 20-100, fouettez-le]", 10)
249 self
.overops
=config_overops
250 self
.ops
=self
.overops
+config_ops
251 self
.report_bugs_to
=config_report_bugs_to
252 self
.chanlist
=config_chanlist
254 self
.identities
=pickle
.load(open("identities.pickle","r"))
255 self
.stay_channels
=config_stay_channels
256 self
.quiet_channels
=config_quiet_channels
260 def new_connection_NK(self
,serv
,username
,password
,typ
="bdd"):
262 login_result
,sock
=login_NK(username
,password
,typ
)
263 droits
,retcode
,errmsg
=login_result
["msg"],login_result
["retcode"],login_result
["errmsg"]
264 except NKRefused
as exc
:
265 for report
in self
.report_bugs_to
:
266 serv
.privmsg(report
,"Le Serveur NK2015 est down.")
268 except NKHelloFailed
as exc
:
269 for report
in self
.report_bugs_to
:
271 "La version du site utilisée n'est pas supportée par le serveur NK2015.")
273 except NKUnknownError
as exc
:
274 erreurs
=["Une fucking erreur inconnue s'est produite"]
275 erreurs
+=str(exc
).split("\n")
276 for report
in self
.report_bugs_to
:
278 serv
.privmsg(report
,err
)
280 except Exception as exc
:
281 # Exception qui ne vient pas de la communication avec le serveur NK2015
282 log(self
.serveur
,"Erreur dans new_connection_NK\n"+str(exc
))
289 def give_me_my_pseudo(self
,serv
):
290 serv
.privmsg("NickServ","RECOVER %s %s"%(config_irc_pseudo
,config_irc_password
))
291 serv
.privmsg("NickServ","RELEASE %s %s"%(config_irc_pseudo
,config_irc_password
))
293 serv
.nick(config_irc_pseudo
)
295 def on_welcome(self
, serv
, ev
):
296 self
.give_me_my_pseudo(serv
)
297 serv
.privmsg("NickServ","identify %s"%(config_irc_password))
298 log(self
.serveur
,"Connected")
300 self
.chanlist
=["#bot"]
301 for c
in self
.chanlist
:
302 log(self
.serveur
,"JOIN %s"%(c))
304 # on ouvre la connexion note de Basile, special user
305 self
.nk
=self
.new_connection_NK(serv
,config_note_pseudo
,config_note_password
,"special")[1]
307 for report
in self
.report_bugs_to
:
308 serv
.privmsg(report
,"Connection to NK2015 failed, invalid password ?")
310 def lost(self
,serv
,channel
,forced
=False):
311 if self
.last_perdu
+config_time_between_perdu
<time
.time() or forced
:
312 if not channel
in self
.quiet_channels
or forced
:
313 serv
.privmsg(channel
,"J'ai perdu !")
314 self
.last_perdu
=time
.time()
315 delay
=config_time_between_perdu_trigger
316 delta
=config_time_between_perdu_trigger_delta
317 serv
.execute_delayed(random
.randrange(delay
-delta
,delay
+delta
),self
.lost
,(serv
,channel
))
319 def try_tamere(self
,serv
,channel
,auteur
,message
):
320 """Essaye de trigger un ta mère"""
321 #pas à chaque fois quand même
322 if random
.randrange(4)==0:
323 debuts
=u
"("+config_regexp_etre
+u
"|"+config_regexp_etre_avec_c
+u
")"
324 adjectifs
={u
"bon(|ne|s|nes)":u
"bonne",
325 u
"baisable(|s)":u
"baisable",
326 u
"faisable(|s)":u
"faisable",
327 u
"pas ch(ère(|s)|er(|s))":u
"pas chère",
328 u
"facile(|s)":u
"facile",
329 u
"chaud(|e|s|es)":u
"chaude",
330 u
"gratuit(|e|s|es)":u
"gratuite",
331 u
"payant(|e|s|es)":u
"payante",
332 u
"ouvert(|e|s|es)":u
"ouverte",
334 u
"plein(|s|es)":u
"pleine",
335 u
"bien plein(|e|s|es)":u
"bien pleine"}
336 adj_reg
=u
"(?P<adjectif>"+u
"|".join(adjectifs
.keys())+u
")"
337 reg
=u
".*(^| )"+debuts
+u
" "+adj_reg
+u
"($|,|;|\.| ).*"
338 matched
=re
.match(reg
,message
)
340 # il faut repasser l'adjectif au féminin singulier
341 found
=matched
.groupdict()["adjectif"]
342 for adj
in adjectifs
.keys():
343 if re
.match(adj
,found
):
344 adjectif
=adjectifs
[adj
]
346 serv
.privmsg(channel
,(u
"%s: c'est ta mère qui est %s !"%(auteur
,adjectif
)).encode("utf8"))
347 elif random
.randrange(5)==0:
348 # deuxième type de trigger, mais moins probable
349 matched
=re
.match(adj_reg
,message
)
351 found
=matched
.groupdict()["adjectif"]
352 for adj
in adjectifs
.keys():
353 if re
.match(adj
,found
):
354 adjectif
=adjectifs
[adj
]
356 fille
=random
.choice([u
"mère",u
"soœur"])
357 serv
.privmsg(channel
,(u
"%s: et ta %s, elle est %s ?"%
358 (auteur
,fille
,adjectif
)).encode("utf8"))
360 # troisième type de trigger
361 cpgt
=config_premier_groupe_terminaisons
362 verbes
={u
"tourn"+cpgt
:u
"tourne",
363 u
"balad"+cpgt
+u
" sur le trottoir":u
"se balade sur le trottoir",
364 u
"prom(e|è)n"+cpgt
+" sur le trottoir":u
"se promène sur le trottoir",
366 vb_reg
=u
".*(^| )(?P<verbe>"+"|".join(verbes
.keys())+")( |,|;|\.|$)"
367 matched
=re
.match(vb_reg
,message
)
369 found
=matched
.groupdict()["verbe"]
370 for vb
in verbes
.keys():
371 if re
.match(vb
,found
):
374 fille
=random
.choice([u
"mère",u
"soœur"])
375 serv
.privmsg(channel
,(u
"%s: et ta %s, elle %s ?"%
376 (auteur
,fille
,verbe
)).encode("utf8"))
377 def pourmoi(self
, serv
, message
):
378 """renvoie (False,lemessage) ou (True, le message amputé de "pseudo: ")"""
379 pseudo
=serv
.get_nickname()
381 if message
[:size
]==pseudo
and message
[size
]==":":
382 return (True,message
[size
+1:].lstrip(" "))
384 return (False,message
)
386 def on_privmsg(self
, serv
, ev
):
387 message
=ev
.arguments()[0]
388 auteur
= irclib
.nm_to_n(ev
.source())
390 test
=bot_unicode(message
)
391 except UnicodeBotError
:
393 "Euh, tu fais de la merde avec ton encodage là, j'ai failli crasher…")
395 message
=message
.split()
396 cmd
=message
[0].lower()
399 if not len(message
) in [2,3]:
400 serv
.privmsg(auteur
,"Syntaxe : CONNECT [<username>] <password>")
404 username
=(message
[1])
405 password
=" ".join(message
[2:])
407 password
=" ".join(message
[1:])
408 success
,sock
=self
.new_connection_NK(serv
,username
,password
)
410 self
.sockets
[username
]=sock
411 serv
.privmsg(auteur
,"Connection successful")
412 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
414 serv
.privmsg(auteur
,"Connection failed")
415 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
418 helpdico
={"connect": """CONNECT [<username>] <password>
419 Ouvre une connexion au serveur NoteKfet.
420 Si <username> n'est pas précisé, j'utiliserais l'identité sous laquelle je te connais, ou, à défaut, ton pseudo.""",
421 "identify": """IDENTIFY <username> <password>
422 Vérifie le mot de passe et me permet de savoir à l'avenir quel est ton pseudo note kfet.
423 Sans paramètre, je réponds sous quel pseudo je te connais.""",
424 "drop":"""DROP <password>
425 Vérifie le mot de passe et me fait d'oublier ton pseudo note kfet."""}
426 helpmsg_default
="""Liste des commandes :
427 HELP Affiche de l'aide sur une commande.
428 CONNECT Ouvre une connection au serveur Note Kfet.
429 IDENTIFY Me permet de savoir qui tu es sur la note kfet.
430 DROP Me fait oublier ton identité."""
432 JOIN Faire rejoindre un channel
433 LEAVE Faire quitter un channel
434 QUIET Se taire sur un chanel
435 NOQUIET Opposé de QUIET
436 LOST Perdre sur un chan"""
438 SAY Fais envoyer un message sur un chan ou à une personne
439 STAY Ignorera les prochains LEAVE pour un chan
440 NOSTAY Opposé de STAY
443 helpmsg
=helpmsg_default
444 if auteur
in self
.ops
:
446 if auteur
in self
.overops
:
447 helpmsg
+=helpmsg_overops
449 helpmsg
=helpdico
.get(message
[1].lower(),"Commande inconnue.")
450 for ligne
in helpmsg
.split("\n"):
451 serv
.privmsg(auteur
,ligne
)
452 elif cmd
=="identify":
454 if self
.identities
.has_key(auteur
):
455 serv
.privmsg(auteur
,"Je te connais sous le pseudo note %s."%(
456 self
.identities
[auteur
].encode("utf8")))
458 serv
.privmsg(auteur
,"Je ne connais pas ton pseudo note.")
459 elif len(message
)>=3:
460 username
,password
=message
[1],unicode(" ".join(message
[2:]),"utf8")
461 success
,_
=self
.new_connection_NK(serv
,username
,password
)
463 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
464 serv
.privmsg(auteur
,"Identité enregistrée.")
465 self
.identities
[auteur
]=username
466 pickle
.dump(self
.identities
,open("identities.pickle","w"))
468 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
469 serv
.privmsg(auteur
,"Mot de passe invalide. (ou serveur down)")
471 serv
.privmsg(auteur
,u
"Syntaxe : IDENTIFY [<username> <password>]")
474 if self
.identities
.has_key(auteur
):
475 password
=" ".join(message
[1:])
476 success
,_
=self
.new_connection_NK(serv
,self
.identities
[auteur
],password
)
478 del self
.identities
[auteur
]
479 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
480 pickle
.dump(self
.identities
,open("identities.pickle","w"))
481 serv
.privmsg(auteur
,"Identité oubliée.")
483 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
484 serv
.privmsg(auteur
,"Mot de passe invalide. (ou serveur down)")
486 serv
.privmsg(auteur
,"Je ne connais pas ton pseudo note.")
488 serv
.privmsg(auteur
,"Syntaxe : DROP <password>")
490 if auteur
in self
.ops
:
492 if message
[1] in self
.chanlist
:
493 serv
.privmsg(auteur
,"Je suis déjà sur %s"%(message
[1]))
495 serv
.join(message
[1])
496 self
.chanlist
.append(message
[1])
497 serv
.privmsg(auteur
,"Channels : "+" ".join(self
.chanlist
))
498 log(self
.serveur
,"priv",auteur
," ".join(message
))
500 serv
.privmsg(auteur
,"Channels : "+" ".join(self
.chanlist
))
504 if auteur
in self
.ops
and len(message
)>1:
505 if message
[1] in self
.chanlist
:
506 if not (message
[1] in self
.stay_channels
) or auteur
in self
.overops
:
507 serv
.part(message
[1])
508 self
.chanlist
.remove(message
[1])
509 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
511 serv
.privmsg(auteur
,"Non, je reste !")
512 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
514 serv
.privmsg(auteur
,"Je ne suis pas sur %s"%(message
[1]))
518 if auteur
in self
.overops
:
520 if message
[1] in self
.stay_channels
:
521 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
522 serv
.privmsg(auteur
,"Je stay déjà sur %s."%(message
[1]))
524 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
525 self
.stay_channels
.append(message
[1])
526 serv
.privmsg(auteur
,"Stay channels : "+" ".join(self
.stay_channels
))
528 serv
.privmsg(auteur
,"Stay channels : "+" ".join(self
.stay_channels
))
532 if auteur
in self
.overops
:
534 if message
[1] in self
.stay_channels
:
535 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
536 self
.stay_channels
.remove(message
[1])
537 serv
.privmsg(auteur
,"Stay channels : "+" ".join(self
.stay_channels
))
539 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
540 serv
.privmsg(auteur
,"Je ne stay pas sur %s."%(message
[1]))
545 if auteur
in self
.overops
:
546 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
551 if auteur
in self
.ops
:
553 if message
[1] in self
.quiet_channels
:
554 serv
.privmsg(auteur
,"Je me la ferme déjà sur %s"%(message
[1]))
555 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
557 self
.quiet_channels
.append(message
[1])
558 serv
.privmsg(auteur
,"Quiet channels : "+" ".join(self
.quiet_channels
))
559 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
561 serv
.privmsg(auteur
,"Quiet channels : "+" ".join(self
.quiet_channels
))
565 if auteur
in self
.ops
:
567 if message
[1] in self
.quiet_channels
:
568 self
.quiet_channels
.remove(message
[1])
569 serv
.privmsg(auteur
,"Quiet channels : "+" ".join(self
.quiet_channels
))
570 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
572 serv
.privmsg(auteur
,"Je ne me la ferme pas sur %s."%(message
[1]))
573 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
577 if auteur
in self
.overops
and len(message
)>2:
578 serv
.privmsg(message
[1]," ".join(message
[2:]))
579 log(self
.serveur
,"priv",auteur
," ".join(message
))
580 elif len(message
)<=2:
581 serv
.privmsg(auteur
,"Syntaxe : SAY <channel> <message>")
585 if auteur
in self
.ops
and len(message
)>1:
586 serv
.privmsg(message
[1],"J'ai perdu !")
587 log(self
.serveur
,"priv",auteur
," ".join(message
))
588 elif len(message
)<=1:
589 serv
.privmsg(auteur
,"Syntaxe : LOST <channel>")
595 serv
.privmsg(auteur
,"Je n'ai pas compris. Essaye HELP…")
597 def on_pubmsg(self
, serv
, ev
):
598 auteur
= irclib
.nm_to_n(ev
.source())
600 message
= ev
.arguments()[0]
602 test
=bot_unicode(message
)
603 except UnicodeBotError
:
605 "%s: Euh, tu fais de la merde avec ton encodage là, j'ai failli crasher…"%(auteur))
607 pour_moi
,message
=self
.pourmoi(serv
,message
)
608 if pour_moi
and message
.split()!=[]:
609 cmd
=message
.split()[0].lower()
611 args
=" ".join(message
.split()[1:])
614 if cmd
in ["meurs","die","crève"]:
615 if auteur
in self
.overops
:
616 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
619 serv
.privmsg(canal
,"%s: crève !"%(auteur))
620 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
622 elif cmd
in ["part","leave","dégage"]:
623 if auteur
in self
.ops
and (not (canal
in self
.stay_channels
)
624 or auteur
in self
.overops
):
625 serv
.part(canal
,message
="Éjecté par %s"%(auteur))
626 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
628 serv
.privmsg(canal
,"%s: Non, je reste !"%(auteur))
629 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
631 elif cmd
in ["reconnect"]:
632 if auteur
in self
.ops
:
634 self
.nk
=self
.new_connection_NK(serv
,config_note_pseudo
,config_note_password
)[1]
635 except Exception as exc
:
637 log(self
.serveur
,"""Erreur dans on_pubmsg/"cmd in ["reconnect"]\n"""+str(exc
))
639 serv
.privmsg(canal
,"%s: done"%(auteur))
640 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
642 serv
.privmsg(canal
,"%s: failed"%(auteur))
643 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
644 for report
in self
.report_bugs_to
:
645 serv
.privmsg(report
,"Connection to NK2015 failed, invalid password ?")
647 serv
.privmsg(canal
,"%s: crève !"%(auteur))
648 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
650 elif cmd
in ["deviens","pseudo"]:
651 if auteur
in self
.ops
:
654 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
656 elif cmd
in ["coucou"] and not canal
in self
.quiet_channels
:
657 serv
.privmsg(canal
,"%s: coucou"%(auteur))
658 elif cmd
in ["ping"] and not canal
in self
.quiet_channels
:
659 serv
.privmsg(canal
,"%s: pong"%(auteur))
661 elif cmd
in ["solde","!solde"]:
662 if self
.identities
.has_key(auteur
):
663 pseudo
=self
.identities
[auteur
]
665 self
.nk
.write('search ["x",["pseudo"],%s]'%(json
.dumps(pseudo
)))
666 ret
=json
.loads(self
.nk
.read())
667 solde
=ret
["msg"][0]["solde"]
668 pseudo
=ret
["msg"][0]["pseudo"]
669 except Exception as exc
:
670 serv
.privmsg(canal
,"%s: failed"%(auteur))
671 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
673 serv
.privmsg(canal
,"%s: %s (%s)"%(auteur
,float(solde
)/100,pseudo
.encode("utf8")))
674 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
676 serv
.privmsg(canal
,"%s: Je ne connais pas ton pseudo note."%(auteur))
677 log(self
.serveur
,canal
,auteur
,message
+"[unknown]")
678 elif message
in ["pain au chocolat","chocolatine"] and not canal
in self
.quiet_channels
:
679 serv
.action(canal
,"sert un pain au chocolat à %s"%(auteur))
680 elif re
.match("!?manzana",message
.lower()) and not canal
in self
.quiet_channels
:
681 if auteur
=="[20-100]":
682 serv
.action(canal
,"sert une bouteille de manzana à %s"%(auteur))
684 serv
.action(canal
,"sert un verre de manzana à %s"%(auteur))
685 if is_insult(message
) and not canal
in self
.quiet_channels
:
686 if is_not_insult(message
):
687 answer
=random
.choice(config_compliment_answers
)
688 for ligne
in answer
.split("\n"):
689 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
691 answer
=random
.choice(config_insultes_answers
)
692 for ligne
in answer
.split("\n"):
693 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
694 if is_gros(message
) and not canal
in self
.quiet_channels
:
695 taille
=get_filesize()
696 answer
=u
"Mais non, je ne suis pas gros, %sKo tout au plus…"%(taille)
697 serv
.privmsg(canal
,"%s: %s"%(auteur
,answer
.encode("utf8")))
698 if is_tesla(message
) and not canal
in self
.quiet_channels
:
699 l1
,l2
=config_tesla_answers
,config_tesla_actions
700 n1
,n2
=len(l1
),len(l2
)
701 i
=random
.randrange(n1
+n2
)
703 serv
.action(canal
,l2
[i
-n1
])
705 serv
.privmsg(canal
,"%s: %s"%(auteur
,l1
[i
].encode("utf8")))
706 if is_tamere(message
) and not canal
in self
.quiet_channels
:
707 answer
=random
.choice(config_tamere_answers
)
708 for ligne
in answer
.split("\n"):
709 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
710 if is_tag(message
) and not canal
in self
.quiet_channels
:
711 if auteur
in self
.ops
:
712 action
=random
.choice(config_tag_actions
)
713 serv
.action(canal
,action
.encode("utf8"))
714 self
.quiet_channels
.append(canal
)
716 answer
=random
.choice(config_tag_answers
)
717 for ligne
in answer
.split("\n"):
718 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
719 if is_merci(message
):
720 answer
=random
.choice(config_merci_answers
)
721 for ligne
in answer
.split("\n"):
722 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
723 out
=re
.match(u
"^([A-Z[]|\\|[0-9]+|(¹|²|³|⁴|⁵|⁶|⁷|⁸|⁹|⁰)+)(?:| \?| !)$",
724 unicode(message
.upper(),"utf8"))
725 if out
and not canal
in self
.quiet_channels
:
729 serv
.privmsg(canal
,"%s: %s !"%(auteur
,out
+1))
730 if out
+1>1000 and random
.randrange(4)==0:
731 serv
.privmsg(canal
,"%s: Tu sais, je peux continuer longtemps comme ça…"%(auteur))
733 serv
.privmsg(canal
,"%s: Tu croyais m'avoir sur le maxint ? J'suis en python mon vieux, 'va falloir trouver mieux…"%(auteur))
735 except Exception as exc
:
737 if re
.match("[A-Y]",out
):
738 alphabet
="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
739 serv
.privmsg(canal
,"%s: %s !"%(auteur
,alphabet
[alphabet
.index(out
)+1]))
741 serv
.privmsg(canal
,"%s: pfff, j'ai l'air malin maintenant… [ ?"%(auteur))
743 serv
.privmsg(canal
,"%s: nan mais il faut qu'on arrête, ça va finir par poser des problèmes…"%(auteur))
744 elif re
.match(r
"(¹|²|³|⁴|⁵|⁶|⁷|⁸|⁹|⁰)+",out
):
746 return "".join([{u
"⁰¹²³⁴⁵⁶⁷⁸⁹0123456789"[i
]:u
"0123456789⁰¹²³⁴⁵⁶⁷⁸⁹"[i
]
747 for i
in range(20)}[j
]
749 out
=int(translate(out
))
750 serv
.privmsg(canal
,"%s: %s !"%(auteur
,translate(str(out
+1)).encode("utf8")))
751 if (not canal
in self
.quiet_channels
752 and re
.match((u
"^("+"|".join(config_bonjour
)+").*").lower(),message
.lower()) ):
753 answer
=random
.choice(config_bonjour_answers
)
754 serv
.privmsg(canal
,answer
.format(auteur
).encode("utf8"))
756 serv
.privmsg(canal
,"%s: c'est pas sur moi qu'il faut tirer !"%(auteur))
758 if message
in ["!pain au chocolat","!chocolatine"] and not canal
in self
.quiet_channels
:
759 serv
.action(canal
,"sert un pain au chocolat à %s"%(auteur))
760 if message
in ["!manzana"] and not canal
in self
.quiet_channels
:
761 if auteur
=="[20-100]":
762 serv
.action(canal
,"sert une bouteille de manzana à %s"%(auteur))
764 serv
.action(canal
,"sert un verre de manzana à %s"%(auteur))
765 if re
.match('^(.|§|:|)(w|b) [0-9]+$',message
) and not canal
in self
.quiet_channels
:
766 failanswers
=config_buffer_fail_answers
767 answer
=random
.choice(failanswers
)
768 serv
.privmsg(canal
,"%s: %s"%(auteur
,answer
))
769 if not canal
in self
.quiet_channels
:
770 self
.try_tamere(serv
,canal
,auteur
,message
)
771 mypseudo
=serv
.get_nickname()
772 if re
.match((u
"^("+u
"|".join(config_bonjour
)
773 +u
")( {}| all| tout le monde|(|à) tous)(\.|( |)!|)$"
774 ).format(mypseudo
).lower(), message
.strip().lower()):
775 answer
=random
.choice(config_bonjour_answers
)
776 serv
.privmsg(canal
,answer
.format(auteur
).encode("utf8"))
777 if (is_perdu(message
) and not canal
in self
.quiet_channels
):
778 # proba de perdre sur trigger :
779 # avant 30min (enfin, config) : 0
780 # ensuite, +25%/30min, linéairement
781 deltat
=time
.time()-self
.last_perdu
782 barre
=(deltat
-config_time_between_perdu
)/(2*3600.0)
783 if random
.uniform(0,1)<barre
:
784 serv
.privmsg(canal
,"%s: J'ai perdu !"%(auteur))
785 self
.last_perdu
=time
.time()
787 def on_action(self
, serv
, ev
):
788 action
= ev
.arguments()[0]
789 auteur
= irclib
.nm_to_n(ev
.source())
790 channel
= ev
.target()
791 mypseudo
=serv
.get_nickname()
792 if is_action_trigger(action
,mypseudo
):
793 l1
,l2
=config_action_answers
,config_action_actions
794 n1
,n2
=len(l1
),len(l2
)
795 i
=random
.randrange(n1
+n2
)
797 serv
.action(channel
,l2
[i
-n1
])
799 serv
.privmsg(channel
,"%s: %s"%(auteur
,l1
[i
].encode("utf8")))
801 if __name__
=="__main__":
804 print "Usage : basile.py <serveur> [--debug]"
807 if "debug" in sys
.argv
or "--debug" in sys
.argv
:
811 serveurs
={"a♡":"acoeur.crans.org","acoeur":"acoeur.crans.org","acoeur.crans.org":"acoeur.crans.org",
812 "irc":"irc.crans.org","crans":"irc.crans.org","irc.crans.org":"irc.crans.org"}
814 serveur
=serveurs
[serveur
]
816 print "Server Unknown : %s"%(serveur)
818 basile
=Basile(serveur
,debug
)