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",[["note"],[],false]]'%(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 u
"innocent(|e|s|es)":u
"innocente"}
337 adj_reg
=u
"(?P<adjectif>"+u
"|".join(adjectifs
.keys())+u
")"
338 reg
=u
".*(^| |')"+debuts
+u
" "+adj_reg
+u
"($|,|;|\.| ).*"
339 matched
=re
.match(reg
,message
)
341 # il faut repasser l'adjectif au féminin singulier
342 found
=matched
.groupdict()["adjectif"]
343 for adj
in adjectifs
.keys():
344 if re
.match(adj
,found
):
345 adjectif
=adjectifs
[adj
]
347 serv
.privmsg(channel
,(u
"%s: c'est ta mère qui est %s !"%(auteur
,adjectif
)).encode("utf8"))
348 elif random
.randrange(5)==0:
349 # deuxième type de trigger, mais moins probable
350 matched
=re
.match(adj_reg
,message
)
352 found
=matched
.groupdict()["adjectif"]
353 for adj
in adjectifs
.keys():
354 if re
.match(adj
,found
):
355 adjectif
=adjectifs
[adj
]
357 fille
=random
.choice([u
"mère",u
"soœur"])
358 serv
.privmsg(channel
,(u
"%s: et ta %s, elle est %s ?"%
359 (auteur
,fille
,adjectif
)).encode("utf8"))
361 # troisième type de trigger
362 cpgt
=config_premier_groupe_terminaisons
363 verbes
={u
"tourn"+cpgt
:u
"tourne",
364 u
"balad"+cpgt
+u
" sur le trottoir":u
"se balade sur le trottoir",
365 u
"prom(e|è)n"+cpgt
+" sur le trottoir":u
"se promène sur le trottoir",
367 vb_reg
=u
".*(^| )(?P<verbe>"+"|".join(verbes
.keys())+")( |,|;|\.|$)"
368 matched
=re
.match(vb_reg
,message
)
370 found
=matched
.groupdict()["verbe"]
371 for vb
in verbes
.keys():
372 if re
.match(vb
,found
):
375 fille
=random
.choice([u
"mère",u
"soœur"])
376 serv
.privmsg(channel
,(u
"%s: et ta %s, elle %s ?"%
377 (auteur
,fille
,verbe
)).encode("utf8"))
378 def pourmoi(self
, serv
, message
):
379 """renvoie (False,lemessage) ou (True, le message amputé de "pseudo: ")"""
380 pseudo
=serv
.get_nickname()
382 if message
[:size
]==pseudo
and len(message
)>size
and message
[size
]==":":
383 return (True,message
[size
+1:].lstrip(" "))
385 return (False,message
)
387 def on_privmsg(self
, serv
, ev
):
388 message
=ev
.arguments()[0]
389 auteur
= irclib
.nm_to_n(ev
.source())
391 test
=bot_unicode(message
)
392 except UnicodeBotError
:
394 "Euh, tu fais de la merde avec ton encodage là, j'ai failli crasher…")
396 message
=message
.split()
397 cmd
=message
[0].lower()
400 if not len(message
) in [2,3]:
401 serv
.privmsg(auteur
,"Syntaxe : CONNECT [<username>] <password>")
405 username
=(message
[1])
406 password
=" ".join(message
[2:])
408 password
=" ".join(message
[1:])
409 success
,sock
=self
.new_connection_NK(serv
,username
,password
)
411 self
.sockets
[username
]=sock
412 serv
.privmsg(auteur
,"Connection successful")
413 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
415 serv
.privmsg(auteur
,"Connection failed")
416 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
419 helpdico
={"connect": """CONNECT [<username>] <password>
420 Ouvre une connexion au serveur NoteKfet.
421 Si <username> n'est pas précisé, j'utiliserais l'identité sous laquelle je te connais, ou, à défaut, ton pseudo.""",
422 "identify": """IDENTIFY <username> <password>
423 Vérifie le mot de passe et me permet de savoir à l'avenir quel est ton pseudo note kfet.
424 Sans paramètre, je réponds sous quel pseudo je te connais.""",
425 "drop":"""DROP <password>
426 Vérifie le mot de passe et me fait d'oublier ton pseudo note kfet."""}
427 helpmsg_default
="""Liste des commandes :
428 HELP Affiche de l'aide sur une commande.
429 CONNECT Ouvre une connection au serveur Note Kfet.
430 IDENTIFY Me permet de savoir qui tu es sur la note kfet.
431 DROP Me fait oublier ton identité."""
433 JOIN Faire rejoindre un chan
434 LEAVE Faire quitter un chan
435 QUIET Se taire sur un chan
436 NOQUIET Opposé de QUIET
437 LOST Perdre sur un chan"""
439 SAY Fais envoyer un message sur un chan ou à une personne
440 STAY Ignorera les prochains LEAVE pour un chan
441 NOSTAY Opposé de STAY
444 helpmsg
=helpmsg_default
445 if auteur
in self
.ops
:
447 if auteur
in self
.overops
:
448 helpmsg
+=helpmsg_overops
450 helpmsg
=helpdico
.get(message
[1].lower(),"Commande inconnue.")
451 for ligne
in helpmsg
.split("\n"):
452 serv
.privmsg(auteur
,ligne
)
453 elif cmd
=="identify":
455 if self
.identities
.has_key(auteur
):
456 serv
.privmsg(auteur
,"Je te connais sous le pseudo note %s."%(
457 self
.identities
[auteur
].encode("utf8")))
459 serv
.privmsg(auteur
,"Je ne connais pas ton pseudo note.")
460 elif len(message
)>=3:
461 username
,password
=message
[1],unicode(" ".join(message
[2:]),"utf8")
462 success
,_
=self
.new_connection_NK(serv
,username
,password
)
464 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
465 serv
.privmsg(auteur
,"Identité enregistrée.")
466 self
.identities
[auteur
]=username
467 pickle
.dump(self
.identities
,open("identities.pickle","w"))
469 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
470 serv
.privmsg(auteur
,"Mot de passe invalide. (ou serveur down)")
472 serv
.privmsg(auteur
,u
"Syntaxe : IDENTIFY [<username> <password>]")
475 if self
.identities
.has_key(auteur
):
476 password
=" ".join(message
[1:])
477 success
,_
=self
.new_connection_NK(serv
,self
.identities
[auteur
],password
)
479 del self
.identities
[auteur
]
480 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
481 pickle
.dump(self
.identities
,open("identities.pickle","w"))
482 serv
.privmsg(auteur
,"Identité oubliée.")
484 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
485 serv
.privmsg(auteur
,"Mot de passe invalide. (ou serveur down)")
487 serv
.privmsg(auteur
,"Je ne connais pas ton pseudo note.")
489 serv
.privmsg(auteur
,"Syntaxe : DROP <password>")
491 if auteur
in self
.ops
:
493 if message
[1] in self
.chanlist
:
494 serv
.privmsg(auteur
,"Je suis déjà sur %s"%(message
[1]))
496 serv
.join(message
[1])
497 self
.chanlist
.append(message
[1])
498 serv
.privmsg(auteur
,"Channels : "+" ".join(self
.chanlist
))
499 log(self
.serveur
,"priv",auteur
," ".join(message
))
501 serv
.privmsg(auteur
,"Channels : "+" ".join(self
.chanlist
))
505 if auteur
in self
.ops
and len(message
)>1:
506 if message
[1] in self
.chanlist
:
507 if not (message
[1] in self
.stay_channels
) or auteur
in self
.overops
:
508 serv
.part(message
[1])
509 self
.chanlist
.remove(message
[1])
510 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
512 serv
.privmsg(auteur
,"Non, je reste !")
513 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
515 serv
.privmsg(auteur
,"Je ne suis pas sur %s"%(message
[1]))
519 if auteur
in self
.overops
:
521 if message
[1] in self
.stay_channels
:
522 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
523 serv
.privmsg(auteur
,"Je stay déjà sur %s."%(message
[1]))
525 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
526 self
.stay_channels
.append(message
[1])
527 serv
.privmsg(auteur
,"Stay channels : "+" ".join(self
.stay_channels
))
529 serv
.privmsg(auteur
,"Stay channels : "+" ".join(self
.stay_channels
))
533 if auteur
in self
.overops
:
535 if message
[1] in self
.stay_channels
:
536 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
537 self
.stay_channels
.remove(message
[1])
538 serv
.privmsg(auteur
,"Stay channels : "+" ".join(self
.stay_channels
))
540 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
541 serv
.privmsg(auteur
,"Je ne stay pas sur %s."%(message
[1]))
546 if auteur
in self
.overops
:
547 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
552 if auteur
in self
.ops
:
554 if message
[1] in self
.quiet_channels
:
555 serv
.privmsg(auteur
,"Je me la ferme déjà sur %s"%(message
[1]))
556 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
558 self
.quiet_channels
.append(message
[1])
559 serv
.privmsg(auteur
,"Quiet channels : "+" ".join(self
.quiet_channels
))
560 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
562 serv
.privmsg(auteur
,"Quiet channels : "+" ".join(self
.quiet_channels
))
566 if auteur
in self
.ops
:
568 if message
[1] in self
.quiet_channels
:
569 self
.quiet_channels
.remove(message
[1])
570 serv
.privmsg(auteur
,"Quiet channels : "+" ".join(self
.quiet_channels
))
571 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
573 serv
.privmsg(auteur
,"Je ne me la ferme pas sur %s."%(message
[1]))
574 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
578 if auteur
in self
.overops
and len(message
)>2:
579 serv
.privmsg(message
[1]," ".join(message
[2:]))
580 log(self
.serveur
,"priv",auteur
," ".join(message
))
581 elif len(message
)<=2:
582 serv
.privmsg(auteur
,"Syntaxe : SAY <channel> <message>")
586 if auteur
in self
.ops
and len(message
)>1:
587 serv
.privmsg(message
[1],"J'ai perdu !")
588 log(self
.serveur
,"priv",auteur
," ".join(message
))
589 elif len(message
)<=1:
590 serv
.privmsg(auteur
,"Syntaxe : LOST <channel>")
596 serv
.privmsg(auteur
,"Je n'ai pas compris. Essaye HELP…")
598 def on_pubmsg(self
, serv
, ev
):
599 auteur
= irclib
.nm_to_n(ev
.source())
601 message
= ev
.arguments()[0]
603 test
=bot_unicode(message
)
604 except UnicodeBotError
:
606 "%s: Euh, tu fais de la merde avec ton encodage là, j'ai failli crasher…"%(auteur))
608 pour_moi
,message
=self
.pourmoi(serv
,message
)
609 if pour_moi
and message
.split()!=[]:
610 cmd
=message
.split()[0].lower()
612 args
=" ".join(message
.split()[1:])
615 if cmd
in ["meurs","die","crève"]:
616 if auteur
in self
.overops
:
617 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
620 serv
.privmsg(canal
,"%s: crève !"%(auteur))
621 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
623 elif cmd
in ["part","leave","dégage"]:
624 if auteur
in self
.ops
and (not (canal
in self
.stay_channels
)
625 or auteur
in self
.overops
):
626 serv
.part(canal
,message
="Éjecté par %s"%(auteur))
627 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
629 serv
.privmsg(canal
,"%s: Non, je reste !"%(auteur))
630 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
632 elif cmd
in ["reconnect"]:
633 if auteur
in self
.ops
:
635 self
.nk
=self
.new_connection_NK(serv
,config_note_pseudo
,
636 config_note_password
,"special")[1]
637 except Exception as exc
:
639 log(self
.serveur
,"""Erreur dans on_pubmsg/"cmd in ["reconnect"]\n"""+str(exc
))
641 serv
.privmsg(canal
,"%s: done"%(auteur))
642 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
644 serv
.privmsg(canal
,"%s: failed"%(auteur))
645 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
646 for report
in self
.report_bugs_to
:
647 serv
.privmsg(report
,"Connection to NK2015 failed, invalid password ?")
649 serv
.privmsg(canal
,"%s: crève !"%(auteur))
650 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
652 elif cmd
in ["deviens","pseudo"]:
653 if auteur
in self
.ops
:
656 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
658 elif cmd
in ["coucou"] and not canal
in self
.quiet_channels
:
659 serv
.privmsg(canal
,"%s: coucou"%(auteur))
660 elif cmd
in ["ping"] and not canal
in self
.quiet_channels
:
661 serv
.privmsg(canal
,"%s: pong"%(auteur))
663 elif cmd
in ["solde","!solde"]:
664 if self
.identities
.has_key(auteur
):
665 pseudo
=self
.identities
[auteur
]
667 self
.nk
.write('search ["x",["pseudo"],%s]'%(json
.dumps(pseudo
)))
668 ret
=json
.loads(self
.nk
.read())
669 solde
=ret
["msg"][0]["solde"]
670 pseudo
=ret
["msg"][0]["pseudo"]
671 except Exception as exc
:
672 serv
.privmsg(canal
,"%s: failed"%(auteur))
673 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
675 serv
.privmsg(canal
,"%s: %s (%s)"%(auteur
,float(solde
)/100,pseudo
.encode("utf8")))
676 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
678 serv
.privmsg(canal
,"%s: Je ne connais pas ton pseudo note."%(auteur))
679 log(self
.serveur
,canal
,auteur
,message
+"[unknown]")
680 elif (re
.match("!?(pain au chocolat|chocolatine)",message
.lower())
681 and not canal
in self
.quiet_channels
):
682 serv
.action(canal
,"sert un pain au chocolat à %s"%(auteur))
683 elif re
.match("!?manzana",message
.lower()) and not canal
in self
.quiet_channels
:
684 if auteur
=="[20-100]":
685 serv
.action(canal
,"sert une bouteille de manzana à %s"%(auteur))
687 serv
.action(canal
,"sert un verre de manzana à %s"%(auteur))
688 if is_insult(message
) and not canal
in self
.quiet_channels
:
689 if is_not_insult(message
):
690 answer
=random
.choice(config_compliment_answers
)
691 for ligne
in answer
.split("\n"):
692 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
694 answer
=random
.choice(config_insultes_answers
)
695 for ligne
in answer
.split("\n"):
696 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
697 if is_gros(message
) and not canal
in self
.quiet_channels
:
698 taille
=get_filesize()
699 answer
=u
"Mais non, je ne suis pas gros, %sKo tout au plus…"%(taille)
700 serv
.privmsg(canal
,"%s: %s"%(auteur
,answer
.encode("utf8")))
701 if is_tesla(message
) and not canal
in self
.quiet_channels
:
702 l1
,l2
=config_tesla_answers
,config_tesla_actions
703 n1
,n2
=len(l1
),len(l2
)
704 i
=random
.randrange(n1
+n2
)
706 serv
.action(canal
,l2
[i
-n1
])
708 serv
.privmsg(canal
,"%s: %s"%(auteur
,l1
[i
].encode("utf8")))
709 if is_tamere(message
) and not canal
in self
.quiet_channels
:
710 answer
=random
.choice(config_tamere_answers
)
711 for ligne
in answer
.split("\n"):
712 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
713 if is_tag(message
) and not canal
in self
.quiet_channels
:
714 if auteur
in self
.ops
:
715 action
=random
.choice(config_tag_actions
)
716 serv
.action(canal
,action
.encode("utf8"))
717 self
.quiet_channels
.append(canal
)
719 answer
=random
.choice(config_tag_answers
)
720 for ligne
in answer
.split("\n"):
721 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
722 if is_merci(message
):
723 answer
=random
.choice(config_merci_answers
)
724 for ligne
in answer
.split("\n"):
725 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
726 out
=re
.match(u
"^([A-Z[]|\\|[0-9]+|(¹|²|³|⁴|⁵|⁶|⁷|⁸|⁹|⁰)+)(?:| \?| !)$",
727 unicode(message
.upper(),"utf8"))
728 if out
and not canal
in self
.quiet_channels
:
732 serv
.privmsg(canal
,"%s: %s !"%(auteur
,out
+1))
733 if out
+1>1000 and random
.randrange(4)==0:
734 serv
.privmsg(canal
,"%s: Tu sais, je peux continuer longtemps comme ça…"%(auteur))
736 serv
.privmsg(canal
,"%s: Tu croyais m'avoir sur le maxint ? J'suis en python mon vieux, 'va falloir trouver mieux…"%(auteur))
738 except Exception as exc
:
740 if re
.match("[A-Y]",out
):
741 alphabet
="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
742 serv
.privmsg(canal
,"%s: %s !"%(auteur
,alphabet
[alphabet
.index(out
)+1]))
744 serv
.privmsg(canal
,"%s: pfff, j'ai l'air malin maintenant… [ ?"%(auteur))
746 serv
.privmsg(canal
,"%s: nan mais il faut qu'on arrête, ça va finir par poser des problèmes…"%(auteur))
747 elif re
.match(r
"(¹|²|³|⁴|⁵|⁶|⁷|⁸|⁹|⁰)+",out
):
749 return "".join([{u
"⁰¹²³⁴⁵⁶⁷⁸⁹0123456789"[i
]:u
"0123456789⁰¹²³⁴⁵⁶⁷⁸⁹"[i
]
750 for i
in range(20)}[j
]
752 out
=int(translate(out
))
753 serv
.privmsg(canal
,"%s: %s !"%(auteur
,translate(str(out
+1)).encode("utf8")))
754 if (not canal
in self
.quiet_channels
755 and re
.match((u
"^("+"|".join(config_bonjour
)+").*").lower(),message
.lower()) ):
756 answer
=random
.choice(config_bonjour_answers
)
757 serv
.privmsg(canal
,answer
.format(auteur
).encode("utf8"))
759 serv
.privmsg(canal
,"%s: c'est pas sur moi qu'il faut tirer !"%(auteur))
761 if message
in ["!pain au chocolat","!chocolatine"] and not canal
in self
.quiet_channels
:
762 serv
.action(canal
,"sert un pain au chocolat à %s"%(auteur))
763 if message
in ["!manzana"] and not canal
in self
.quiet_channels
:
764 if auteur
=="[20-100]":
765 serv
.action(canal
,"sert une bouteille de manzana à %s"%(auteur))
767 serv
.action(canal
,"sert un verre de manzana à %s"%(auteur))
768 if re
.match('^(.|§|:|)(w|b) [0-9]+$',message
) and not canal
in self
.quiet_channels
:
769 failanswers
=config_buffer_fail_answers
770 answer
=random
.choice(failanswers
)
771 serv
.privmsg(canal
,"%s: %s"%(auteur
,answer
))
772 if not canal
in self
.quiet_channels
:
773 self
.try_tamere(serv
,canal
,auteur
,message
)
774 mypseudo
=serv
.get_nickname()
775 if re
.match((u
"^("+u
"|".join(config_bonjour
)
776 +u
")( {}| all| tout le monde|(|à) tous)(\.|( |)!|)$"
777 ).format(mypseudo
).lower(), message
.strip().lower()):
778 answer
=random
.choice(config_bonjour_answers
)
779 serv
.privmsg(canal
,answer
.format(auteur
).encode("utf8"))
780 if (is_perdu(message
) and not canal
in self
.quiet_channels
):
781 # proba de perdre sur trigger :
782 # avant 30min (enfin, config) : 0
783 # ensuite, +25%/30min, linéairement
784 deltat
=time
.time()-self
.last_perdu
785 barre
=(deltat
-config_time_between_perdu
)/(2*3600.0)
786 if random
.uniform(0,1)<barre
:
787 serv
.privmsg(canal
,"%s: J'ai perdu !"%(auteur))
788 self
.last_perdu
=time
.time()
790 def on_action(self
, serv
, ev
):
791 action
= ev
.arguments()[0]
792 auteur
= irclib
.nm_to_n(ev
.source())
793 channel
= ev
.target()
794 mypseudo
=serv
.get_nickname()
795 if is_action_trigger(action
,mypseudo
):
796 l1
,l2
=config_action_answers
,config_action_actions
797 n1
,n2
=len(l1
),len(l2
)
798 i
=random
.randrange(n1
+n2
)
800 serv
.action(channel
,l2
[i
-n1
])
802 serv
.privmsg(channel
,"%s: %s"%(auteur
,l1
[i
].encode("utf8")))
804 if __name__
=="__main__":
807 print "Usage : basile.py <serveur> [--debug]"
810 if "debug" in sys
.argv
or "--debug" in sys
.argv
:
814 serveurs
={"a♡":"acoeur.crans.org","acoeur":"acoeur.crans.org","acoeur.crans.org":"acoeur.crans.org",
815 "irc":"irc.crans.org","crans":"irc.crans.org","irc.crans.org":"irc.crans.org"}
817 serveur
=serveurs
[serveur
]
819 print "Server Unknown : %s"%(serveur)
821 basile
=Basile(serveur
,debug
)