3 # Codé par 20-100 (commencé le 21/06/12)
5 # Un bot IRC pour kicker à tour de bras de #déprime
10 import socket
, ssl
, json
17 # Oui, j'ai recodé ma version d'irclib pour pouvoir rattrapper les SIGHUP
18 sys
.path
.insert(0, "/home/vincent/scripts/python-myirclib")
23 config_debug_stdout
=True
24 if "--quiet" in sys
.argv
:
25 config_debug_stdout
=False
27 config_irc_password
="YouMustObeyGaétan"
28 config_irc_pseudo
="Themis"
29 config_chanlist
=["#déprime"]
30 config_stay_channels
=["#déprime"]
31 config_quiet_channels
=[]
32 config_logfile_template
="themis.%s.log"
33 def get_config_logfile(serveur
):
34 serveurs
={"acoeur.crans.org":"acoeur","irc.crans.org":"crans"}
35 return config_logfile_template
%(serveurs
[serveur
])
36 config_overops
=["[20-100]","Gaetan"]
38 config_report_bugs_to
=["[20-100]"]
41 config_utf8_fail
= [u
"Ton encodage me déprime…"]
42 config_utf8_trigger
= True
43 # config "tu m'traites ?"
44 config_insultes
=[u
"conna(rd|sse)",u
"pute",u
"con(|ne)",u
"enf(oiré|lure)",
45 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",
46 u
"pétasse",u
"enculé",u
"chagasse",u
"cagole",u
"abruti",u
"ahuri",u
"analphabète",u
"andouille",
47 u
"atardé",u
"avorton",u
"bachibouzouk",u
"(balais|brosse) (de|à) chiotte(|s)",
48 u
"batard",u
"blaireau",u
"bouffon",u
"branque",u
"bouseux",u
"branleur",u
"catin",u
"chacal",
49 u
"charogne",u
"chiant(|e)",u
"chieur",u
"cochon",u
"coprophage",u
"couillon",u
"crapule",u
"crevard",
50 u
"cruche",u
"cuistre",u
"ducon",u
"décérébré",
51 u
"emmerdeur",u
"feignasse",u
"fainéant",u
"fourbe",u
"freluquet",u
"frigide",
52 u
"garce",u
"glandu",u
"gogol",u
"goujat",u
"gourdasse",u
"gredin",u
"gringalet",u
"grognasse",
53 u
"naze",u
"truie",u
"iconoclaste",
54 u
"peigne(-|)cul",u
"ignare",u
"illétré",u
"lèche(|-)cul",u
"malotru",u
"motherfucker",u
"nabot",u
"nigaud",
55 u
"nul",u
"escroc",u
"pouffiasse",u
"pourriture",u
"raclure",u
"relou",u
"sagouin",u
"putain",
57 config_insultes_answers
=[
58 u
"Oh non ! Quelle insulte ! Je crois que je ne m'en relèverai jamais…\nEnfin presque.",
59 u
"J'entends comme un vague murmure, vous disiez ?",
60 u
"Je vais prendre ça pour un compliment.",
61 u
"Vous savez, pour vous c'est peut-être une insulte, mais pour moi ce n'est qu'une suite de 0 et de 1…",
62 u
"Permettez-moi de vous retourner le compliment.",
63 u
"Votre indélicatesse vous sied à ravir.",
64 u
"Parfois, je me demande pourquoi je fais encore ce métier…",
65 u
"Le saviez-vous : l'invective ne déshonore que son auteur.",
66 u
"Le saviez-vous : vous perdez plus de temps à m'insulter qu'à vous taire.",
67 u
"Mais je ne vous permets pas ! Enfin, pas comme ça…"]
69 # config "jeu", d'ailleurs, j'ai perdu.
70 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))"
71 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)"
72 config_regexp_etre_avec_c
=u
"c'(e(s|st)|étai(t|ent))"
73 config_regexp_faire
=u
"fais"
74 config_perdu
=[u
"perd(|s|ons|ez|ent|r(e|ai|as|a|ons|ez|ont)|(|r)(ais|ait|ions|iez|aient))"
75 u
"perd(i(s|t|rent)|î(mes|tes|t))", # oui, j'ai inclus qu'il perdît
76 u
"perdiss(e(|s|nt)|i(ons|ez))",
77 u
"perdu(|s|e|es)",u
"perdant(|s|e|es)",u
"perte(|s)",
79 u
"(gagn|trouv)"+config_premier_groupe_terminaisons
,u
"gagnant(|s|e|es)",u
"gain(|s)",
81 u
"trouvant",u
"trouvaille(|s)",
83 u
"victoire(|s)",u
"vaincu(|s|e|es)",
84 u
"loose",u
"lost",u
"looser(|s)",u
"win(|ner)(|s)",
85 u
"jeu(|x)",u
"game(|s)"]
86 config_time_between_perdu_trigger
=3600*3 #temps moyen pour perdre en l'absence de trigger
87 config_time_between_perdu_trigger_delta
= 30*60 #marge autorisée autour de ^^^
88 config_time_between_perdu
=30*60 #temps pendant lequel on ne peut pas perdre
91 config_tag_triggers
=[u
"t(|a)g",u
"ta gueule",u
"la ferme",u
"ferme( |-)la",u
"tais-toi",u
"chut",u
"tu fais trop de bruit",u
"tu parles trop"]
92 config_tag_actions
=[u
"se tait",u
"se tient coi"]
94 u
"Ç'aurait été avec plaisir, mais je ne crois pas que vous puissiez vous passer de mes services.",
95 u
"Dès que cela sera utile.",
96 u
"Une autre fois, peut-être.",
97 u
"Si je me tais, qui vous rappellera combien vous me devez ?",
98 u
"J'aurais aimé accéder à votre requête, mais après mûre réflexion, j'en ai perdu l'envie.",
99 u
"Je ne ressens pas de besoin irrésistible de me taire, navré."]
102 config_tesla_triggers
=[u
"t('|u )es là \?",u
"\?",u
"plop \?",u
"plouf \?"]
103 config_tesla_answers
=[
106 config_tesla_actions
=[u
"déprime",u
"est prêt à kicker les gens heureux"]
108 # config en cas de non-insulte
109 config_compliment_triggers
=[u
"gentil",u
"cool",u
"sympa",u
"efficace"]
110 config_compliment_answers
=[
111 u
"Merci, c'est gentil de votre part. :)",
112 u
"Permettez-moi de vous retourner le compliment, sans ironie cette fois.",
113 u
"Je vous remercie.",
114 u
"C'est trop d'honneur.",
115 u
"Vous êtes bien aimable."
119 config_merci_triggers
=[u
"merci",u
"remercie",u
"thx",u
"thank(|s)"]
120 config_merci_answers
=[u
"Mais de rien.",u
"À votre service. ;)",u
"Quand vous voulez. :)",
121 u
"Tout le plaisir est pour moi."]
124 config_tamere_triggers
=[u
"ta mère"]
125 config_tamere_answers
=[u
"Laissez donc ma mère en dehors de ça !",
126 u
"Puis-je préciser que je n'ai pas de mère ? Seulement deux pères…",
127 u
"""Un certain Max chantait "♩ J'ai vu ta mère sur chat rouleeeeeeette ♫", vous êtes de sa famille ?""",
128 u
"""N'avait-on pas dit "pas les mamans" ?"""]
130 # config pour les actions désagréables
131 config_bad_action_triggers
=[u
"(frappe|cogne|tape)(| sur)",u
"(démolit|dégomme|fouette|agresse|tabasse)",
132 u
"(vomit|pisse|chie|crache) sur",u
"slap(|s)"]
133 config_bad_action_answers
=[
134 u
"Je ne peux pas dire que j'apprécie, mais je l'ai sans doute bien mérité.",
135 u
"{}: Pourquoi tant de violence en ce monde si doux ?",
136 u
"""Si je n'étais pas aussi prude, je dirais "Mais euh…", cependant, je me contenterai de hausser un sourcil.""",
137 u
"{}: J'aurais préféré que vous ne fassiez pas cela en public.",
138 u
"{}: Entre nous, cela vous gratifie-t-il ?",
139 u
"{}: Une telle relation entre nous deux n'est pas saine, revenons à quelque chose de plus conventionnel. :D",
140 u
"J'ai la désagréable impression que {} cherche comment tuer le temps en ce moment…"
142 config_bad_action_actions
=[u
"prend de la distance, par précaution…",u
"esquive",u
"est bon pour prendre une semaine de repos… virtuel !",u
"n'aime pas servir de souffre douleur, mais n'a malheureusement pas le choix", u
"s'en souviendra sans doute longtemps… de quoi parlait-on déjà ?"]
144 # config pour les actions agréables
145 config_good_action_triggers
=[u
"fait (:?des bisous|un c(?:â|a)lin|des c(?:â|a)lins) à",u
"embrasse",u
"c(?:â|a)line",u
"caresse"]
146 config_good_action_answers
=[u
":D",u
"{}: Moi aussi je vous aime. ♡",u
"Tant de délicatesse ne saurait être ignorée !",u
"Pour une fois que quelqu'un me considère à ma juste valeur…"]
147 config_good_action_actions
=[u
"ronronne",u
"aimerait exprimer avec des mots simples le bonheur que {} lui procure !",u
"éprouve une joie indescriptible",u
"apprécie que des personnes comme {} soient sur IRC, sans quoi il n'y aurait sans doute jamais personne pour tenir compte de lui"]
149 # config bonjour/bonsoir/que fais-tu encore debout à cette heure, gros sale !
150 config_bonjour_triggers
=[u
"(s|)(a|'|)lu(t|)",u
"hello",u
"pl(o|i)p",u
"pr(ou|ü)t",u
"bonjour",u
"bonsoir",u
"coucou"]
151 config_bonjour_answers
=[u
"Bien le bonjour, {}.",u
"Bonjour {}.",u
"{}: bonjour.",u
"{}: Quel beau temps aujourd'hui (arrêtez-moi si je me trompe) !",u
"Meteo: Cachan"]
152 config_bonsoir_answers
=[u
"Bonsoir {} !",u
"{}: bonsoir.",u
"Quel beau te… euh… bonsoir !",u
"{}: Je cherche désespérément une formule pour vous dire bonsoir, mais j'avoue que mon lexique est un peu… limité."]
153 config_night_answers
=[u
"{}: vous m'avez fait peur, je m'étais assoupi !", u
"Debout à une heure pareille, {} ? Que vous arrive-t-il ?",u
"Vous venez prendre la relève, {} ?"]
154 config_daytime
= [7,18]
155 config_nighttime
= [3, 6]
158 config_bonne_nuit_triggers
=[u
"bonne nuit",u
"'?nite",u
"'?nuit",u
"'?night",u
"good night",u
"'?nenuit"]
159 config_bonne_nuit_answers
=[u
"{}: thanks, make sweet dreams tonight ! ;)",u
"Bonne nuit {}.",u
"À demain {}. :)",u
"{}: si seulement j'avais le droit de dormir… enfin, bonne nuit !",u
"{}: à vous aussi !"]
161 # config quelqu'un est encore en train d'abuser de ses droits.
162 config_kick_answers
=[u
"Suis-je de trop ici ?",u
"{}: je m'excuse pour ce bruit indu qui a stimulé votre colère",u
"{} a le /kick facile, sans doute la fatigue.",u
"{}: j'ai l'impression que vous n'allez pas bien aujourd'hui, vous vous en prenez à un robot !"]
163 config_kick_actions
=[u
"sera désormais exemplaire",u
"prépare une lettre d'excuses à {}",u
"essaiera de ne plus s'attirer les foudres de {}",u
"croyait avoir tout bien fait… cruelle déception."]
165 # config on m'a demandé de mourir/partir
166 config_quit_messages
=[u
"J'ai enfin trouvé une corde et un tabouret"]
167 config_leave_messages
=config_quit_messages
168 config_quit_fail_messages
=[u
"Tu rêves là."]
169 config_leave_fail_messages
=config_quit_fail_messages
173 config_kick_channels
=config_chanlist
175 config_smileys
= [ur
':(-|o)?\)', u
'\^(_|\.)?\^', u
':-?(p|P)', u
'=(\)|D|p|P)', ur
'\\o/', ur
':-?D', ur
'x(\)|D)', u
'krkr', ur
':-?(\]|>)', ur
'(<|d|q|\(|\[)(:|=)', u
'mdr']
176 config_anglicismes
= [u
"wtf", u
"ftfy", u
"it works?", u
"fyi", u
"kill[^ ]*", u
"kick[^ ]*", u
"chan(nel)?", u
"join",
177 u
"btw", u
"lmgtfy", u
"rtfm", u
"asap", u
"afaik", u
"shit", u
"damn", u
"fuck", u
"bitch", u
"updat(e|ed|ing)", u
"lol", u
"buffer[^ ]*", u
"rofl"]
179 def log(serveur
,channel
,auteur
=None,message
=None):
180 f
=open(get_config_logfile(serveur
),"a")
181 if auteur
==message
==None:
182 # alors c'est que c'est pas un channel mais juste une ligne de log
183 chain
="%s %s"%(time
.strftime("%F %T"),channel
)
185 chain
="%s [%s:%s] %s"%(time
.strftime("%F %T"),channel
,auteur
,message
)
187 if config_debug_stdout
:
191 reg_is_smiley
= re
.compile(u
".*("+u
"|".join(config_smileys
)+u
")")
192 def is_smiley(chain
):
193 chain
=unicode(chain
,"utf8")
194 o
=re
.match(reg_is_smiley
,chain
)
197 reg_is_anglicisme
= re
.compile(u
".*(?:^| )(" + u
"|".join(config_anglicismes
) + u
")(?:$|\.| |,|;)")
198 def is_anglicisme(chain
):
199 chain
= unicode(chain
, "utf8").lower()
200 o
= re
.match(reg_is_anglicisme
, chain
)
203 # Cette liste contient la liste des raisons pour lesquelles on peut se faire kicker
204 # chaque élément contient :
205 # - la fonction de détection du kick (qui matchera une regexp et renverra l'objet de match)
206 # - la raison donnée au moment du kick ({0} étant remplacé par ce qui a matché)
207 config_kicking_list
= [
208 [is_smiley
, u
'"{0}" ? Ici on déprime.'],
209 [is_anglicisme
, u
'"{0}" ? Get out, you and your fucking anglicism !']
212 def is_something(chain
,matches
,avant
=u
".*(?:^| )",apres
=u
"(?:$|\.| |,|;).*",case_sensitive
=False,debug
=False):
214 chain
=unicode(chain
,"utf8")
216 chain
=unicode(chain
,"utf8").lower()
217 allmatches
="("+"|".join(matches
)+")"
218 reg
=(avant
+allmatches
+apres
).lower()
219 o
=re
.match(reg
,chain
)
222 def is_insult(chain
,debug
=True):
223 return is_something(chain
,config_insultes
,avant
=".*(?:^| |')")
224 def is_not_insult(chain
):
225 chain
=unicode(chain
,"utf8")
226 insult_regexp
=u
"("+u
"|".join(config_insultes
)+u
")"
227 middle_regexp
=u
"(une? (?:(?:putain|enfoiré) d(?:e |'))*|)(?:| super )(?: (?:gros|petit|grand|énorme) |)"
228 reg
=".*pas %s%s.*"%(middle_regexp
,insult_regexp
)
229 if re
.match(reg
,chain
):
233 def is_compliment(chain
,debug
=True):
234 return is_something(chain
,config_compliment_triggers
,avant
=".*(?:^| |')")
236 return is_something(chain
,config_perdu
)
238 return is_something(chain
,config_tag_triggers
)
240 return is_something(chain
,config_tesla_triggers
,avant
=u
"^",apres
=u
"$",debug
=True)
242 return is_something(chain
,config_merci_triggers
)
243 def is_tamere(chain
):
244 return is_something(chain
,config_tamere_triggers
)
245 def is_bad_action_trigger(chain
,pseudo
):
246 return is_something(chain
,config_bad_action_triggers
,avant
=u
"^",
247 apres
="(?: [a-z]*ment)? %s($|\.| |,|;).*"%(pseudo))
248 def is_good_action_trigger(chain
,pseudo
):
249 return is_something(chain
,config_good_action_triggers
,avant
=u
"^",
250 apres
="(?: [a-z]*ment)? %s($|\.| |,|;).*"%(pseudo))
251 def is_bonjour(chain
):
252 return is_something(chain
,config_bonjour_triggers
,avant
=u
"^")
253 def is_bonne_nuit(chain
):
254 return is_something(chain
,config_bonne_nuit_triggers
,avant
=u
"^")
256 return re
.match(u
"^(pan|bim|bang)( .*)?$",unicode(chain
,"utf8").lower().strip())
259 _
,_
,_
,h
,m
,s
,_
,_
,_
=time
.localtime()
260 return (conf
[0],0,0)<(h
,m
,s
)<(conf
[1],0,0)
262 return is_time(config_daytime
)
264 return is_time(config_nighttime
)
267 class UnicodeBotError(Exception):
269 def bot_unicode(chain
):
271 unicode(chain
,"utf8")
272 except UnicodeDecodeError as exc
:
273 raise UnicodeBotError
275 class Themis(ircbot
.SingleServerIRCBot
):
276 def __init__(self
,serveur
,debug
=False):
277 temporary_pseudo
=config_irc_pseudo
+str(random
.randrange(10000,100000))
278 ircbot
.SingleServerIRCBot
.__init
__(self
, [(serveur
, 6667)],
279 temporary_pseudo
,"Des[bot]e de #déprime", 10)
282 self
.overops
=config_overops
283 self
.ops
=self
.overops
+config_ops
284 self
.report_bugs_to
=config_report_bugs_to
285 self
.chanlist
=config_chanlist
286 self
.kick_channels
=config_kick_channels
287 self
.stay_channels
=config_stay_channels
288 self
.quiet_channels
=config_quiet_channels
292 def give_me_my_pseudo(self
,serv
):
293 serv
.privmsg("NickServ","RECOVER %s %s"%(config_irc_pseudo
,config_irc_password
))
294 serv
.privmsg("NickServ","RELEASE %s %s"%(config_irc_pseudo
,config_irc_password
))
296 serv
.nick(config_irc_pseudo
)
298 def give_me_my_op_status(self
,serv
,chan
):
299 serv
.privmsg("ChanServ","OP %s"%(chan))
301 def on_welcome(self
, serv
, ev
):
302 self
.serv
=serv
# ça serv ira
303 self
.give_me_my_pseudo(serv
)
304 serv
.privmsg("NickServ","identify %s"%(config_irc_password))
305 log(self
.serveur
,"Connected")
307 self
.chanlist
=["#bot"]
308 self
.kick_channels
=["#bot"]
309 for c
in self
.chanlist
:
310 log(self
.serveur
,"JOIN %s"%(c))
312 self
.give_me_my_op_status(serv
,c
)
315 def lost(self
,serv
,channel
,forced
=False):
316 if self
.last_perdu
+config_time_between_perdu
<time
.time() or forced
:
317 if not channel
in self
.quiet_channels
or forced
:
318 serv
.privmsg(channel
,"J'ai perdu !")
319 self
.last_perdu
=time
.time()
320 delay
=config_time_between_perdu_trigger
321 delta
=config_time_between_perdu_trigger_delta
322 serv
.execute_delayed(random
.randrange(delay
-delta
,delay
+delta
),self
.lost
,(serv
,channel
))
324 def pourmoi(self
, serv
, message
):
325 """renvoie (False,lemessage) ou (True, le message amputé de "pseudo: ")"""
328 if message
[:size
]==pseudo
and len(message
)>size
and message
[size
]==":":
329 return (True,message
[size
+1:].lstrip(" "))
331 return (False,message
)
333 def on_privmsg(self
, serv
, ev
):
334 message
=ev
.arguments()[0]
335 auteur
= irclib
.nm_to_n(ev
.source())
337 test
=bot_unicode(message
)
338 except UnicodeBotError
:
339 if config_utf8_trigger
:
340 serv
.privmsg(auteur
, config_utf8_fail
)
342 message
=message
.split()
343 cmd
=message
[0].lower()
346 helpdico
={"help":["""HELP <commande>
347 Affiche de l'aide sur la commande""",None,None],
348 "join": [None, """JOIN <channel>
349 Me fait rejoindre le channel""",None],
350 "leave": [None,"""LEAVE <channel>
351 Me fait quitter le channel (sauf s'il est dans ma stay_list).""",None],
352 "quiet": [None,"""QUIET <channel>
353 Me rend silencieux sur le channel.""",None],
354 "noquiet": [None,"""NOQUIET <channel>
355 Me rend la parole sur le channel.""",None],
356 "say": [None,None,"""SAY <channel> <message>
357 Me fait parler sur le channel."""],
358 "do": [None,None,"""DO <channel> <action>
359 Me fait faitre une action (/me) sur le channel."""],
360 "stay": [None,None,"""STAY <channel>
361 Ajoute le channel à ma stay_list."""],
362 "nostay": [None,None,"""NOSTAY <channel>
363 Retire le channel de ma stay_list."""],
364 "ops": [None,None,"""OPS
365 Affiche la liste des ops."""],
366 "overops": [None,None,"""OVEROPS
367 Affiche la liste des overops."""],
368 "kick": [None,None,"""KICK <channel> <pseudo> [<raison>]
369 Kicke <pseudo> du channel (Il faut bien entendu que j'y sois op)."""],
370 "die": [None,None,"""DIE
371 Me déconnecte du serveur IRC."""]
373 helpmsg_default
="Liste des commandes disponibles :\nHELP"
374 helpmsg_ops
=" JOIN LEAVE QUIET NOQUIET LOST"
375 helpmsg_overops
=" SAY DO STAY NOSTAY OPS OVEROPS KICK DIE"
376 op
,overop
=auteur
in self
.ops
, auteur
in self
.overops
378 helpmsg
=helpmsg_default
382 helpmsg
+=helpmsg_overops
384 helpmsgs
=helpdico
.get(message
[1].lower(),["Commande inconnue.",None,None])
386 if op
and helpmsgs
[1]:
388 helpmsg
+="\n"+helpmsgs
[1]
391 if overop
and helpmsgs
[2]:
393 helpmsg
+="\n"+helpmsgs
[2]
396 for ligne
in helpmsg
.split("\n"):
397 serv
.privmsg(auteur
,ligne
)
399 if auteur
in self
.ops
:
401 if message
[1] in self
.chanlist
:
402 serv
.privmsg(auteur
,"Je suis déjà sur %s"%(message
[1]))
404 serv
.join(message
[1])
405 self
.chanlist
.append(message
[1])
406 serv
.privmsg(auteur
,"Channels : "+" ".join(self
.chanlist
))
407 log(self
.serveur
,"priv",auteur
," ".join(message
))
409 serv
.privmsg(auteur
,"Channels : "+" ".join(self
.chanlist
))
413 if auteur
in self
.ops
and len(message
)>1:
414 if message
[1] in self
.chanlist
:
415 if not (message
[1] in self
.stay_channels
) or auteur
in self
.overops
:
416 self
.quitter(message
[1]," ".join(message
[2:]))
417 self
.chanlist
.remove(message
[1])
418 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
420 serv
.privmsg(auteur
,random
.choice(config_leave_fail_messages
))
421 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
423 serv
.privmsg(auteur
,"Je ne suis pas sur %s"%(message
[1]))
427 if auteur
in self
.overops
:
429 if message
[1] in self
.stay_channels
:
430 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
431 serv
.privmsg(auteur
,"Je stay déjà sur %s."%(message
[1]))
433 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
434 self
.stay_channels
.append(message
[1])
435 serv
.privmsg(auteur
,"Stay channels : "+" ".join(self
.stay_channels
))
437 serv
.privmsg(auteur
,"Stay channels : "+" ".join(self
.stay_channels
))
441 if auteur
in self
.overops
:
443 if message
[1] in self
.stay_channels
:
444 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
445 self
.stay_channels
.remove(message
[1])
446 serv
.privmsg(auteur
,"Stay channels : "+" ".join(self
.stay_channels
))
448 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
449 serv
.privmsg(auteur
,"Je ne stay pas sur %s."%(message
[1]))
454 if auteur
in self
.overops
:
455 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
460 if auteur
in self
.ops
:
462 if message
[1] in self
.quiet_channels
:
463 serv
.privmsg(auteur
,"Je me la ferme déjà sur %s"%(message
[1]))
464 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
466 self
.quiet_channels
.append(message
[1])
467 serv
.privmsg(auteur
,"Quiet channels : "+" ".join(self
.quiet_channels
))
468 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
470 serv
.privmsg(auteur
,"Quiet channels : "+" ".join(self
.quiet_channels
))
474 if auteur
in self
.ops
:
476 if message
[1] in self
.quiet_channels
:
477 self
.quiet_channels
.remove(message
[1])
478 serv
.privmsg(auteur
,"Quiet channels : "+" ".join(self
.quiet_channels
))
479 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
481 serv
.privmsg(auteur
,"Je ne me la ferme pas sur %s."%(message
[1]))
482 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
486 if auteur
in self
.overops
and len(message
)>2:
487 serv
.privmsg(message
[1]," ".join(message
[2:]))
488 log(self
.serveur
,"priv",auteur
," ".join(message
))
489 elif len(message
)<=2:
490 serv
.privmsg(auteur
,"Syntaxe : SAY <channel> <message>")
494 if auteur
in self
.overops
and len(message
)>2:
495 serv
.action(message
[1]," ".join(message
[2:]))
496 log(self
.serveur
,"priv",auteur
," ".join(message
))
497 elif len(message
)<=2:
498 serv
.privmsg(auteur
,"Syntaxe : DO <channel> <action>")
502 if auteur
in self
.overops
and len(message
)>2:
503 serv
.kick(message
[1],message
[2]," ".join(message
[3:]))
504 log(self
.serveur
,"priv",auteur
," ".join(message
))
505 elif len(message
)<=2:
506 serv
.privmsg(auteur
,"Syntaxe : KICK <channel> <pseudo> [<raison>]")
510 if auteur
in self
.overops
:
511 serv
.privmsg(auteur
," ".join(self
.ops
))
515 if auteur
in self
.overops
:
516 serv
.privmsg(auteur
," ".join(self
.overops
))
522 serv
.privmsg(auteur
,"Je n'ai pas compris. Essayez HELP…")
524 def on_pubmsg(self
, serv
, ev
):
525 auteur
= irclib
.nm_to_n(ev
.source())
527 message
= ev
.arguments()[0]
529 test
=bot_unicode(message
)
530 except UnicodeBotError
:
531 if not canal
in self
.quiet_channels
and config_utf8_trigger
:
532 serv
.privmsg(canal
, "%s: %s"%(auteur
,config_utf8_fail
))
534 pour_moi
,message
=self
.pourmoi(serv
,message
)
535 for (detect
, reason
) in config_kicking_list
:
536 matching
= detect(message
)
538 if canal
in self
.kick_channels
:
539 serv
.kick(canal
,auteur
,(reason
.format(matching
.groups()[0])).encode("utf8"))
541 if pour_moi
and message
.split()!=[]:
542 cmd
=message
.split()[0].lower()
544 args
=" ".join(message
.split()[1:])
547 if cmd
in ["meurs","die","crève","pends-toi"]:
548 if auteur
in self
.overops
:
549 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
552 serv
.privmsg(canal
,"%s: %s"%(auteur
,random
.choice(config_quit_fail_messages
)))
553 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
555 elif cmd
in ["part","leave","dégage","va-t-en"]:
556 if auteur
in self
.ops
and (not (canal
in self
.stay_channels
)
557 or auteur
in self
.overops
):
559 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
560 if canal
in self
.chanlist
:
561 self
.chanlist
.remove(canal
)
563 serv
.privmsg(canal
,"%s: %s"%(auteur
,random
.choice(config_leave_fail_messages
)))
564 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
566 elif cmd
in ["deviens","pseudo"]:
567 if auteur
in self
.ops
:
570 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
572 if cmd
in ["meur", "meurt","meurre","meurres"] and not canal
in self
.quiet_channels
:
573 serv
.privmsg(canal
,'%s: Mourir, impératif, 2ème personne du singulier : "meurs" (de rien)'%(auteur))
574 elif cmd
in ["ping"] and not canal
in self
.quiet_channels
:
575 serv
.privmsg(canal
,"%s: pong"%(auteur))
576 # if is_insult(message) and not canal in self.quiet_channels:
577 # if is_not_insult(message):
578 # answer=random.choice(config_compliment_answers)
579 # for ligne in answer.split("\n"):
580 # serv.privmsg(canal,"%s: %s"%(auteur,ligne.encode("utf8")))
582 # answer=random.choice(config_insultes_answers)
583 # for ligne in answer.split("\n"):
584 # serv.privmsg(canal,"%s: %s"%(auteur,ligne.encode("utf8")))
585 # elif is_compliment(message) and not canal in self.quiet_channels:
586 # answer=random.choice(config_compliment_answers)
587 # for ligne in answer.split("\n"):
588 # serv.privmsg(canal,"%s: %s"%(auteur,ligne.encode("utf8")))
589 if is_tesla(message
) and not canal
in self
.quiet_channels
:
590 l1
,l2
=config_tesla_answers
,config_tesla_actions
591 n1
,n2
=len(l1
),len(l2
)
592 i
=random
.randrange(n1
+n2
)
594 serv
.action(canal
,l2
[i
-n1
].encode("utf8"))
596 serv
.privmsg(canal
,"%s: %s"%(auteur
,l1
[i
].encode("utf8")))
597 if is_tag(message
) and not canal
in self
.quiet_channels
:
598 if auteur
in self
.ops
:
599 action
=random
.choice(config_tag_actions
)
600 serv
.action(canal
,action
.encode("utf8"))
601 self
.quiet_channels
.append(canal
)
603 answer
=random
.choice(config_tag_answers
)
604 for ligne
in answer
.split("\n"):
605 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
606 if is_bonjour(message
) and not canal
in self
.quiet_channels
:
608 answer
=random
.choice(config_night_answers
)
610 answer
=random
.choice(config_bonjour_answers
)
612 answer
=random
.choice(config_bonsoir_answers
)
613 serv
.privmsg(canal
,answer
.format(auteur
).encode("utf8"))
614 if is_bonne_nuit(message
) and not canal
in self
.quiet_channels
:
615 answer
=random
.choice(config_bonne_nuit_answers
)
616 serv
.privmsg(canal
,answer
.format(auteur
).encode("utf8"))
618 if not canal
in self
.quiet_channels
:
620 if re
.match((u
"^("+u
"|".join(config_bonjour_triggers
)
621 +u
")( {}| all| tout le monde|(|à) tous)(\.|( |)!|)$"
622 ).format(mypseudo
).lower(), message
.strip().lower()):
623 answer
=random
.choice(config_bonjour_answers
)
624 serv
.privmsg(canal
,answer
.format(auteur
).encode("utf8"))
626 def on_action(self
, serv
, ev
):
627 action
= ev
.arguments()[0]
628 auteur
= irclib
.nm_to_n(ev
.source())
629 channel
= ev
.target()
631 test
=bot_unicode(action
)
632 except UnicodeBotError
:
633 if not channel
in self
.quiet_channels
and config_utf8_trigger
:
634 serv
.privmsg(channel
, "%s: %s"%(auteur
,config_utf8_fail
))
638 # if is_bad_action_trigger(action,mypseudo) and not channel in self.quiet_channels:
639 # l1,l2=config_bad_action_answers,config_bad_action_actions
640 # n1,n2=len(l1),len(l2)
641 # i=random.randrange(n1+n2)
643 # serv.action(channel,l2[i-n1].format(auteur).encode("utf8"))
645 # serv.privmsg(channel,l1[i].format(auteur).format(auteur).encode("utf8"))
646 # if is_good_action_trigger(action,mypseudo) and not channel in self.quiet_channels:
647 # l1,l2=config_good_action_answers,config_good_action_actions
648 # n1,n2=len(l1),len(l2)
649 # i=random.randrange(n1+n2)
651 # serv.action(channel,l2[i-n1].format(auteur).format(auteur).encode("utf8"))
653 # serv.privmsg(channel,l1[i].format(auteur).format(auteur).encode("utf8"))
655 def on_kick(self
,serv
,ev
):
656 auteur
= irclib
.nm_to_n(ev
.source())
657 channel
= ev
.target()
658 victime
= ev
.arguments()[0]
659 raison
= ev
.arguments()[1]
660 if victime
==self
.nick
:
661 log(self
.serveur
,"%s kické de %s par %s (raison : %s)" %(victime
,channel
,auteur
,raison
))
664 username
= irclib
.nm_to_u(ev
.source()).lower()
666 print channel
, username
667 if channel
== "#déprime" and "peb" in username
or "becue" in username
:
669 serv
.kick(auteur
, "Va abuser de tes droits ailleurs !")
671 def kicker(self
, chan
, pseudo
, raison
=None):
673 raison
= config_kick_default_reason
674 self
.serv
.kick(chan
,pseudo
,raison
)
676 def quitter(self
,chan
,leave_message
=None):
677 if leave_message
==None:
678 leave_message
=random
.choice(config_leave_messages
)
679 self
.serv
.part(chan
,message
=leave_message
.encode("utf8"))
682 quit_message
=random
.choice(config_quit_messages
)
683 self
.die(msg
=quit_message
.encode("utf8"))
686 return self
.serv
.get_nickname()
687 nick
=property(_getnick
)
689 def start_as_daemon(self
, outfile
):
690 sys
.stderr
= Logger(outfile
)
694 class Logger(object):
695 """Pour écrire ailleurs que sur stdout"""
696 def __init__(self
, filename
="themis.full.log"):
697 self
.filename
= filename
699 def write(self
, message
):
700 f
= open(self
.filename
, "a")
705 if __name__
=="__main__":
708 print "Usage : themis.py <serveur> [--debug] [--no-output] [--daemon [--pidfile]] [--outfile]"
709 print " --outfile sans --no-output ni --daemon n'a aucun effet"
712 if "--daemon" in sys
.argv
:
713 thisfile
= os
.path
.realpath(__file__
)
714 thisdirectory
= thisfile
.rsplit("/", 1)[0]
715 os
.chdir(thisdirectory
)
719 if "debug" in sys
.argv
or "--debug" in sys
.argv
:
723 if "--no-output" in sys
.argv
or "--daemon" in sys
.argv
:
724 outfile
= "/var/log/bots/themis.full.log"
727 if arg
[0].strip('-') in ["out", "outfile", "logfile"]:
729 sys
.stdout
= Logger(outfile
)
730 serveurs
={"a♡":"acoeur.crans.org","acoeur":"acoeur.crans.org","acoeur.crans.org":"acoeur.crans.org",
731 "irc":"irc.crans.org","crans":"irc.crans.org","irc.crans.org":"irc.crans.org"}
733 serveur
=serveurs
[serveur
]
735 print "Server Unknown : %s"%(serveur)
737 themis
=Themis(serveur
,debug
)
739 child_pid
= os
.fork()
742 themis
.start_as_daemon(outfile
)
744 # on enregistre le pid de themis
745 pidfile
= "/var/run/bots/themis.pid"
748 if arg
[0].strip('-') in ["pidfile"]:
750 f
= open(pidfile
, "w")
751 f
.write("%s\n" % child_pid
)