]>
gitweb.pimeys.fr Git - bots/saturnin.git/blob - saturnin.py
2 # -*- encoding: utf-8 -*-
6 # Un bot IRC pour remplacer le canard.
7 # parce que le canard, c'est le bien et que braice ne pong pas
14 import socket
, ssl
, json
18 from commands
import getstatusoutput
as ex
20 # on récupère la config
25 def get_config_logfile(serveur
):
26 serveurs
={"acoeur.crans.org":"acoeur","irc.crans.org":"crans"}
27 return config
.logfile_template
%(serveurs
[serveur
])
29 def log(serveur
,channel
,auteur
=None,message
=None):
30 f
=open(get_config_logfile(serveur
),"a")
31 if auteur
==message
==None:
32 # alors c'est que c'est pas un channel mais juste une ligne de log
33 chain
="%s %s"%(time
.strftime("%F %T"),channel
)
35 chain
="%s [%s:%s] %s"%(time
.strftime("%F %T"),channel
,auteur
,message
)
37 if config
.debug_stdout
:
41 def is_something(chain
,matches
,avant
=u
".*(?:^| )",apres
=u
"(?:$|\.| |,|;).*",case_sensitive
=False,debug
=False):
43 chain
=unicode(chain
,"utf8")
45 chain
=unicode(chain
,"utf8").lower()
46 allmatches
="("+"|".join(matches
)+")"
47 reg
=(avant
+allmatches
+apres
).lower()
51 regexp_pan
= re
.compile(u
".*(" + "|".join(config
.killwords
) + u
").*")
53 return regexp_pan
.match(unicode(chain
,"utf8").lower())
55 class UnicodeBotError(Exception):
57 def bot_unicode(chain
):
60 except UnicodeDecodeError as exc
:
63 class Saturnin(ircbot
.SingleServerIRCBot
):
64 def __init__(self
,serveur
,debug
=False):
65 temporary_pseudo
=config
.irc_pseudo
+str(random
.randrange(10000,100000))
66 ircbot
.SingleServerIRCBot
.__init
__(self
, [(serveur
, 6667)],
67 temporary_pseudo
,"Coin ? ©braice [mais 'faut frapper 20-100]", 10)
70 self
.overops
=config
.overops
71 self
.ops
=self
.overops
+config
.ops
72 self
.chanlist
=config
.chanlist
73 self
.stay_channels
=config
.stay_channels
74 self
.quiet_channels
=config
.quiet_channels
75 self
.spawn_channels
=config
.spawn_channels
76 self
.status
= { chan
: False for chan
in self
.spawn_channels
}
79 def give_me_my_pseudo(self
,serv
):
80 serv
.privmsg("NickServ","RECOVER %s %s"%(config
.irc_pseudo
,config
.irc_password
))
81 serv
.privmsg("NickServ","RELEASE %s %s"%(config
.irc_pseudo
,config
.irc_password
))
83 serv
.nick(config
.irc_pseudo
)
85 def on_welcome(self
, serv
, ev
):
86 self
.serv
=serv
# ça serv ira :)
87 self
.give_me_my_pseudo(serv
)
88 serv
.privmsg("NickServ","IDENTIFY %s"%(config
.irc_password
))
89 log(self
.serveur
,"Connected")
91 self
.chanlist
= self
.spawn_channels
= ["#bot"]
92 self
.status
= { chan
: False for chan
in self
.spawn_channels
}
93 for c
in self
.chanlist
:
94 log(self
.serveur
,"JOIN %s"%(c))
97 def pourmoi(self
, serv
, message
):
98 """renvoie (False,lemessage) ou (True, le message amputé de "pseudo: ")"""
101 if message
[:size
]==pseudo
and len(message
)>size
and message
[size
]==":":
102 return (True,message
[size
+1:].lstrip(" "))
104 return (False,message
)
106 def on_privmsg(self
, serv
, ev
):
107 message
=ev
.arguments()[0]
108 auteur
= irclib
.nm_to_n(ev
.source())
110 test
=bot_unicode(message
)
111 except UnicodeBotError
:
112 if config
.utf8_trigger
:
113 serv
.privmsg(auteur
, random
.choice(config
.utf8_fail_answers
).encode("utf8"))
115 message
=message
.split()
116 cmd
=message
[0].lower()
119 helpdico
={"help":["""HELP <commande>
120 Affiche de l'aide sur la commande""",None,None],
122 Affiche votre score""", None, None],
124 Afficher tous les scores""", None, None],
125 "join": [None, """JOIN <channel>
126 Me fait rejoindre le channel""",None],
127 "leave": [None,"""LEAVE <channel>
128 Me fait quitter le channel (sauf s'il est dans ma stay_list).""",None],
129 "quiet": [None,"""QUIET <channel>
130 Me rend silencieux sur le channel.""",None],
131 "noquiet": [None,"""NOQUIET <channel>
132 Me rend la parole sur le channel.""",None],
133 "say": [None,None,"""SAY <channel> <message>
134 Me fait parler sur le channel."""],
135 "do": [None,None,"""DO <channel> <action>
136 Me fait faitre une action (/me) sur le channel."""],
137 "stay": [None,None,"""STAY <channel>
138 Ajoute le channel à ma stay_list."""],
139 "nostay": [None,None,"""NOSTAY <channel>
140 Retire le channel de ma stay_list."""],
141 "ops": [None,None,"""OPS
142 Affiche la liste des ops."""],
143 "overops": [None,None,"""OVEROPS
144 Affiche la liste des overops."""],
145 "kick": [None,None,"""KICK <channel> <pseudo> [<raison>]
146 Kicke <pseudo> du channel (Il faut bien entendu que j'y sois op)."""],
147 "die": [None,None,"""DIE
148 Me déconnecte du serveur IRC."""]
150 helpmsg_default
="Liste des commandes disponibles :\nHELP SCORE SCORES"
151 helpmsg_ops
=" JOIN LEAVE QUIET NOQUIET LOST"
152 helpmsg_overops
=" SAY DO STAY NOSTAY OPS OVEROPS KICK DIE"
153 op
,overop
=auteur
in self
.ops
, auteur
in self
.overops
155 helpmsg
=helpmsg_default
159 helpmsg
+=helpmsg_overops
161 helpmsgs
=helpdico
.get(message
[1].lower(),["Commande inconnue.",None,None])
163 if op
and helpmsgs
[1]:
165 helpmsg
+="\n"+helpmsgs
[1]
168 if overop
and helpmsgs
[2]:
170 helpmsg
+="\n"+helpmsgs
[2]
173 for ligne
in helpmsg
.split("\n"):
174 serv
.privmsg(auteur
,ligne
)
176 if auteur
in self
.ops
:
178 if message
[1] in self
.chanlist
:
179 serv
.privmsg(auteur
,"Je suis déjà sur %s"%(message
[1]))
181 serv
.join(message
[1])
182 self
.chanlist
.append(message
[1])
183 serv
.privmsg(auteur
,"Channels : "+" ".join(self
.chanlist
))
184 log(self
.serveur
,"priv",auteur
," ".join(message
))
186 serv
.privmsg(auteur
,"Channels : "+" ".join(self
.chanlist
))
190 if auteur
in self
.ops
and len(message
)>1:
191 if message
[1] in self
.chanlist
:
192 if not (message
[1] in self
.stay_channels
) or auteur
in self
.overops
:
193 self
.quitter(message
[1]," ".join(message
[2:]))
194 self
.chanlist
.remove(message
[1])
195 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
197 serv
.privmsg(auteur
,"Non, je reste !")
198 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
200 serv
.privmsg(auteur
,"Je ne suis pas sur %s"%(message
[1]))
204 if auteur
in self
.overops
:
206 if message
[1] in self
.stay_channels
:
207 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
208 serv
.privmsg(auteur
,"Je stay déjà sur %s."%(message
[1]))
210 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
211 self
.stay_channels
.append(message
[1])
212 serv
.privmsg(auteur
,"Stay channels : "+" ".join(self
.stay_channels
))
214 serv
.privmsg(auteur
,"Stay channels : "+" ".join(self
.stay_channels
))
218 if auteur
in self
.overops
:
220 if message
[1] in self
.stay_channels
:
221 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
222 self
.stay_channels
.remove(message
[1])
223 serv
.privmsg(auteur
,"Stay channels : "+" ".join(self
.stay_channels
))
225 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
226 serv
.privmsg(auteur
,"Je ne stay pas sur %s."%(message
[1]))
231 if auteur
in self
.overops
:
232 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
237 if auteur
in self
.ops
:
239 if message
[1] in self
.quiet_channels
:
240 serv
.privmsg(auteur
,"Je me la ferme déjà sur %s"%(message
[1]))
241 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
243 self
.quiet_channels
.append(message
[1])
244 serv
.privmsg(auteur
,"Quiet channels : "+" ".join(self
.quiet_channels
))
245 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
247 serv
.privmsg(auteur
,"Quiet channels : "+" ".join(self
.quiet_channels
))
251 if auteur
in self
.ops
:
253 if message
[1] in self
.quiet_channels
:
254 self
.quiet_channels
.remove(message
[1])
255 serv
.privmsg(auteur
,"Quiet channels : "+" ".join(self
.quiet_channels
))
256 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
258 serv
.privmsg(auteur
,"Je ne me la ferme pas sur %s."%(message
[1]))
259 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
263 if auteur
in self
.overops
and len(message
)>2:
264 serv
.privmsg(message
[1]," ".join(message
[2:]))
265 log(self
.serveur
,"priv",auteur
," ".join(message
))
266 elif len(message
)<=2:
267 serv
.privmsg(auteur
,"Syntaxe : SAY <channel> <message>")
271 if auteur
in self
.overops
and len(message
)>2:
272 serv
.action(message
[1]," ".join(message
[2:]))
273 log(self
.serveur
,"priv",auteur
," ".join(message
))
274 elif len(message
)<=2:
275 serv
.privmsg(auteur
,"Syntaxe : DO <channel> <action>")
279 if auteur
in self
.overops
and len(message
)>2:
280 serv
.kick(message
[1],message
[2]," ".join(message
[3:]))
281 log(self
.serveur
,"priv",auteur
," ".join(message
))
282 elif len(message
)<=2:
283 serv
.privmsg(auteur
,"Syntaxe : KICK <channel> <pseudo> [<raison>]")
287 if auteur
in self
.overops
:
288 serv
.privmsg(auteur
," ".join(self
.ops
))
292 if auteur
in self
.overops
:
293 serv
.privmsg(auteur
," ".join(self
.overops
))
298 if len(message
) in [3,4] and message
[1].lower()=="transfert":
299 scores
=self
.get_scores()
300 de
,to
=auteur
,message
[2]
301 value
=scores
.get(de
,0)
304 asked
=int(message
[3])
306 serv
.privmsg(auteur
,"Syntaxe : SCORE TRANSFERT <pseudo> [<n>]")
311 serv
.privmsg(auteur
,"Vous n'avez pas de points")
314 serv
.privmsg(auteur
,"Bien tenté…")
317 serv
.privmsg(auteur
,"Vous n'avez que %s points"%(value))
320 self
.add_score(de
,-asked
)
321 self
.add_score(to
,asked
)
322 serv
.privmsg(auteur
,"Transfert de %s points de %s à %s"%(asked
,de
,to
))
324 serv
.privmsg(auteur
,"Syntaxe : SCORE TRANSFERT <pseudo> [<n>]")
326 self
.sendscore(auteur
)
329 self
.sendscores(auteur
)
330 elif auteur
in self
.overops
:
331 souscmd
=message
[1].lower()
335 scores
=self
.get_scores()
336 if scores
.has_key(todelete
):
338 self
.save_scores(scores
)
339 serv
.privmsg(auteur
,"Score de %s supprimé"%(todelete))
341 serv
.privmsg(auteur
,"Ce score n'existe pas : %s"%(todelete))
343 serv
.privmsg(auteur
,"Syntaxe : SCORES DEL <pseudo>")
344 elif souscmd
in ["add","sub"]:
346 toadd
,val
=message
[2],message
[3]
350 serv
.privmsg(auteur
,"Syntaxe : SCORES {ADD|SUB} <pseudo> <n>")
354 self
.add_score(toadd
,val
)
355 serv
.privmsg(auteur
,"Done")
357 serv
.privmsg(auteur
,"Syntaxe : SCORES {ADD|SUB} <pseudo> <n>")
359 serv
.privmsg(auteur
,"Syntaxe : SCORES {DEL|ADD|SUB} <pseudo> [<n>]")
365 serv
.privmsg(auteur
,"Je n'ai pas compris. Essayez HELP…")
367 def sendscore(self
, to
):
368 self
.serv
.privmsg(to
, "Votre score : %s"%(self
.get_scores().get(to
,0)) )
370 def sendscores(self
, to
):
371 scores
=self
.get_scores().items()
373 scores
.sort(lambda x
,y
:cmp(x
[1],y
[1]))
375 self
.serv
.privmsg(auteur
,"Scores by score : "+" ; ".join(["%s %s"%(i
[0],i
[1]) for i
in scores
]))
377 scores
.sort(lambda x
,y
:cmp(x
[0].lower(),y
[0].lower()))
378 self
.serv
.privmsg(auteur
,"Scores by pseudo : "+" ; ".join(["%s %s"%(i
[0],i
[1]) for i
in scores
]))
380 def on_pubmsg(self
, serv
, ev
):
381 auteur
= irclib
.nm_to_n(ev
.source())
383 message
= ev
.arguments()[0]
385 test
=bot_unicode(message
)
386 except UnicodeBotError
:
387 if config
.utf8_trigger
and not canal
in self
.quiet_channels
:
388 serv
.privmsg(canal
, (u
"%s: %s"%(auteur
,random
.choice(config
.utf8_fail_answers
))).encode("utf8"))
390 pour_moi
,message
=self
.pourmoi(serv
,message
)
391 if pour_moi
and message
.split()!=[]:
392 cmd
=message
.split()[0].lower()
394 args
=" ".join(message
.split()[1:])
397 if cmd
in ["meurs","die","crève"]:
398 if auteur
in self
.overops
:
399 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
402 serv
.privmsg(canal
,("%s: %s"%(auteur
,random
.choice(config
.quit_fail_messages
))).encode("utf8"))
403 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
404 elif cmd
in ["part","leave","dégage","va-t-en","tut'tiresailleurs,c'estmesgalets"]:
405 if auteur
in self
.ops
and (not (canal
in self
.stay_channels
)
406 or auteur
in self
.overops
):
408 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
409 if canal
in self
.chanlist
:
410 self
.chanlist
.remove(canal
)
412 serv
.privmsg(canal
,("%s: %s"%(auteur
,random
.choice(config
.leave_fail_messages
))).encode("utf8"))
413 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
415 self
.sendscore(auteur
)
416 elif cmd
== "scores":
417 self
.sendscores(auteur
)
422 def on_action(self
, serv
, ev
):
423 action
= ev
.arguments()[0]
424 auteur
= irclib
.nm_to_n(ev
.source())
425 channel
= ev
.target()
427 #~ test=bot_unicode(action)
428 #~ except UnicodeBotError:
429 #~ if config.utf8_trigger and not channel in self.quiet_channels:
430 #~ serv.privmsg(channel, (u"%s: %s"%(auteur,random.choice(config.utf8_fail_answers))).encode("utf8"))
432 #~ mypseudo=self.nick
435 def on_kick(self
,serv
,ev
):
436 auteur
= irclib
.nm_to_n(ev
.source())
437 channel
= ev
.target()
438 victime
= ev
.arguments()[0]
439 raison
= ev
.arguments()[1]
440 if victime
==self
.nick
:
441 log(self
.serveur
,"%s kické de %s par %s (raison : %s)" %(victime
,channel
,auteur
,raison
))
444 #~ l1,l2=config.kick_answers,config.kick_actions
445 #~ n1,n2=len(l1),len(l2)
446 #~ i=random.randrange(n1+n2)
448 #~ serv.action(channel,l2[i-n1].format(auteur).encode("utf8"))
450 #~ serv.privmsg(channel,l1[i].format(auteur).encode("utf8"))
452 def quitter(self
,chan
,leave_message
=None):
453 if leave_message
==None:
454 leave_message
=random
.choice(config
.leave_messages
)
455 self
.serv
.part(chan
,message
=leave_message
.encode("utf8"))
458 quit_message
=random
.choice(config
.quit_messages
)
459 self
.die(msg
=quit_message
.encode("utf8"))
461 def get_scores(self
):
462 f
=open(config
.score_file
)
463 scores
=pickle
.load(f
)
467 def add_score(self
,pseudo
,value
):
468 scores
=self
.get_scores()
469 if scores
.has_key(pseudo
):
470 scores
[pseudo
]+=value
473 self
.save_scores(scores
)
475 def save_scores(self
,scores
):
476 f
=open(config
.score_file
,"w")
477 pickle
.dump(scores
,f
)
481 return self
.serv
.get_nickname()
482 nick
=property(_getnick
)
485 if __name__
=="__main__":
488 print "Usage : saturnin.py <serveur> [--debug]"
491 if "debug" in sys
.argv
or "--debug" in sys
.argv
:
495 if "--quiet" in sys
.argv
:
496 config
.debug_stdout
=False
497 serveurs
={"a♡":"acoeur.crans.org","acoeur":"acoeur.crans.org","acoeur.crans.org":"acoeur.crans.org",
498 "irc":"irc.crans.org","crans":"irc.crans.org","irc.crans.org":"irc.crans.org"}
500 serveur
=serveurs
[serveur
]
502 print "Server Unknown : %s"%(serveur)
504 bot
= Saturnin(serveur
,debug
)