4 # Codé par 20-100 (commencé le 23/04/12)
6 # Un bot IRC qui, un jour, s'interfacera avec la Note Kfet 2015
13 import socket
, ssl
, json
17 from commands
import getstatusoutput
as ex
19 # on récupère la config
20 import config_basile
as config
22 def get_config_logfile(serveur
):
23 serveurs
={"acoeur.crans.org":"acoeur","irc.crans.org":"crans"}
24 return config
.logfile_template
%(serveurs
[serveur
])
27 return ex("ls -s %s"%(config
.thisfile
))[1].split()[0]
29 class NKError(Exception):
30 def __init__(self
,msg
):
31 Exception.__init
__(self
)
35 def __unicode__(self
):
36 return unicode(self
.msg
)
38 class NKRefused(NKError
):
41 class NKHelloFailed(NKError
):
44 class NKUnknownError(NKError
):
47 def log(serveur
,channel
,auteur
=None,message
=None):
48 f
=open(get_config_logfile(serveur
),"a")
49 if auteur
==message
==None:
50 # alors c'est que c'est pas un channel mais juste une ligne de log
51 chain
="%s %s"%(time
.strftime("%F %T"),channel
)
53 chain
="%s [%s:%s] %s"%(time
.strftime("%F %T"),channel
,auteur
,message
)
55 if config
.debug_stdout
:
62 # On établit la connexion sur port 4242
63 sock
.connect(("127.0.0.1",4242))
65 sock
=ssl
.wrap_socket(sock
,ca_certs
='../keys/ca_.crt')
67 sock
.write('hello "Basile"')
68 # On récupère la réponse du hello
71 except Exception as exc
:
72 # Si on a foiré quelque part, c'est que le serveur est down
73 raise NKRefused(str(exc
))
76 elif out
["retcode"]==11:
77 raise NKHelloFailed(out
["errmsg"])
79 raise NKUnknownError(out
["errmsg"])
81 def login_NK(username
,password
,typ
="bdd"):
83 if typ
=="special": # ça c'est pour Basile lui-même
86 masque
='[["all"],["all"],false]'
88 # Basile a un compte special user
89 commande
='login [%s,%s,"%s",%s]'%(json
.dumps(username
),json
.dumps(password
),typ
,masque
)
92 except Exception as exc
:
93 # Si on a foiré quelque part, c'est que le serveur est down
94 raise NKRefused(str(exc
))
95 # On vérifie ensuite que le login
96 return json
.loads(out
),sock
99 def is_something(chain
,matches
,avant
=u
".*(?:^| )",apres
=u
"(?:$|\.| |,|;).*",case_sensitive
=False,debug
=False):
101 chain
=unicode(chain
,"utf8")
103 chain
=unicode(chain
,"utf8").lower()
104 allmatches
="("+"|".join(matches
)+")"
105 reg
=(avant
+allmatches
+apres
).lower()
106 o
=re
.match(reg
,chain
)
109 def is_insult(chain
,debug
=True):
110 return is_something(chain
,config
.insultes
,avant
=".*(?:^| |')")
111 def is_not_insult(chain
):
112 chain
=unicode(chain
,"utf8")
113 insult_regexp
=u
"("+u
"|".join(config
.insultes
)+u
")"
114 middle_regexp
=u
"(une? (?:(?:putain|enfoiré) d(?:e |'))*|)(?:| super )(?: (?:gros|petit|grand|énorme) |)"
115 reg
=".*pas %s%s.*"%(middle_regexp
,insult_regexp
)
116 if re
.match(reg
,chain
):
120 def is_compliment(chain
,debug
=True):
121 return is_something(chain
,config
.compliment_triggers
,avant
=".*(?:^| |')")
123 return is_something(chain
,config
.perdu
)
125 return is_something(chain
,config
.tag_triggers
)
127 return is_something(chain
,config
.gros
)
129 return is_something(chain
,config
.tesla_triggers
,avant
=u
"^",apres
=u
"$",debug
=True)
131 return is_something(chain
,config
.merci_triggers
)
132 def is_tamere(chain
):
133 return is_something(chain
,config
.tamere_triggers
)
134 def is_bad_action_trigger(chain
,pseudo
):
135 return is_something(chain
,config
.bad_action_triggers
,avant
=u
"^",
136 apres
="(?: [a-z]*ment)? %s($|\.| |,|;).*"%(pseudo))
137 def is_good_action_trigger(chain
,pseudo
):
138 return is_something(chain
,config
.good_action_triggers
,avant
=u
"^",
139 apres
="(?: [a-z]*ment)? %s($|\.| |,|;).*"%(pseudo))
140 def is_bonjour(chain
):
141 return is_something(chain
,config
.bonjour_triggers
,avant
=u
"^")
142 def is_bonne_nuit(chain
):
143 return is_something(chain
,config
.bonne_nuit_triggers
,avant
=u
"^")
145 return re
.match(u
"^(pan|bim|bang)( .*)?$",unicode(chain
,"utf8").lower().strip())
148 _
,_
,_
,h
,m
,s
,_
,_
,_
=time
.localtime()
149 return (conf
[0],0,0)<(h
,m
,s
)<(conf
[1],0,0)
151 return is_time(config
.daytime
)
153 return is_time(config
.nighttime
)
156 class UnicodeBotError(Exception):
158 def bot_unicode(chain
):
160 unicode(chain
,"utf8")
161 except UnicodeDecodeError as exc
:
162 raise UnicodeBotError
164 class Basile(ircbot
.SingleServerIRCBot
):
165 def __init__(self
,serveur
,debug
=False):
166 temporary_pseudo
=config
.irc_pseudo
+str(random
.randrange(10000,100000))
167 ircbot
.SingleServerIRCBot
.__init
__(self
, [(serveur
, 6667)],
168 temporary_pseudo
,"Basile, le bot irc.[Codé par 20-100, fouettez-le]", 10)
171 self
.overops
=config
.overops
172 self
.ops
=self
.overops
+config
.ops
173 self
.report_bugs_to
=config
.report_bugs_to
174 self
.chanlist
=config
.chanlist
175 self
.identities
=pickle
.load(open("identities.pickle","r"))
176 self
.stay_channels
=config
.stay_channels
177 self
.quiet_channels
=config
.quiet_channels
181 def new_connection_NK(self
,serv
,username
,password
,typ
="bdd"):
183 login_result
,sock
=login_NK(username
,password
,typ
)
184 droits
,retcode
,errmsg
=login_result
["msg"],login_result
["retcode"],login_result
["errmsg"]
185 except NKRefused
as exc
:
186 for report
in self
.report_bugs_to
:
187 serv
.privmsg(report
,"Le Serveur NK2015 est down.")
189 except NKHelloFailed
as exc
:
190 for report
in self
.report_bugs_to
:
192 "La version du site utilisée n'est pas supportée par le serveur NK2015.")
194 except NKUnknownError
as exc
:
195 erreurs
=["Une fucking erreur inconnue s'est produite"]
196 erreurs
+=str(exc
).split("\n")
197 for report
in self
.report_bugs_to
:
199 serv
.privmsg(report
,err
)
201 except Exception as exc
:
202 # Exception qui ne vient pas de la communication avec le serveur NK2015
203 log(self
.serveur
,"Erreur dans new_connection_NK\n"+str(exc
))
210 def give_me_my_pseudo(self
,serv
):
211 serv
.privmsg("NickServ","RECOVER %s %s"%(config
.irc_pseudo
,config
.irc_password
))
212 serv
.privmsg("NickServ","RELEASE %s %s"%(config
.irc_pseudo
,config
.irc_password
))
214 serv
.nick(config
.irc_pseudo
)
216 def on_welcome(self
, serv
, ev
):
217 self
.serv
=serv
# ça serv ira :)
218 self
.give_me_my_pseudo(serv
)
219 serv
.privmsg("NickServ","identify %s"%(config
.irc_password
))
220 log(self
.serveur
,"Connected")
222 self
.chanlist
=["#bot"]
224 serv
.privmsg("ChanServ", "INVITE #note-dev")
225 for c
in self
.chanlist
:
226 log(self
.serveur
,"JOIN %s"%(c))
228 # on ouvre la connexion note de Basile, special user
229 self
.nk
=self
.new_connection_NK(serv
,config
.note_pseudo
,config
.note_password
,"special")[1]
231 for report
in self
.report_bugs_to
:
232 serv
.privmsg(report
,"Connection to NK2015 failed, invalid password ?")
234 def lost(self
,serv
,channel
,forced
=False):
235 if self
.last_perdu
+config
.time_between_perdu
<time
.time() or forced
:
236 if not channel
in self
.quiet_channels
or forced
:
237 serv
.privmsg(channel
,"J'ai perdu !")
238 self
.last_perdu
=time
.time()
239 delay
=config
.time_between_perdu_trigger
240 delta
=config
.time_between_perdu_trigger_delta
241 serv
.execute_delayed(random
.randrange(delay
-delta
,delay
+delta
),self
.lost
,(serv
,channel
))
243 def pourmoi(self
, serv
, message
):
244 """renvoie (False,lemessage) ou (True, le message amputé de "pseudo: ")"""
247 if message
[:size
]==pseudo
and len(message
)>size
and message
[size
]==":":
248 return (True,message
[size
+1:].lstrip(" "))
250 return (False,message
)
252 def on_privmsg(self
, serv
, ev
):
253 message
=ev
.arguments()[0]
254 auteur
= irclib
.nm_to_n(ev
.source())
256 test
=bot_unicode(message
)
257 except UnicodeBotError
:
258 if config
.utf8_trigger
:
259 serv
.privmsg(auteur
, random
.choice(config
.utf8_fail_answers
).encode("utf8"))
261 message
=message
.split()
262 cmd
=message
[0].lower()
265 helpdico
={"help":["""HELP <commande>
266 Affiche de l'aide sur la commande""",None,None],
267 "identify": ["""IDENTIFY <username> <password>
268 Vérifie le mot de passe et me permet de savoir à l'avenir quel est votre pseudo note kfet.
269 Sans paramètre, je vous précise sous quel pseudo je vous connais.""",None,None],
270 "drop":["""DROP <password>
271 Vérifie le mot de passe et me fait d'oublier votre pseudo note kfet.""",None,None],
273 Affiche votre solde, si je connais votre pseudo note kfet.""",
275 Affiche le solde de la personne désignée (par son pseudo note).""",None],
276 "join": [None, """JOIN <channel>
277 Me fait rejoindre le channel""",None],
278 "leave": [None,"""LEAVE <channel>
279 Me fait quitter le channel (sauf s'il est dans ma stay_list).""",None],
280 "quiet": [None,"""QUIET <channel>
281 Me rend silencieux sur le channel.""",None],
282 "noquiet": [None,"""NOQUIET <channel>
283 Me rend la parole sur le channel.""",None],
284 "lost": [None,"""LOST <channel>
285 Me fait perdre sur le channel.""",None],
286 "reconnect": [None,"""RECONNECT
287 Établit à nouveau la connexion avec le serveur NK2015""",None],
288 "say": [None,None,"""SAY <channel> <message>
289 Me fait parler sur le channel."""],
290 "do": [None,None,"""DO <channel> <action>
291 Me fait faitre une action (/me) sur le channel."""],
292 "stay": [None,None,"""STAY <channel>
293 Ajoute le channel à ma stay_list."""],
294 "nostay": [None,None,"""NOSTAY <channel>
295 Retire le channel de ma stay_list."""],
296 "ops": [None,None,"""OPS
297 Affiche la liste des ops."""],
298 "overops": [None,None,"""OVEROPS
299 Affiche la liste des overops."""],
300 "kick": [None,None,"""KICK <channel> <pseudo> [<raison>]
301 Kicke <pseudo> du channel (Il faut bien entendu que j'y sois op)."""],
302 "die": [None,None,"""DIE
303 Me déconnecte du serveur IRC."""]
305 helpmsg_default
="Liste des commandes disponibles :\nHELP IDENTIFY DROP SOLDE"
306 helpmsg_ops
=" JOIN LEAVE QUIET NOQUIET LOST RECONNECT"
307 helpmsg_overops
=" SAY DO STAY NOSTAY OPS OVEROPS KICK DIE"
308 op
,overop
=auteur
in self
.ops
, auteur
in self
.overops
310 helpmsg
=helpmsg_default
314 helpmsg
+=helpmsg_overops
316 helpmsgs
=helpdico
.get(message
[1].lower(),["Commande inconnue.",None,None])
318 if op
and helpmsgs
[1]:
320 helpmsg
+="\n"+helpmsgs
[1]
323 if overop
and helpmsgs
[2]:
325 helpmsg
+="\n"+helpmsgs
[2]
328 for ligne
in helpmsg
.split("\n"):
329 serv
.privmsg(auteur
,ligne
)
330 elif cmd
=="identify":
332 if self
.identities
.has_key(auteur
):
333 serv
.privmsg(auteur
,"Je vous connais sous le pseudo note %s."%(
334 self
.identities
[auteur
].encode("utf8")))
336 serv
.privmsg(auteur
,"Je ne connais pas votre pseudo note.")
337 elif len(message
)>=3:
338 username
,password
=message
[1],unicode(" ".join(message
[2:]),"utf8")
339 success
,_
=self
.new_connection_NK(serv
,username
,password
)
341 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
342 serv
.privmsg(auteur
,"Identité enregistrée.")
343 self
.identities
[auteur
]=username
344 pickle
.dump(Xself
.identities
,open("identities.pickle","w"))
346 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
347 serv
.privmsg(auteur
,"Mot de passe invalide. (ou serveur down)")
349 serv
.privmsg(auteur
,u
"Syntaxe : IDENTIFY [<username> <password>]")
352 if self
.identities
.has_key(auteur
):
353 password
=" ".join(message
[1:])
354 success
,_
=self
.new_connection_NK(serv
,self
.identities
[auteur
],password
)
356 del self
.identities
[auteur
]
357 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
358 pickle
.dump(self
.identities
,open("identities.pickle","w"))
359 serv
.privmsg(auteur
,"Identité oubliée.")
361 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
362 serv
.privmsg(auteur
,"Mot de passe invalide. (ou serveur down)")
364 serv
.privmsg(auteur
,"Je ne connais pas ton pseudo note.")
366 serv
.privmsg(auteur
,"Syntaxe : DROP <password>")
368 if auteur
in self
.ops
:
370 if message
[1] in self
.chanlist
:
371 serv
.privmsg(auteur
,"Je suis déjà sur %s"%(message
[1]))
373 serv
.join(message
[1])
374 self
.chanlist
.append(message
[1])
375 serv
.privmsg(auteur
,"Channels : "+" ".join(self
.chanlist
))
376 log(self
.serveur
,"priv",auteur
," ".join(message
))
378 serv
.privmsg(auteur
,"Channels : "+" ".join(self
.chanlist
))
382 if auteur
in self
.ops
and len(message
)>1:
383 if message
[1] in self
.chanlist
:
384 if not (message
[1] in self
.stay_channels
) or auteur
in self
.overops
:
385 self
.quitter(message
[1]," ".join(message
[2:]))
386 self
.chanlist
.remove(message
[1])
387 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
389 serv
.privmsg(auteur
,"Non, je reste !")
390 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
392 serv
.privmsg(auteur
,"Je ne suis pas sur %s"%(message
[1]))
396 if auteur
in self
.overops
:
398 if message
[1] in self
.stay_channels
:
399 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
400 serv
.privmsg(auteur
,"Je stay déjà sur %s."%(message
[1]))
402 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
403 self
.stay_channels
.append(message
[1])
404 serv
.privmsg(auteur
,"Stay channels : "+" ".join(self
.stay_channels
))
406 serv
.privmsg(auteur
,"Stay channels : "+" ".join(self
.stay_channels
))
410 if auteur
in self
.overops
:
412 if message
[1] in self
.stay_channels
:
413 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
414 self
.stay_channels
.remove(message
[1])
415 serv
.privmsg(auteur
,"Stay channels : "+" ".join(self
.stay_channels
))
417 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
418 serv
.privmsg(auteur
,"Je ne stay pas sur %s."%(message
[1]))
423 if auteur
in self
.overops
:
424 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
428 elif cmd
=="reconnect":
429 if auteur
in self
.ops
:
431 self
.nk
=self
.new_connection_NK(serv
,config
.note_pseudo
,
432 config
.note_password
,"special")[1]
433 except Exception as exc
:
435 log(self
.serveur
,"""Erreur dans on_pubmsg/"cmd in ["reconnect"]\n"""+str(exc
))
437 serv
.privmsg(auteur
,"%s: done"%(auteur))
438 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
440 serv
.privmsg(auteur
,"%s: failed"%(auteur))
441 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
442 for report
in self
.report_bugs_to
:
443 serv
.privmsg(report
,"Connection to NK2015 failed, invalid password ? Server dead ?")
447 if auteur
in self
.ops
:
449 if message
[1] in self
.quiet_channels
:
450 serv
.privmsg(auteur
,"Je me la ferme déjà sur %s"%(message
[1]))
451 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
453 self
.quiet_channels
.append(message
[1])
454 serv
.privmsg(auteur
,"Quiet channels : "+" ".join(self
.quiet_channels
))
455 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
457 serv
.privmsg(auteur
,"Quiet channels : "+" ".join(self
.quiet_channels
))
461 if auteur
in self
.ops
:
463 if message
[1] in self
.quiet_channels
:
464 self
.quiet_channels
.remove(message
[1])
465 serv
.privmsg(auteur
,"Quiet channels : "+" ".join(self
.quiet_channels
))
466 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
468 serv
.privmsg(auteur
,"Je ne me la ferme pas sur %s."%(message
[1]))
469 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
473 if auteur
in self
.overops
and len(message
)>2:
474 serv
.privmsg(message
[1]," ".join(message
[2:]))
475 log(self
.serveur
,"priv",auteur
," ".join(message
))
476 elif len(message
)<=2:
477 serv
.privmsg(auteur
,"Syntaxe : SAY <channel> <message>")
481 if auteur
in self
.overops
and len(message
)>2:
482 serv
.action(message
[1]," ".join(message
[2:]))
483 log(self
.serveur
,"priv",auteur
," ".join(message
))
484 elif len(message
)<=2:
485 serv
.privmsg(auteur
,"Syntaxe : DO <channel> <action>")
489 if auteur
in self
.overops
and len(message
)>2:
490 serv
.kick(message
[1],message
[2]," ".join(message
[3:]))
491 log(self
.serveur
,"priv",auteur
," ".join(message
))
492 elif len(message
)<=2:
493 serv
.privmsg(auteur
,"Syntaxe : KICK <channel> <pseudo> [<raison>]")
497 if auteur
in self
.ops
and len(message
)>1:
498 serv
.privmsg(message
[1],"J'ai perdu !")
499 log(self
.serveur
,"priv",auteur
," ".join(message
))
500 elif len(message
)<=1:
501 serv
.privmsg(auteur
,"Syntaxe : LOST <channel>")
506 if self
.identities
.has_key(auteur
):
508 self
.nk
.write('search ["x",["pseudo"],%s]'%(json
.dumps(self
.identities
[auteur
])))
509 ret
=json
.loads(self
.nk
.read())
510 solde
=ret
["msg"][0]["solde"]
511 pseudo
=ret
["msg"][0]["pseudo"]
512 except Exception as exc
:
514 serv
.privmsg(auteur
,"failed")
515 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
517 serv
.privmsg(auteur
,"%s (%s)"%(float(solde
)/100,pseudo
.encode("utf8")))
518 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
520 serv
.privmsg(canal
,"Je ne connais pas ton pseudo note.")
521 elif auteur
in self
.ops
:
523 self
.nk
.write('search ["x",["pseudo"],%s]'%(json
.dumps(message
[1])))
524 ret
=json
.loads(self
.nk
.read())
525 solde
=ret
["msg"][0]["solde"]
526 pseudo
=ret
["msg"][0]["pseudo"]
527 except Exception as exc
:
528 serv
.privmsg(auteur
,"failed")
529 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
531 serv
.privmsg(auteur
,"%s (%s)"%(float(solde
)/100,pseudo
.encode("utf8")))
533 if auteur
in self
.overops
:
534 serv
.privmsg(auteur
," ".join(self
.ops
))
538 if auteur
in self
.overops
:
539 serv
.privmsg(auteur
," ".join(self
.overops
))
545 serv
.privmsg(auteur
,"Je n'ai pas compris. Essayez HELP…")
547 def on_pubmsg(self
, serv
, ev
):
548 auteur
= irclib
.nm_to_n(ev
.source())
550 message
= ev
.arguments()[0]
552 test
=bot_unicode(message
)
553 except UnicodeBotError
:
554 if config
.utf8_trigger
and not canal
in self
.quiet_channels
:
555 serv
.privmsg(canal
, (u
"%s: %s"%(auteur
,random
.choice(config
.utf8_fail_answers
))).encode("utf8"))
557 pour_moi
,message
=self
.pourmoi(serv
,message
)
558 if pour_moi
and message
.split()!=[]:
559 cmd
=message
.split()[0].lower()
561 args
=" ".join(message
.split()[1:])
564 if cmd
in ["meurs","die","crève"]:
565 if auteur
in self
.overops
:
566 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
569 serv
.privmsg(canal
,("%s: %s"%(auteur
,random
.choice(config
.quit_fail_messages
))).encode("utf8"))
570 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
572 elif cmd
in ["part","leave","dégage","va-t-en","tut'tiresailleurs,c'estmesgalets"]:
573 if auteur
in self
.ops
and (not (canal
in self
.stay_channels
)
574 or auteur
in self
.overops
):
576 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
577 if canal
in self
.chanlist
:
578 self
.chanlist
.remove(canal
)
580 serv
.privmsg(canal
,("%s: %s"%(auteur
,random
.choice(config
.leave_fail_messages
))).encode("utf8"))
581 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
583 elif cmd
in ["reconnect"]:
584 if auteur
in self
.ops
:
586 self
.nk
=self
.new_connection_NK(serv
,config
.note_pseudo
,
587 config
.note_password
,"special")[1]
588 except Exception as exc
:
590 log(self
.serveur
,"""Erreur dans on_pubmsg/"cmd in ["reconnect"]\n"""+str(exc
))
592 serv
.privmsg(canal
,"%s: done"%(auteur))
593 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
595 serv
.privmsg(canal
,"%s: failed"%(auteur))
596 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
597 for report
in self
.report_bugs_to
:
598 serv
.privmsg(report
,"Connection to NK2015 failed, invalid password ? Server dead ?")
600 serv
.privmsg(canal
,"%s: %s"%(auteur
,random
.choice(config
.pas_programme_pour_tobeir
).encode("utf8")))
601 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
603 elif cmd
in ["deviens","pseudo"]:
604 if auteur
in self
.ops
:
607 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
609 if cmd
in ["meur", "meurt","meurre","meurres"] and not canal
in self
.quiet_channels
:
610 serv
.privmsg(canal
,'%s: Mourir, impératif, 2ème personne du singulier : "meurs" (de rien)'%(auteur))
611 elif cmd
in ["ping"] and not canal
in self
.quiet_channels
:
612 serv
.privmsg(canal
,"%s: pong"%(auteur))
614 elif cmd
in ["solde","!solde"]:
615 if self
.identities
.has_key(auteur
):
616 pseudo
=self
.identities
[auteur
]
618 self
.nk
.write('search ["x",["pseudo"],%s]'%(json
.dumps(pseudo
)))
619 ret
=json
.loads(self
.nk
.read())
620 solde
=ret
["msg"][0]["solde"]
621 pseudo
=ret
["msg"][0]["pseudo"]
622 except Exception as exc
:
623 serv
.privmsg(canal
,"%s: failed"%(auteur))
624 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
626 serv
.privmsg(canal
,"%s: %s (%s)"%(auteur
,float(solde
)/100,pseudo
.encode("utf8")))
627 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
629 serv
.privmsg(canal
,"%s: Je ne connais pas votre pseudo note."%(auteur))
630 log(self
.serveur
,canal
,auteur
,message
+"[unknown]")
631 elif (re
.match("!?(pain au chocolat|chocolatine)",message
.lower())
632 and not canal
in self
.quiet_channels
):
633 serv
.action(canal
,"sert un pain au chocolat à %s"%(auteur))
634 elif re
.match("!?manzana",message
.lower()) and not canal
in self
.quiet_channels
:
635 if auteur
in config
.manzana
:
636 serv
.action(canal
,"sert une bouteille de manzana à %s"%(auteur))
637 elif auteur
in config
.manzana_bis
:
638 serv
.action(canal
,"sert un grand verre de jus de pomme à %s : tout le monde sait qu'il ne boit pas."%(auteur))
640 serv
.action(canal
,"sert un verre de manzana à %s"%(auteur))
641 if is_insult(message
) and not canal
in self
.quiet_channels
:
642 if is_not_insult(message
):
643 answer
=random
.choice(config
.compliment_answers
)
644 for ligne
in answer
.split("\n"):
645 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
647 answer
=random
.choice(config
.insultes_answers
)
648 for ligne
in answer
.split("\n"):
649 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
650 elif is_compliment(message
) and not canal
in self
.quiet_channels
:
651 answer
=random
.choice(config
.compliment_answers
)
652 for ligne
in answer
.split("\n"):
653 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
654 gros_match
=is_gros(message
)
655 if gros_match
and not canal
in self
.quiet_channels
:
656 taille
=get_filesize()
657 answer
=u
"Mais non, je ne suis pas %s, %sKo tout au plus…"%(gros_match
.groups()[0],taille
)
658 serv
.privmsg(canal
,"%s: %s"%(auteur
,answer
.encode("utf8")))
659 if is_tesla(message
) and not canal
in self
.quiet_channels
:
660 l1
,l2
=config
.tesla_answers
,config
.tesla_actions
661 n1
,n2
=len(l1
),len(l2
)
662 i
=random
.randrange(n1
+n2
)
664 serv
.action(canal
,l2
[i
-n1
].encode("utf8"))
666 serv
.privmsg(canal
,"%s: %s"%(auteur
,l1
[i
].encode("utf8")))
667 if is_tamere(message
) and not canal
in self
.quiet_channels
:
668 answer
=random
.choice(config
.tamere_answers
)
669 for ligne
in answer
.split("\n"):
670 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
671 if is_tag(message
) and not canal
in self
.quiet_channels
:
672 if auteur
in self
.ops
:
673 action
=random
.choice(config
.tag_actions
)
674 serv
.action(canal
,action
.encode("utf8"))
675 self
.quiet_channels
.append(canal
)
677 answer
=random
.choice(config
.tag_answers
)
678 for ligne
in answer
.split("\n"):
679 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
680 if is_merci(message
):
681 answer
=random
.choice(config
.merci_answers
)
682 for ligne
in answer
.split("\n"):
683 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
684 out
=re
.match(ur
"^([A-Z[]|\\|[0-9]+|(¹|²|³|⁴|⁵|⁶|⁷|⁸|⁹|⁰)+)(?:| \?| !)$",
685 unicode(message
.upper(),"utf8"))
686 if re
.match("ma bite dans ton oreille",message
) and not canal
in self
.quiet_channels
:
687 serv
.privmsg(canal
,"%s: Seul un olasd peut imiter un olasd dans un de ses grands jours !"%(auteur))
688 if out
and not canal
in self
.quiet_channels
:
692 serv
.privmsg(canal
,"%s: %s !"%(auteur
,out
+1))
694 serv
.privmsg(canal
,"%s: Ciel, un maxint ! Heureusement que je suis en python…"%(auteur))
696 if out
+1>1000 and random
.randrange(4)==0:
697 serv
.privmsg(canal
,"%s: Vous savez, moi et les chiffres…"%(auteur))
699 except Exception as exc
:
701 if re
.match("[A-Y]",out
):
702 alphabet
="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
703 serv
.privmsg(canal
,"%s: %s !"%(auteur
,alphabet
[alphabet
.index(out
)+1]))
705 serv
.privmsg(canal
,"%s: Je ne vous remercie pas, j'ai l'air idiot ainsi… [ ?"%(auteur))
707 serv
.privmsg(canal
,"%s: Nous devrions nous en tenir là, ça va finir par poser des problèmes…"%(auteur))
708 elif re
.match(ur
"(¹|²|³|⁴|⁵|⁶|⁷|⁸|⁹|⁰)+",out
):
710 return "".join([{u
"⁰¹²³⁴⁵⁶⁷⁸⁹0123456789"[i
]:u
"0123456789⁰¹²³⁴⁵⁶⁷⁸⁹"[i
]
711 for i
in range(20)}[j
]
713 out
=int(translate(out
))
714 serv
.privmsg(canal
,"%s: %s !"%(auteur
,translate(str(out
+1)).encode("utf8")))
715 if is_bonjour(message
) and not canal
in self
.quiet_channels
:
717 answer
=random
.choice(config
.night_answers
)
719 answer
=random
.choice(config
.bonjour_answers
)
721 answer
=random
.choice(config
.bonsoir_answers
)
722 serv
.privmsg(canal
,answer
.format(auteur
).encode("utf8"))
723 if is_bonne_nuit(message
) and not canal
in self
.quiet_channels
:
724 answer
=random
.choice(config
.bonne_nuit_answers
)
725 serv
.privmsg(canal
,answer
.format(auteur
).encode("utf8"))
726 if is_pan(message
) and not canal
in self
.quiet_channels
:
727 serv
.privmsg(canal
,"%s: ce n'est pas sur moi qu'il faut tirer, même si je sais que j'attire l'œil !"%(auteur))
729 if message
in ["!pain au chocolat","!chocolatine"] and not canal
in self
.quiet_channels
:
730 serv
.action(canal
,"sert un pain au chocolat à %s"%(auteur))
731 if message
in ["!manzana"] and not canal
in self
.quiet_channels
:
732 if auteur
in config
.manzana
:
733 serv
.action(canal
,"sert une bouteille de manzana à %s"%(auteur))
734 elif auteur
in config
.manzana_bis
:
735 serv
.action(canal
,"sert un grand verre de jus de pomme à %s : tout le monde sait qu'il ne boit pas."%(auteur))
737 serv
.action(canal
,"sert un verre de manzana à %s"%(auteur))
738 if re
.match(u
'^ *(.|§|!|/|/|:|)(w|b) [0-9]+$',message
.decode("utf8")) and not canal
in self
.quiet_channels
:
739 failanswers
=config
.buffer_fail_answers
740 answer
=random
.choice(failanswers
)
741 serv
.privmsg(canal
,("%s: %s"%(auteur
,answer
)).encode("utf8"))
742 if not canal
in self
.quiet_channels
:
744 if re
.match((u
"^("+u
"|".join(config
.bonjour_triggers
)
745 +u
")( {}| all| tout le monde|(|à) tous)(\.|( |)!|)$"
746 ).format(mypseudo
).lower(), message
.strip().lower()):
747 answer
=random
.choice(config
.bonjour_answers
)
748 serv
.privmsg(canal
,answer
.format(auteur
).encode("utf8"))
749 if (is_perdu(message
) and not canal
in self
.quiet_channels
):
750 # proba de perdre sur trigger :
751 # avant 30min (enfin, config) : 0
752 # ensuite, +25%/30min, linéairement
753 deltat
=time
.time()-self
.last_perdu
754 barre
=(deltat
-config
.time_between_perdu
)/(2*3600.0)
755 if random
.uniform(0,1)<barre
:
756 serv
.privmsg(canal
,"%s: J'ai perdu !"%(auteur))
757 self
.last_perdu
=time
.time()
759 def on_action(self
, serv
, ev
):
760 action
= ev
.arguments()[0]
761 auteur
= irclib
.nm_to_n(ev
.source())
762 channel
= ev
.target()
764 test
=bot_unicode(action
)
765 except UnicodeBotError
:
766 if config
.utf8_trigger
and not channel
in self
.quiet_channels
:
767 serv
.privmsg(channel
, (u
"%s: %s"%(auteur
,random
.choice(config
.utf8_fail_answers
))).encode("utf8"))
771 if is_bad_action_trigger(action
,mypseudo
) and not channel
in self
.quiet_channels
:
772 l1
,l2
=config
.bad_action_answers
,config
.bad_action_actions
773 n1
,n2
=len(l1
),len(l2
)
774 i
=random
.randrange(n1
+n2
)
776 serv
.action(channel
,l2
[i
-n1
].format(auteur
).encode("utf8"))
778 serv
.privmsg(channel
,l1
[i
].format(auteur
).format(auteur
).encode("utf8"))
779 if is_good_action_trigger(action
,mypseudo
) and not channel
in self
.quiet_channels
:
780 l1
,l2
=config
.good_action_answers
,config
.good_action_actions
781 n1
,n2
=len(l1
),len(l2
)
782 i
=random
.randrange(n1
+n2
)
784 serv
.action(channel
,l2
[i
-n1
].format(auteur
).format(auteur
).encode("utf8"))
786 serv
.privmsg(channel
,l1
[i
].format(auteur
).format(auteur
).encode("utf8"))
788 def on_kick(self
,serv
,ev
):
789 auteur
= irclib
.nm_to_n(ev
.source())
790 channel
= ev
.target()
791 victime
= ev
.arguments()[0]
792 raison
= ev
.arguments()[1]
793 if victime
==self
.nick
:
794 log(self
.serveur
,"%s kické de %s par %s (raison : %s)" %(victime
,channel
,auteur
,raison
))
797 l1
,l2
=config
.kick_answers
,config
.kick_actions
798 n1
,n2
=len(l1
),len(l2
)
799 i
=random
.randrange(n1
+n2
)
801 serv
.action(channel
,l2
[i
-n1
].format(auteur
).encode("utf8"))
803 serv
.privmsg(channel
,l1
[i
].format(auteur
).encode("utf8"))
805 def quitter(self
,chan
,leave_message
=None):
806 if leave_message
==None:
807 leave_message
=random
.choice(config
.leave_messages
)
808 self
.serv
.part(chan
,message
=leave_message
.encode("utf8"))
811 quit_message
=random
.choice(config
.quit_messages
)
812 self
.die(msg
=quit_message
.encode("utf8"))
815 return self
.serv
.get_nickname()
816 nick
=property(_getnick
)
819 if __name__
=="__main__":
822 print "Usage : basile.py <serveur> [--debug]"
825 if "debug" in sys
.argv
or "--debug" in sys
.argv
:
829 if "--quiet" in sys
.argv
:
830 config
.debug_stdout
=False
831 serveurs
={"a♡":"acoeur.crans.org","acoeur":"acoeur.crans.org","acoeur.crans.org":"acoeur.crans.org",
832 "irc":"irc.crans.org","crans":"irc.crans.org","irc.crans.org":"irc.crans.org"}
834 serveur
=serveurs
[serveur
]
836 print "Server Unknown : %s"%(serveur)
838 basile
=Basile(serveur
,debug
)