]> gitweb.pimeys.fr Git - bots/basile.git/blob - basile.py
le "tu fais de la merde avec ton encodage" est aussi soumis au quiet_channels
[bots/basile.git] / basile.py
1 #!/usr/bin/python
2 # -*- coding:utf8 -*-
3
4 # Codé par 20-100 le 23/04/12
5
6 # Un test de bot irc, parce que c'est cool
7
8 import irclib
9 import ircbot
10 import threading
11 import random
12 import time
13 import socket, ssl, json
14 import pickle
15 import re
16 import os
17 from commands import getstatusoutput as ex
18
19 import sys
20 config_debug_stdout=True
21 if "--quiet" in sys.argv:
22 config_debug_stdout=False
23
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]"]
38
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",
51 u"péripatéticienne"]
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 !"]
60
61 config_gros=[u"gros"]
62
63 config_buffer_fail_answers=["haha !","You type like you drive","encore un effort ;)"]
64
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)",
73
74 u"(gagn|trouv)"+config_premier_groupe_terminaisons,u"gagnant(|s|e|es)",u"gain(|s)",
75
76 u"trouvant",u"trouvaille(|s)",
77
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
84
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 :°",
89 u"Héhé, try again",
90 u"Non, j'ai pas envie",
91 u"Peut-être quand toi tu la fermeras, et encore…"]
92
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"]
96
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."]
99
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."]
103
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 ?",
107 u"Et la tienne ?",
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\""]
111
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 ?",
114 u"Pourquoi moi ?",
115 u"Mais euh…",
116 u"Mais j'ai rien demandé moi !"]
117 config_action_actions=[u"prend de la distance, par précaution…",u"part en courant"]
118
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"]
121
122
123 config_thisfile= os.path.realpath( __file__ )
124 def get_filesize():
125 return ex("ls -s %s"%(config_thisfile))[1].split()[0]
126
127 class NKError(Exception):
128 def __init__(self,msg):
129 Exception.__init__(self)
130 self.msg=msg
131 def __str__(self):
132 return str(self.msg)
133 def __unicode__(self):
134 return unicode(self.msg)
135
136 class NKRefused(NKError):
137 pass
138
139 class NKHelloFailed(NKError):
140 pass
141
142 class NKUnknownError(NKError):
143 pass
144
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)
150 else:
151 chain="%s [%s:%s] %s"%(time.strftime("%F %T"),channel,auteur,message)
152 f.write(chain+"\n")
153 if config_debug_stdout:
154 print chain
155 f.close()
156
157 def connect_NK():
158 sock=socket.socket()
159 try:
160 # On établit la connexion sur port 4242
161 sock.connect(("127.0.0.1",4242))
162 # On passe en SSL
163 sock=ssl.wrap_socket(sock,ca_certs='../keys/ca_.crt')
164 # On fait un hello
165 sock.write('hello "Basile"')
166 # On récupère la réponse du hello
167 out=sock.read()
168 out=json.loads(out)
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:
173 return sock
174 elif out["retcode"]==11:
175 raise NKHelloFailed(out["errmsg"])
176 else:
177 raise NKUnknownError(out["errmsg"])
178
179 def login_NK(username,password,typ="bdd"):
180 sock=connect_NK()
181 try:
182 # Basile a un compte special user
183 commande='login [%s,%s,"%s",["note"]]'%(json.dumps(username),json.dumps(password),typ)
184 sock.write(commande)
185 out=sock.read()
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
191
192
193 def is_something(chain,matches,avant=u".*(^| )",apres=u"($|\.| |,|;).*",case_sensitive=False,debug=False):
194 if case_sensitive:
195 chain=unicode(chain,"utf8")
196 else:
197 chain=unicode(chain,"utf8").lower()
198 allmatches="("+"|".join(matches)+")"
199 reg=(avant+allmatches+apres).lower()
200 if re.match(reg,chain):
201 return True
202 return False
203
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):
212 return True
213 else:
214 return False
215 def is_perdu(chain):
216 return is_something(chain,config_perdu)
217 def is_tag(chain):
218 return is_something(chain,config_tag)
219 def is_gros(chain):
220 return is_something(chain,config_gros)
221 def is_tesla(chain):
222 return is_something(chain,config_tesla,avant=u"^",apres=u"$",debug=True)
223 def is_merci(chain):
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))
229 def is_pan(chain):
230 return re.match(u"^(pan|bim|bang)$",unicode(chain,"utf8").lower().strip())
231
232
233
234 class UnicodeBotError(Exception):
235 pass
236 def bot_unicode(chain):
237 try:
238 unicode(chain,"utf8")
239 except UnicodeDecodeError as exc:
240 raise UnicodeBotError
241
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)
247 self.debug=debug
248 self.serveur=serveur
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
253 self.sockets={}
254 self.identities=pickle.load(open("identities.pickle","r"))
255 self.stay_channels=config_stay_channels
256 self.quiet_channels=config_quiet_channels
257 self.last_perdu=0
258
259
260 def new_connection_NK(self,serv,username,password,typ="bdd"):
261 try:
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.")
267 return (False,None)
268 except NKHelloFailed as exc:
269 for report in self.report_bugs_to:
270 serv.privmsg(report,
271 "La version du site utilisée n'est pas supportée par le serveur NK2015.")
272 return (False,None)
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:
277 for err in erreurs:
278 serv.privmsg(report,err)
279 return (False,None)
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))
283 return (False,None)
284 if retcode==0:
285 return (True,sock)
286 else:
287 return (False,None)
288
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))
292 time.sleep(0.3)
293 serv.nick(config_irc_pseudo)
294
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")
299 if self.debug:
300 self.chanlist=["#bot"]
301 for c in self.chanlist:
302 log(self.serveur,"JOIN %s"%(c))
303 serv.join(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]
306 if self.nk==None:
307 for report in self.report_bugs_to:
308 serv.privmsg(report,"Connection to NK2015 failed, invalid password ?")
309
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))
318
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",
333 u"open":u"open",
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)
340 if matched:
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]
346 break
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)
351 if matched:
352 found=matched.groupdict()["adjectif"]
353 for adj in adjectifs.keys():
354 if re.match(adj,found):
355 adjectif=adjectifs[adj]
356 break
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"))
360 else:
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",
366 u"_srqhbkjjn":""}
367 vb_reg=u".*(^| )(?P<verbe>"+"|".join(verbes.keys())+")( |,|;|\.|$)"
368 matched=re.match(vb_reg,message)
369 if matched:
370 found=matched.groupdict()["verbe"]
371 for vb in verbes.keys():
372 if re.match(vb,found):
373 verbe=verbes[vb]
374 break
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()
381 size=len(pseudo)
382 if message[:size]==pseudo and len(message)>size and message[size]==":":
383 return (True,message[size+1:].lstrip(" "))
384 else:
385 return (False,message)
386
387 def on_privmsg(self, serv, ev):
388 message=ev.arguments()[0]
389 auteur = irclib.nm_to_n(ev.source())
390 try:
391 test=bot_unicode(message)
392 except UnicodeBotError:
393 serv.privmsg(auteur,
394 "Euh, tu fais de la merde avec ton encodage là, j'ai failli crasher…")
395 return
396 message=message.split()
397 cmd=message[0].lower()
398 notunderstood=False
399 if cmd=="connect":
400 if not len(message) in [2,3]:
401 serv.privmsg(auteur,"Syntaxe : CONNECT [<username>] <password>")
402 return
403 username=auteur
404 if len(message)>2:
405 username=(message[1])
406 password=" ".join(message[2:])
407 else:
408 password=" ".join(message[1:])
409 success,sock=self.new_connection_NK(serv,username,password)
410 if success:
411 self.sockets[username]=sock
412 serv.privmsg(auteur,"Connection successful")
413 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
414 else:
415 serv.privmsg(auteur,"Connection failed")
416 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
417
418 elif cmd=="help":
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é."""
432 helpmsg_ops="""
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"""
438 helpmsg_overops="""
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
442 DIE Mourir"""
443 if len(message)==1:
444 helpmsg=helpmsg_default
445 if auteur in self.ops:
446 helpmsg+=helpmsg_ops
447 if auteur in self.overops:
448 helpmsg+=helpmsg_overops
449 else:
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":
454 if len(message)==1:
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")))
458 else:
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)
463 if success:
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"))
468 else:
469 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
470 serv.privmsg(auteur,"Mot de passe invalide. (ou serveur down)")
471 else:
472 serv.privmsg(auteur,u"Syntaxe : IDENTIFY [<username> <password>]")
473 elif cmd=="drop":
474 if len(message)>1:
475 if self.identities.has_key(auteur):
476 password=" ".join(message[1:])
477 success,_=self.new_connection_NK(serv,self.identities[auteur],password)
478 if success:
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.")
483 else:
484 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
485 serv.privmsg(auteur,"Mot de passe invalide. (ou serveur down)")
486 else:
487 serv.privmsg(auteur,"Je ne connais pas ton pseudo note.")
488 else:
489 serv.privmsg(auteur,"Syntaxe : DROP <password>")
490 elif cmd=="join":
491 if auteur in self.ops:
492 if len(message)>1:
493 if message[1] in self.chanlist:
494 serv.privmsg(auteur,"Je suis déjà sur %s"%(message[1]))
495 else:
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))
500 else:
501 serv.privmsg(auteur,"Channels : "+" ".join(self.chanlist))
502 else:
503 notunderstood=True
504 elif cmd=="leave":
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]")
511 else:
512 serv.privmsg(auteur,"Non, je reste !")
513 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
514 else:
515 serv.privmsg(auteur,"Je ne suis pas sur %s"%(message[1]))
516 else:
517 notunderstood=True
518 elif cmd=="stay":
519 if auteur in self.overops:
520 if len(message)>1:
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]))
524 else:
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))
528 else:
529 serv.privmsg(auteur,"Stay channels : "+" ".join(self.stay_channels))
530 else:
531 notunderstood=True
532 elif cmd=="nostay":
533 if auteur in self.overops:
534 if len(message)>1:
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))
539 else:
540 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
541 serv.privmsg(auteur,"Je ne stay pas sur %s."%(message[1]))
542
543 else:
544 notunderstood=True
545 elif cmd=="die":
546 if auteur in self.overops:
547 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
548 self.die()
549 else:
550 notunderstood=True
551 elif cmd=="quiet":
552 if auteur in self.ops:
553 if len(message)>1:
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]")
557 else:
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]")
561 else:
562 serv.privmsg(auteur,"Quiet channels : "+" ".join(self.quiet_channels))
563 else:
564 notunderstood=True
565 elif cmd=="noquiet":
566 if auteur in self.ops:
567 if len(message)>1:
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]")
572 else:
573 serv.privmsg(auteur,"Je ne me la ferme pas sur %s."%(message[1]))
574 log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
575 else:
576 notunderstood=True
577 elif cmd=="say":
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>")
583 else:
584 notunderstood=True
585 elif cmd=="lost":
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>")
591 else:
592 notunderstood=True
593 else:
594 notunderstood=True
595 if notunderstood:
596 serv.privmsg(auteur,"Je n'ai pas compris. Essaye HELP…")
597
598 def on_pubmsg(self, serv, ev):
599 auteur = irclib.nm_to_n(ev.source())
600 canal = ev.target()
601 message = ev.arguments()[0]
602 try:
603 test=bot_unicode(message)
604 except UnicodeBotError:
605 if not canal in self.quiet_channels:
606 serv.privmsg(canal,
607 "%s: Euh, tu fais de la merde avec ton encodage là, j'ai failli crasher…"%(auteur))
608 return
609 pour_moi,message=self.pourmoi(serv,message)
610 if pour_moi and message.split()!=[]:
611 cmd=message.split()[0].lower()
612 try:
613 args=" ".join(message.split()[1:])
614 except:
615 args=""
616 if cmd in ["meurs","die","crève"]:
617 if auteur in self.overops:
618 log(self.serveur,canal,auteur,message+"[successful]")
619 self.die()
620 else:
621 serv.privmsg(canal,"%s: crève !"%(auteur))
622 log(self.serveur,canal,auteur,message+"[failed]")
623
624 elif cmd in ["part","leave","dégage"]:
625 if auteur in self.ops and (not (canal in self.stay_channels)
626 or auteur in self.overops):
627 serv.part(canal,message="Éjecté par %s"%(auteur))
628 log(self.serveur,canal,auteur,message+"[successful]")
629 else:
630 serv.privmsg(canal,"%s: Non, je reste !"%(auteur))
631 log(self.serveur,canal,auteur,message+"[failed]")
632
633 elif cmd in ["reconnect"]:
634 if auteur in self.ops:
635 try:
636 self.nk=self.new_connection_NK(serv,config_note_pseudo,
637 config_note_password,"special")[1]
638 except Exception as exc:
639 self.nk=None
640 log(self.serveur,"""Erreur dans on_pubmsg/"cmd in ["reconnect"]\n"""+str(exc))
641 if self.nk!=None:
642 serv.privmsg(canal,"%s: done"%(auteur))
643 log(self.serveur,canal,auteur,message+"[successful]")
644 else:
645 serv.privmsg(canal,"%s: failed"%(auteur))
646 log(self.serveur,canal,auteur,message+"[failed]")
647 for report in self.report_bugs_to:
648 serv.privmsg(report,"Connection to NK2015 failed, invalid password ?")
649 else:
650 serv.privmsg(canal,"%s: crève !"%(auteur))
651 log(self.serveur,canal,auteur,message+"[failed]")
652
653 elif cmd in ["deviens","pseudo"]:
654 if auteur in self.ops:
655 become=args
656 serv.nick(become)
657 log(self.serveur,canal,auteur,message+"[successful]")
658
659 elif cmd in ["coucou"] and not canal in self.quiet_channels:
660 serv.privmsg(canal,"%s: coucou"%(auteur))
661 elif cmd in ["ping"] and not canal in self.quiet_channels:
662 serv.privmsg(canal,"%s: pong"%(auteur))
663
664 elif cmd in ["solde","!solde"]:
665 if self.identities.has_key(auteur):
666 pseudo=self.identities[auteur]
667 try:
668 self.nk.write('search ["x",["pseudo"],%s]'%(json.dumps(pseudo)))
669 ret=json.loads(self.nk.read())
670 solde=ret["msg"][0]["solde"]
671 pseudo=ret["msg"][0]["pseudo"]
672 except Exception as exc:
673 serv.privmsg(canal,"%s: failed"%(auteur))
674 log(self.serveur,canal,auteur,message+"[failed]")
675 else:
676 serv.privmsg(canal,"%s: %s (%s)"%(auteur,float(solde)/100,pseudo.encode("utf8")))
677 log(self.serveur,canal,auteur,message+"[successful]")
678 else:
679 serv.privmsg(canal,"%s: Je ne connais pas ton pseudo note."%(auteur))
680 log(self.serveur,canal,auteur,message+"[unknown]")
681 elif (re.match("!?(pain au chocolat|chocolatine)",message.lower())
682 and not canal in self.quiet_channels):
683 serv.action(canal,"sert un pain au chocolat à %s"%(auteur))
684 elif re.match("!?manzana",message.lower()) and not canal in self.quiet_channels:
685 if auteur=="[20-100]":
686 serv.action(canal,"sert une bouteille de manzana à %s"%(auteur))
687 else:
688 serv.action(canal,"sert un verre de manzana à %s"%(auteur))
689 if is_insult(message) and not canal in self.quiet_channels:
690 if is_not_insult(message):
691 answer=random.choice(config_compliment_answers)
692 for ligne in answer.split("\n"):
693 serv.privmsg(canal,"%s: %s"%(auteur,ligne.encode("utf8")))
694 else:
695 answer=random.choice(config_insultes_answers)
696 for ligne in answer.split("\n"):
697 serv.privmsg(canal,"%s: %s"%(auteur,ligne.encode("utf8")))
698 if is_gros(message) and not canal in self.quiet_channels:
699 taille=get_filesize()
700 answer=u"Mais non, je ne suis pas gros, %sKo tout au plus…"%(taille)
701 serv.privmsg(canal,"%s: %s"%(auteur,answer.encode("utf8")))
702 if is_tesla(message) and not canal in self.quiet_channels:
703 l1,l2=config_tesla_answers,config_tesla_actions
704 n1,n2=len(l1),len(l2)
705 i=random.randrange(n1+n2)
706 if i>=n1:
707 serv.action(canal,l2[i-n1])
708 else:
709 serv.privmsg(canal,"%s: %s"%(auteur,l1[i].encode("utf8")))
710 if is_tamere(message) and not canal in self.quiet_channels:
711 answer=random.choice(config_tamere_answers)
712 for ligne in answer.split("\n"):
713 serv.privmsg(canal,"%s: %s"%(auteur,ligne.encode("utf8")))
714 if is_tag(message) and not canal in self.quiet_channels:
715 if auteur in self.ops:
716 action=random.choice(config_tag_actions)
717 serv.action(canal,action.encode("utf8"))
718 self.quiet_channels.append(canal)
719 else:
720 answer=random.choice(config_tag_answers)
721 for ligne in answer.split("\n"):
722 serv.privmsg(canal,"%s: %s"%(auteur,ligne.encode("utf8")))
723 if is_merci(message):
724 answer=random.choice(config_merci_answers)
725 for ligne in answer.split("\n"):
726 serv.privmsg(canal,"%s: %s"%(auteur,ligne.encode("utf8")))
727 out=re.match(u"^([A-Z[]|\\|[0-9]+|(¹|²|³|⁴|⁵|⁶|⁷|⁸|⁹|⁰)+)(?:| \?| !)$",
728 unicode(message.upper(),"utf8"))
729 if out and not canal in self.quiet_channels:
730 out=out.groups()[0]
731 try:
732 out=int(out)
733 serv.privmsg(canal,"%s: %s !"%(auteur,out+1))
734 if out+1>1000 and random.randrange(4)==0:
735 serv.privmsg(canal,"%s: Tu sais, je peux continuer longtemps comme ça…"%(auteur))
736 if out==2147483647:
737 serv.privmsg(canal,"%s: Tu croyais m'avoir sur le maxint ? J'suis en python mon vieux, 'va falloir trouver mieux…"%(auteur))
738 return
739 except Exception as exc:
740 pass
741 if re.match("[A-Y]",out):
742 alphabet="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
743 serv.privmsg(canal,"%s: %s !"%(auteur,alphabet[alphabet.index(out)+1]))
744 elif out=="Z":
745 serv.privmsg(canal,"%s: pfff, j'ai l'air malin maintenant… [ ?"%(auteur))
746 elif out in "[\\":
747 serv.privmsg(canal,"%s: nan mais il faut qu'on arrête, ça va finir par poser des problèmes…"%(auteur))
748 elif re.match(r"(¹|²|³|⁴|⁵|⁶|⁷|⁸|⁹|⁰)+",out):
749 def translate(mess):
750 return "".join([{u"⁰¹²³⁴⁵⁶⁷⁸⁹0123456789"[i]:u"0123456789⁰¹²³⁴⁵⁶⁷⁸⁹"[i]
751 for i in range(20)}[j]
752 for j in mess])
753 out=int(translate(out))
754 serv.privmsg(canal,"%s: %s !"%(auteur,translate(str(out+1)).encode("utf8")))
755 if (not canal in self.quiet_channels
756 and re.match((u"^("+"|".join(config_bonjour)+").*").lower(),message.lower()) ):
757 answer=random.choice(config_bonjour_answers)
758 serv.privmsg(canal,answer.format(auteur).encode("utf8"))
759 if is_pan(message):
760 serv.privmsg(canal,"%s: c'est pas sur moi qu'il faut tirer !"%(auteur))
761 else:
762 if message in ["!pain au chocolat","!chocolatine"] and not canal in self.quiet_channels:
763 serv.action(canal,"sert un pain au chocolat à %s"%(auteur))
764 if message in ["!manzana"] and not canal in self.quiet_channels:
765 if auteur=="[20-100]":
766 serv.action(canal,"sert une bouteille de manzana à %s"%(auteur))
767 else:
768 serv.action(canal,"sert un verre de manzana à %s"%(auteur))
769 if re.match('^(.|§|:|)(w|b) [0-9]+$',message) and not canal in self.quiet_channels:
770 failanswers=config_buffer_fail_answers
771 answer=random.choice(failanswers)
772 serv.privmsg(canal,"%s: %s"%(auteur,answer))
773 if not canal in self.quiet_channels:
774 self.try_tamere(serv,canal,auteur,message)
775 mypseudo=serv.get_nickname()
776 if re.match((u"^("+u"|".join(config_bonjour)
777 +u")( {}| all| tout le monde|(|à) tous)(\.|( |)!|)$"
778 ).format(mypseudo).lower(), message.strip().lower()):
779 answer=random.choice(config_bonjour_answers)
780 serv.privmsg(canal,answer.format(auteur).encode("utf8"))
781 if (is_perdu(message) and not canal in self.quiet_channels):
782 # proba de perdre sur trigger :
783 # avant 30min (enfin, config) : 0
784 # ensuite, +25%/30min, linéairement
785 deltat=time.time()-self.last_perdu
786 barre=(deltat-config_time_between_perdu)/(2*3600.0)
787 if random.uniform(0,1)<barre:
788 serv.privmsg(canal,"%s: J'ai perdu !"%(auteur))
789 self.last_perdu=time.time()
790
791 def on_action(self, serv, ev):
792 action = ev.arguments()[0]
793 auteur = irclib.nm_to_n(ev.source())
794 channel = ev.target()
795 mypseudo=serv.get_nickname()
796 if is_action_trigger(action,mypseudo):
797 l1,l2=config_action_answers,config_action_actions
798 n1,n2=len(l1),len(l2)
799 i=random.randrange(n1+n2)
800 if i>=n1:
801 serv.action(channel,l2[i-n1])
802 else:
803 serv.privmsg(channel,"%s: %s"%(auteur,l1[i].encode("utf8")))
804
805 if __name__=="__main__":
806 import sys
807 if len(sys.argv)==1:
808 print "Usage : basile.py <serveur> [--debug]"
809 exit(1)
810 serveur=sys.argv[1]
811 if "debug" in sys.argv or "--debug" in sys.argv:
812 debug=True
813 else:
814 debug=False
815 serveurs={"a♡":"acoeur.crans.org","acoeur":"acoeur.crans.org","acoeur.crans.org":"acoeur.crans.org",
816 "irc":"irc.crans.org","crans":"irc.crans.org","irc.crans.org":"irc.crans.org"}
817 try:
818 serveur=serveurs[serveur]
819 except KeyError:
820 print "Server Unknown : %s"%(serveur)
821 exit(404)
822 basile=Basile(serveur,debug)
823 basile.start()