]>
gitweb.pimeys.fr Git - bots/helixbot.git/blob - helixbot.py
2 # -*- encoding: utf-8 -*-
6 Un bot IRC qui donne les réponses de Helix the fossil.
14 from commands
import getstatusoutput
as ex
16 # on récupère la config
20 def get_config_logfile(serveur
):
21 """Renvoie le nom du fichier de log en fonction du serveur."""
22 serveurs
= {"acoeur.crans.org" : "acoeur", "irc.crans.org" : "crans"}
23 return config
.logfile_template
% (serveurs
[serveur
])
25 def log(serveur
, channel
, auteur
=None, message
=None):
26 f
= open(get_config_logfile(serveur
), "a")
27 if auteur
== message
== None:
28 # alors c'est que c'est pas un channel mais juste une ligne de log
29 chain
= "%s %s" % (time
.strftime("%F %T"), channel
)
31 chain
= "%s [%s:%s] %s" % (time
.strftime("%F %T"), channel
, auteur
, message
)
33 if config
.debug_stdout
:
37 def is_something(chain
, matches
, avant
=u
".*(?:^| )", apres
=u
"(?:$|\.| |,|;).*", case_sensitive
=False, debug
=False):
39 chain
= unicode(chain
, "utf8")
41 chain
= unicode(chain
, "utf8").lower()
42 allmatches
= "("+"|".join(matches
)+")"
43 reg
= (avant
+allmatches
+apres
).lower()
44 o
= re
.match(reg
, chain
)
48 return is_something(chain
, config
.tag_triggers
)
50 return is_something(chain
, config
.tesla_triggers
, avant
=u
"^", apres
=u
"$", debug
=True)
53 class UnicodeBotError(Exception):
55 def bot_unicode(chain
):
57 unicode(chain
, "utf8")
58 except UnicodeDecodeError as exc
:
61 class HelixBot(ircbot
.SingleServerIRCBot
):
62 def __init__(self
, serveur
, debug
=False):
63 temporary_pseudo
= config
.irc_pseudo
+ str(random
.randrange(10000, 100000))
64 ircbot
.SingleServerIRCBot
.__init
__(self
, [(serveur
, 6667)],
65 temporary_pseudo
, config
.ircname
, 10)
67 self
.serveur
= serveur
68 self
.overops
= config
.overops
69 self
.ops
= self
.overops
+config
.ops
70 self
.chanlist
= config
.chanlist
71 self
.stay_channels
= config
.stay_channels
72 self
.quiet_channels
= config
.quiet_channels
74 def give_me_my_pseudo(self
, serv
):
75 serv
.privmsg("NickServ", "RECOVER %s %s" % (config
.irc_pseudo
, config
.irc_password
))
76 serv
.privmsg("NickServ", "RELEASE %s %s" % (config
.irc_pseudo
, config
.irc_password
))
78 serv
.nick(config
.irc_pseudo
)
80 def on_welcome(self
, serv
, ev
):
81 self
.serv
= serv
# ça serv ira :)
82 self
.give_me_my_pseudo(serv
)
83 serv
.privmsg("NickServ", "identify %s" % (config
.irc_password
))
84 log(self
.serveur
, "Connected")
86 self
.chanlist
= ["#bot"]
87 for c
in self
.chanlist
:
88 log(self
.serveur
, "JOIN %s" % (c
))
91 def pourmoi(self
, serv
, message
):
92 """renvoie (False, lemessage) ou (True, le message amputé de "pseudo: ")"""
95 if message
[:size
] == pseudo
and len(message
)>size
and message
[size
] == ":":
96 return (True, message
[size
+1:].lstrip(" "))
98 return (False, message
)
100 def on_privmsg(self
, serv
, ev
):
101 message
= ev
.arguments()[0]
102 auteur
= irclib
.nm_to_n(ev
.source())
105 except UnicodeBotError
:
106 if config
.utf8_trigger
:
107 serv
.privmsg(auteur
, random
.choice(config
.utf8_fail_answers
).encode("utf8"))
109 message
= message
.split()
110 cmd
= message
[0].lower()
111 notunderstood
= False
113 helpdico
= {"help":["""HELP <commande>
114 Affiche de l'aide sur la commande""", None, None],
115 "join": [None, """JOIN <channel>
116 Me fait rejoindre le channel""", None],
117 "leave": [None, """LEAVE <channel>
118 Me fait quitter le channel (sauf s'il est dans ma stay_list).""", None],
119 "quiet": [None, """QUIET <channel>
120 Me rend silencieux sur le channel.""", None],
121 "noquiet": [None, """NOQUIET <channel>
122 Me rend la parole sur le channel.""", None],
123 "say": [None, None, """SAY <channel> <message>
124 Me fait parler sur le channel."""],
125 "do": [None, None, """DO <channel> <action>
126 Me fait faitre une action (/me) sur le channel."""],
127 "stay": [None, None, """STAY <channel>
128 Ajoute le channel à ma stay_list."""],
129 "nostay": [None, None, """NOSTAY <channel>
130 Retire le channel de ma stay_list."""],
131 "ops": [None, None, """OPS
132 Affiche la liste des ops."""],
133 "overops": [None, None, """OVEROPS
134 Affiche la liste des overops."""],
135 "kick": [None, None, """KICK <channel> <pseudo> [<raison>]
136 Kicke <pseudo> du channel (Il faut bien entendu que j'y sois op)."""],
137 "die": [None, None, """DIE
138 Me déconnecte du serveur IRC."""]
140 helpmsg_default
= "Liste des commandes disponibles :\nHELP"
141 helpmsg_ops
= " JOIN LEAVE QUIET NOQUIET RECONNECT"
142 helpmsg_overops
= " SAY DO STAY NOSTAY OPS OVEROPS KICK DIE"
143 op
, overop
= auteur
in self
.ops
, auteur
in self
.overops
144 if len(message
) == 1:
145 helpmsg
= helpmsg_default
147 helpmsg
+= helpmsg_ops
149 helpmsg
+= helpmsg_overops
151 helpmsgs
= helpdico
.get(message
[1].lower(), ["Commande inconnue.", None, None])
152 helpmsg
= helpmsgs
[0]
153 if op
and helpmsgs
[1]:
155 helpmsg
+= "\n"+helpmsgs
[1]
157 helpmsg
= helpmsgs
[1]
158 if overop
and helpmsgs
[2]:
160 helpmsg
+= "\n"+helpmsgs
[2]
162 helpmsg
= helpmsgs
[2]
163 for ligne
in helpmsg
.split("\n"):
164 serv
.privmsg(auteur
, ligne
)
166 if auteur
in self
.ops
:
168 if message
[1] in self
.chanlist
:
169 serv
.privmsg(auteur
, "Je suis déjà sur %s" % (message
[1]))
171 serv
.join(message
[1])
172 self
.chanlist
.append(message
[1])
173 serv
.privmsg(auteur
, "Channels : "+" ".join(self
.chanlist
))
174 log(self
.serveur
, "priv", auteur
, " ".join(message
))
176 serv
.privmsg(auteur
, "Channels : "+" ".join(self
.chanlist
))
180 if auteur
in self
.ops
and len(message
)>1:
181 if message
[1] in self
.chanlist
:
182 if not (message
[1] in self
.stay_channels
) or auteur
in self
.overops
:
183 self
.quitter(message
[1], " ".join(message
[2:]))
184 self
.chanlist
.remove(message
[1])
185 log(self
.serveur
, "priv", auteur
, " ".join(message
)+"[successful]")
187 serv
.privmsg(auteur
, "Non, je reste !")
188 log(self
.serveur
, "priv", auteur
, " ".join(message
)+"[failed]")
190 serv
.privmsg(auteur
, "Je ne suis pas sur %s" % (message
[1]))
194 if auteur
in self
.overops
:
196 if message
[1] in self
.stay_channels
:
197 log(self
.serveur
, "priv", auteur
, " ".join(message
)+"[failed]")
198 serv
.privmsg(auteur
, "Je stay déjà sur %s." % (message
[1]))
200 log(self
.serveur
, "priv", auteur
, " ".join(message
)+"[successful]")
201 self
.stay_channels
.append(message
[1])
202 serv
.privmsg(auteur
, "Stay channels : "+" ".join(self
.stay_channels
))
204 serv
.privmsg(auteur
, "Stay channels : "+" ".join(self
.stay_channels
))
207 elif cmd
== "nostay":
208 if auteur
in self
.overops
:
210 if message
[1] in self
.stay_channels
:
211 log(self
.serveur
, "priv", auteur
, " ".join(message
)+"[successful]")
212 self
.stay_channels
.remove(message
[1])
213 serv
.privmsg(auteur
, "Stay channels : "+" ".join(self
.stay_channels
))
215 log(self
.serveur
, "priv", auteur
, " ".join(message
)+"[failed]")
216 serv
.privmsg(auteur
, "Je ne stay pas sur %s." % (message
[1]))
221 if auteur
in self
.overops
:
222 log(self
.serveur
, "priv", auteur
, " ".join(message
)+"[successful]")
227 if auteur
in self
.ops
:
229 if message
[1] in self
.quiet_channels
:
230 serv
.privmsg(auteur
, "Je me la ferme déjà sur %s" % (message
[1]))
231 log(self
.serveur
, "priv", auteur
, " ".join(message
)+"[failed]")
233 self
.quiet_channels
.append(message
[1])
234 serv
.privmsg(auteur
, "Quiet channels : "+" ".join(self
.quiet_channels
))
235 log(self
.serveur
, "priv", auteur
, " ".join(message
)+"[successful]")
237 serv
.privmsg(auteur
, "Quiet channels : "+" ".join(self
.quiet_channels
))
240 elif cmd
== "noquiet":
241 if auteur
in self
.ops
:
243 if message
[1] in self
.quiet_channels
:
244 self
.quiet_channels
.remove(message
[1])
245 serv
.privmsg(auteur
, "Quiet channels : "+" ".join(self
.quiet_channels
))
246 log(self
.serveur
, "priv", auteur
, " ".join(message
)+"[successful]")
248 serv
.privmsg(auteur
, "Je ne me la ferme pas sur %s." % (message
[1]))
249 log(self
.serveur
, "priv", auteur
, " ".join(message
)+"[failed]")
253 if auteur
in self
.overops
and len(message
)>2:
254 serv
.privmsg(message
[1], " ".join(message
[2:]))
255 log(self
.serveur
, "priv", auteur
, " ".join(message
))
256 elif len(message
) <= 2:
257 serv
.privmsg(auteur
, "Syntaxe : SAY <channel> <message>")
261 if auteur
in self
.overops
and len(message
)>2:
262 serv
.action(message
[1], " ".join(message
[2:]))
263 log(self
.serveur
, "priv", auteur
, " ".join(message
))
264 elif len(message
) <= 2:
265 serv
.privmsg(auteur
, "Syntaxe : DO <channel> <action>")
269 if auteur
in self
.overops
and len(message
)>2:
270 serv
.kick(message
[1], message
[2], " ".join(message
[3:]))
271 log(self
.serveur
, "priv", auteur
, " ".join(message
))
272 elif len(message
) <= 2:
273 serv
.privmsg(auteur
, "Syntaxe : KICK <channel> <pseudo> [<raison>]")
277 if auteur
in self
.overops
:
278 serv
.privmsg(auteur
, " ".join(self
.ops
))
281 elif cmd
== "overops":
282 if auteur
in self
.overops
:
283 serv
.privmsg(auteur
, " ".join(self
.overops
))
289 serv
.privmsg(auteur
, "Je n'ai pas compris. Essayez HELP…")
291 def on_pubmsg(self
, serv
, ev
):
292 auteur
= irclib
.nm_to_n(ev
.source())
294 message
= ev
.arguments()[0]
297 except UnicodeBotError
:
298 if config
.utf8_trigger
and not canal
in self
.quiet_channels
:
299 serv
.privmsg(canal
, (u
"%s: %s" % (auteur
, random
.choice(config
.utf8_fail_answers
))).encode("utf8"))
301 pour_moi
, message
= self
.pourmoi(serv
, message
)
302 if pour_moi
and message
.split() != []:
303 cmd
= message
.split()[0].lower()
305 args
= " ".join(message
.split()[1:])
308 if cmd
in ["meurs", "die", "crève"]:
309 if auteur
in self
.overops
:
310 log(self
.serveur
, canal
, auteur
, message
+"[successful]")
313 serv
.privmsg(canal
, ("%s: %s" % (auteur
, random
.choice(config
.quit_fail_messages
))).encode("utf8"))
314 log(self
.serveur
, canal
, auteur
, message
+"[failed]")
316 elif cmd
in ["part", "leave", "dégage", "va-t-en", "tut'tiresailleurs, c'estmesgalets"]:
317 if auteur
in self
.ops
and (not (canal
in self
.stay_channels
)
318 or auteur
in self
.overops
):
320 log(self
.serveur
, canal
, auteur
, message
+"[successful]")
321 if canal
in self
.chanlist
:
322 self
.chanlist
.remove(canal
)
324 serv
.privmsg(canal
, ("%s: %s" % (auteur
, random
.choice(config
.leave_fail_messages
))).encode("utf8"))
325 log(self
.serveur
, canal
, auteur
, message
+"[failed]")
327 elif cmd
in ["deviens", "pseudo"]:
328 if auteur
in self
.ops
:
331 log(self
.serveur
, canal
, auteur
, message
+"[successful]")
333 elif cmd
in ["ping"] and not canal
in self
.quiet_channels
:
334 serv
.privmsg(canal
, "%s: pong" % (auteur
))
335 if is_tag(message
) and not canal
in self
.quiet_channels
:
336 if auteur
in self
.ops
:
337 action
= random
.choice(config
.tag_actions
)
338 serv
.action(canal
, action
.encode("utf8"))
339 self
.quiet_channels
.append(canal
)
341 answer
= random
.choice(config
.tag_answers
)
342 for ligne
in answer
.split("\n"):
343 serv
.privmsg(canal
, "%s: %s" % (auteur
, ligne
.encode("utf8")))
344 elif (any([re
.match(trig
, message
) for trig
in config
.fossil_triggers
]) and
345 not canal
in self
.quiet_channels
):
346 answer
= random
.choice(config
.fossil_answers
)
347 serv
.privmsg(canal
, "%s: %s" % (auteur
, answer
))
351 def on_action(self
, serv
, ev
):
352 action
= ev
.arguments()[0]
353 auteur
= irclib
.nm_to_n(ev
.source())
354 channel
= ev
.target()
357 except UnicodeBotError
:
358 if config
.utf8_trigger
and not channel
in self
.quiet_channels
:
359 serv
.privmsg(channel
, (u
"%s: %s" % (auteur
, random
.choice(config
.utf8_fail_answers
))).encode("utf8"))
364 def on_kick(self
, serv
, ev
):
365 auteur
= irclib
.nm_to_n(ev
.source())
366 channel
= ev
.target()
367 victime
= ev
.arguments()[0]
368 raison
= ev
.arguments()[1]
369 if victime
== self
.nick
:
370 log(self
.serveur
, "%s kické de %s par %s (raison : %s)" % (victime
, channel
, auteur
, raison
))
373 return # pas de réaction verbale au kick
374 l1
, l2
= config
.kick_answers
, config
.kick_actions
375 n1
, n2
= len(l1
), len(l2
)
376 i
= random
.randrange(n1
+n2
)
378 serv
.action(channel
, l2
[i
-n1
].format(auteur
).encode("utf8"))
380 serv
.privmsg(channel
, l1
[i
].format(auteur
).encode("utf8"))
382 def quitter(self
, chan
, leave_message
=None):
383 if leave_message
== None:
384 leave_message
= random
.choice(config
.leave_messages
)
385 self
.serv
.part(chan
, message
=leave_message
.encode("utf8"))
388 quit_message
= random
.choice(config
.quit_messages
)
389 self
.die(msg
=quit_message
.encode("utf8"))
392 return self
.serv
.get_nickname()
393 nick
= property(_getnick
)
396 if __name__
== "__main__":
398 if len(sys
.argv
) == 1:
399 print "Usage : helixbot.py <serveur> [--debug]"
401 serveur
= sys
.argv
[1]
402 if "debug" in sys
.argv
or "--debug" in sys
.argv
:
406 if "--quiet" in sys
.argv
:
407 config
.debug_stdout
= False
408 serveurs
= {"a♡":"acoeur.crans.org", "acoeur":"acoeur.crans.org", "acoeur.crans.org":"acoeur.crans.org",
409 "irc":"irc.crans.org", "crans":"irc.crans.org", "irc.crans.org":"irc.crans.org"}
411 serveur
= serveurs
[serveur
]
413 print "Server Unknown : %s" % (serveur
)
415 bot
= HelixBot(serveur
, debug
)