]> gitweb.pimeys.fr Git - bots/basile.git/blobdiff - basile.py
Basile est le bienvenu sur #note-dev
[bots/basile.git] / basile.py
index ab2c7119d8ac70e4f9d4ed4dfc2b72bab88b3629..4c071ff5a5d520e2cd429566f0633b74b6a791cb 100755 (executable)
--- a/basile.py
+++ b/basile.py
@@ -1,9 +1,9 @@
 #!/usr/bin/python
 # -*- coding:utf8 -*-
 
-# Codé par 20-100 le 23/04/12
+# Codé par 20-100 (commencé le 23/04/12)
 
-# Un test de bot irc, parce que c'est cool
+# Un bot IRC qui, un jour, s'interfacera avec la Note Kfet 2015
 
 import irclib
 import ircbot
@@ -23,8 +23,8 @@ if "--quiet" in sys.argv:
 
 config_irc_password="NK2015BasileB0t"
 config_irc_pseudo="Basile"
-config_chanlist=["#bot","#flood"]
-config_stay_channels=["#bot","#flood"]
+config_chanlist=["#bot","#flood","#note-dev"]
+config_stay_channels=["#bot","#flood","#note-dev"]
 config_quiet_channels=[]
 config_note_pseudo="Basile"
 config_note_password="NK2015BasileB0tr4nd0omp4assword]6_+{#]78{"
@@ -32,10 +32,16 @@ config_logfile_template="basile.%s.log"
 def get_config_logfile(serveur):
     serveurs={"acoeur.crans.org":"acoeur","irc.crans.org":"crans"}
     return config_logfile_template%(serveurs[serveur])
-config_overops=["[20-100]","[20-100]_"]
-config_ops=["PEB","Nit"]
+config_overops=["[20-100]","[20-100]_", "PEB"]
+config_ops=["Nit"]
 config_report_bugs_to=["[20-100]"]
 
+# config "ce bot a été codé par 20-100, tu te rappelles ?"
+config_manzana = ["[20-100]", "Petite-Peste"] 
+# config "mais PEB aussi est passé par là"
+config_manzana_bis = ["PEB"]
+
+# config "tu m'traites ?"
 config_insultes=[u"conna(rd|sse)",u"pute",u"con(|ne)",u"enf(oiré|lure)",
 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",
 u"pétasse",u"enculé",u"chagasse",u"cagole",u"abruti",u"ahuri",u"analphabète",u"andouille",
@@ -49,19 +55,30 @@ u"naze",u"truie",u"iconoclaste",
 u"peigne(-|)cul",u"ignare",u"illétré",u"lèche(|-)cul",u"malotru",u"motherfucker",u"nabot",u"nigaud",
 u"nul",u"escroc",u"pouffiasse",u"pourriture",u"raclure",u"relou",u"sagouin",u"putain",
 u"péripatéticienne"]
-config_insultes_answers=[u"toi-même",
-u"Oh non ! Quelle insulte ! Je crois que je ne m'en reléverai jamaisâ\80¦\nAh si, Ã§a y est.",
-u"J'entends comme un vague murmure, tu disais ?",
+config_insultes_answers=[
+u"Oh non ! Quelle insulte ! Je crois que je ne m'en relèverai jamaisâ\80¦\nEnfin presque.",
+u"J'entends comme un vague murmure, vous disiez ?",
 u"Je vais prendre ça pour un compliment.",
-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…",
-u"Si tu allais voir sur un autre chan si j'y suis ?",
-u"Permets-moi de te retourner le compliment.",
-u"Mais je ne te permets pas !"]
-
-config_gros=[u"gros"]
+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…",
+u"Permettez-moi de vous retourner le compliment.",
+u"Votre indélicatesse vous sied à ravir.",
+u"Parfois, je me demande pourquoi je fais encore ce métier…",
+u"Le saviez-vous : l'invective ne déshonore que son auteur.",
+u"Le saviez-vous : vous perdez plus de temps à m'insulter qu'à vous taire.",
+u"Mais je ne vous permets pas ! Enfin, pas comme ça…"]
+
+# config "à peine quelques kilos octets"
+config_gros=[u"gros",u"énorme",u"lourd"]
+config_thisfile= os.path.realpath( __file__ )
+def get_filesize():
+    return ex("ls -s %s"%(config_thisfile))[1].split()[0]
 
-config_buffer_fail_answers=["haha !","You type like you drive","encore un effort ;)"]
+# config spéciale-iota
+config_buffer_fail_answers=[u"Pas de chance !",u"Révisez vos classiques !",
+u"Encore un effort, je sais que vous pouvez le faire. ;)",
+u"Where did you learn to type?"]
 
+# config "jeu", d'ailleurs, j'ai perdu.
 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))"
 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)"
 config_regexp_etre_avec_c=u"c'(e(s|st)|étai(t|ent))"
@@ -82,47 +99,87 @@ config_time_between_perdu_trigger=3600*3 #temps moyen pour perdre en l'absence d
 config_time_between_perdu_trigger_delta = 30*60 #marge autorisée autour de ^^^
 config_time_between_perdu=30*60 #temps pendant lequel on ne peut pas perdre
 
-config_tag=[u"t(|a)g",u"ta gueule",u"la ferme",u"ferme( |-)la",u"tais-toi",u"chut"]
-config_tag_actions=[u"se tait",u"ferme sa gueule",u"se la ferme",u"la ferme"]
-config_tag_answers=[u"J'me tais si j'veux !",
-u"Je t'entends pas :°",
-u"Héhé, try again",
-u"Non, j'ai pas envie",
-u"Peut-être quand toi tu la fermeras, et encore…"]
-
-config_tesla=[u"t('|u )es là \?",u"\?",u"plop \?",u"plouf \?"]
-config_tesla_answers=[u"Oui, je suis là",u"Oui ?",u"En quoi puis-je me rendre utile ?"]
-config_tesla_actions=[u"est là",u"attend des instructions",u"is alive"]
-
-config_compliment=[u"gentil",u"cool",u"sympa"]
-config_compliment_answers=[u"Merci, c'est gentil :)",u"Je te retourne le compliment",u"C'est gentil ça."]
-
-config_merci=[u"merci",u"remercie",u"thx",u"thank(|s)"]
-config_merci_answers=[u"Mais de rien.",u"À ton service ;)",u"Quand tu veux ^^",
+# config "tais-toi"
+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"]
+config_tag_actions=[u"se tait",u"se tient coi"]
+config_tag_answers=[
+u"Ç'aurait été avec plaisir, mais je ne crois pas que vous puissiez vous passer de mes services.",
+u"Dès que cela sera utile.",
+u"Une autre fois, peut-être.",
+u"Si je me tais, qui vous rappellera combien vous me devez ?",
+u"J'aurais aimé accéder à votre requête, mais après mûre réflexion, j'en ai perdu l'envie.",
+u"Je ne ressens pas de besoin irrésistible de me taire, navré."]
+
+# config ping
+config_tesla_triggers=[u"t('|u )es là \?",u"\?",u"plop \?",u"plouf \?"]
+config_tesla_answers=[
+u"Oui, je suis là.",
+u"J'écoute.",
+u"En quoi puis-je me rendre utile ?",
+u"On a besoin de moi ?"
+]
+config_tesla_actions=[u"est là",u"attend des instructions",u"est toujours disponible"]
+
+# config en cas de non-insulte
+config_compliment_triggers=[u"gentil",u"cool",u"sympa",u"efficace"]
+config_compliment_answers=[
+u"Merci, c'est gentil de votre part. :)",
+u"Permettez-moi de vous retourner le compliment, sans ironie cette fois.",
+u"Je vous remercie.",
+u"C'est trop d'honneur.",
+u"Vous êtes bien aimable."
+]
+
+# config merci
+config_merci_triggers=[u"merci",u"remercie",u"thx",u"thank(|s)"]
+config_merci_answers=[u"Mais de rien.",u"À votre service. ;)",u"Quand vous voulez. :)",
 u"Tout le plaisir est pour moi."]
 
-config_tamere=[u"ta mère"]
-config_tamere_answers=[u"Laisse ma mère en dehors de ça !",
-u"Tu veux qu'on parle de ta soœur ?",
-u"Et la tienne ?",
-u"Ce que fait ma mère c'est comme ce que tu fais avec ta bite, ça nous regarde pas…",
-u"♩ J'ai vu ta mère sur chat rouleeeeeeette ♫"
-u"On avait dit \"pas les mamans\""]
-
-config_action_trigger=[u"(frappe|cogne|tape)(| sur)",u"démolit",u"vomit sur",u"slap(|s)"]
-config_action_answers=[u"Hey ! Mais qu'est-ce que j'ai fait ?",
-u"Pourquoi moi ?",
-u"Mais euh…",
-u"Mais j'ai rien demandé moi !"]
-config_action_actions=[u"prend de la distance, par précaution…",u"part en courant"]
-
-config_bonjour=[u"(s|)(a|'|)lu(t|)",u"hello",u"plop",u"plip",u"pr(ou|ü)t",u"bonjour",u"bonsoir"]
-config_bonjour_answers=[u"Salut {}",u"Hello {} :)",u"Bonjour {}",u"Hello {}",u"{}: hello",u"{}: bonjour"]
-
-
-config_thisfile= os.path.realpath( __file__ )
-def get_filesize():
-    return ex("ls -s %s"%(config_thisfile))[1].split()[0]
+# config "ta mère" 
+config_tamere_triggers=[u"ta mère"]
+config_tamere_answers=[u"Laissez donc ma mère en dehors de ça !",
+u"Puis-je préciser que je n'ai pas de mère ? Seulement deux pères…",
+u"""Un certain Max chantait "♩ J'ai vu ta mère sur chat rouleeeeeeette ♫", vous êtes de sa famille ?""",
+u"""N'avait-on pas dit "pas les mamans" ?"""]
+
+# config pour les actions désagréables à Basile
+config_bad_action_triggers=[u"(frappe|cogne|tape)(| sur)",u"(démolit|dégomme|fouette|agresse|tabasse)",
+u"(vomit|pisse|chie|crache) sur",u"slap(|s)"]
+config_bad_action_answers=[
+u"Je ne peux pas dire que j'apprécie, mais je l'ai sans doute bien mérité.",
+u"{}: Pourquoi tant de violence en ce monde si doux ?",
+u"""Si je n'étais pas aussi prude, je dirais "Mais euh…", cependant, je me contenterai de hausser un sourcil.""",
+u"{}: J'aurais préféré que vous ne fassiez pas cela en public.",
+u"{}: Entre nous, cela vous gratifie-t-il ?",
+u"{}: Une telle relation entre nous deux n'est pas saine, revenons à quelque chose de plus conventionnel. :D",
+u"J'ai la désagréable impression que {} cherche comment tuer le temps en ce moment…"
+]
+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à ?"]
+
+# config pour les actions agréables à Basile
+config_good_action_triggers=[u"fait (:?des bisous|un c(?:â|a)lin|des c(?:â|a)lins) à",u"embrasse",u"c(?:â|a)line",u"caresse"]
+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…"]
+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"]
+
+# config bonjour/bonsoir/que fais-tu encore debout à cette heure, gros sale !
+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"]
+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"]
+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é."]
+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, {} ?"]
+config_daytime = [7,18]
+config_nighttime = [3, 6]
+
+# config dodo
+config_bonne_nuit_triggers=[u"bonne nuit",u"'?nite",u"'?nuit",u"'?night",u"good night",u"'?nenuit"]
+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 !"]
+
+# config PEB est encore en train d'abuser de ses droits.
+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 !"]
+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."]
+
+# config on m'a demandé de mourir/partir
+config_quit_messages=[u"Bien que cela me désole, je me vois dans l'obligation de vous abandonner."]
+config_leave_messages=config_quit_messages
 
 class NKError(Exception):
     def __init__(self,msg):
@@ -178,9 +235,13 @@ def connect_NK():
 
 def login_NK(username,password,typ="bdd"):
     sock=connect_NK()
+    if typ=="special": # ça c'est pour Basile lui-même
+        masque='["note"]'
+    elif typ=="bdd":
+        masque='[["all"],["all"],false]'
     try:
         # Basile a un compte special user
-        commande='login [%s,%s,"%s"]'%(json.dumps(username),json.dumps(password),typ)
+        commande='login [%s,%s,"%s",%s]'%(json.dumps(username),json.dumps(password),typ,masque)
         sock.write(commande)
         out=sock.read()
     except Exception as exc:
@@ -190,45 +251,61 @@ def login_NK(username,password,typ="bdd"):
     return json.loads(out),sock
 
 
-def is_something(chain,matches,avant=u".*(^| )",apres=u"($|\.| |,|;).*",case_sensitive=False,debug=False):
+def is_something(chain,matches,avant=u".*(?:^| )",apres=u"(?:$|\.| |,|;).*",case_sensitive=False,debug=False):
     if case_sensitive:
         chain=unicode(chain,"utf8")
     else:
         chain=unicode(chain,"utf8").lower()
     allmatches="("+"|".join(matches)+")"
     reg=(avant+allmatches+apres).lower()
-    if re.match(reg,chain):
-        return True
-    return False
+    o=re.match(reg,chain)
+    return o
 
 def is_insult(chain,debug=True):
-    return is_something(chain,config_insultes,avant=".*(^| |')")
+    return is_something(chain,config_insultes,avant=".*(?:^| |')")
 def is_not_insult(chain):
     chain=unicode(chain,"utf8")
     insult_regexp=u"("+u"|".join(config_insultes)+u")"
-    middle_regexp=u"(un(|e) ((putain|enfoiré) d(e |'))*|)(| super )( (gros|petit|grand|énorme) |)"
+    middle_regexp=u"(une? (?:(?:putain|enfoiré) d(?:e |'))*|)(?:| super )(?: (?:gros|petit|grand|énorme) |)"
     reg=".*pas %s%s.*"%(middle_regexp,insult_regexp)
     if re.match(reg,chain):
         return True
     else:
         return False
+def is_compliment(chain,debug=True):
+    return is_something(chain,config_compliment_triggers,avant=".*(?:^| |')")
 def is_perdu(chain):
     return is_something(chain,config_perdu)
 def is_tag(chain):
-    return is_something(chain,config_tag)
+    return is_something(chain,config_tag_triggers)
 def is_gros(chain):
     return is_something(chain,config_gros)
 def is_tesla(chain):
-    return is_something(chain,config_tesla,avant=u"^",apres=u"$",debug=True)
+    return is_something(chain,config_tesla_triggers,avant=u"^",apres=u"$",debug=True)
 def is_merci(chain):
-    return is_something(chain,config_merci)
+    return is_something(chain,config_merci_triggers)
 def is_tamere(chain):
-    return is_something(chain,config_tamere)
-def is_action_trigger(chain,pseudo):
-    return is_something(chain,config_action_trigger,avant=u"^",apres=" %s($|\.| |,|;).*"%(pseudo))
+    return is_something(chain,config_tamere_triggers)
+def is_bad_action_trigger(chain,pseudo):
+    return is_something(chain,config_bad_action_triggers,avant=u"^",
+                            apres="(?: [a-z]*ment)? %s($|\.| |,|;).*"%(pseudo))
+def is_good_action_trigger(chain,pseudo):
+    return is_something(chain,config_good_action_triggers,avant=u"^",
+                            apres="(?: [a-z]*ment)? %s($|\.| |,|;).*"%(pseudo))
+def is_bonjour(chain):
+    return is_something(chain,config_bonjour_triggers,avant=u"^")
+def is_bonne_nuit(chain):
+    return is_something(chain,config_bonne_nuit_triggers,avant=u"^")
 def is_pan(chain):
-    return re.match(u"^(pan|bim|bang)$",unicode(chain,"utf8").lower().strip())
+    return re.match(u"^(pan|bim|bang)( .*)?$",unicode(chain,"utf8").lower().strip())
 
+def is_time(conf):
+    _,_,_,h,m,s,_,_,_=time.localtime()
+    return (conf[0],0,0)<(h,m,s)<(conf[1],0,0)
+def is_day():
+    return is_time(config_daytime)
+def is_night():
+    return is_time(config_nighttime)
 
       
 class UnicodeBotError(Exception):
@@ -250,7 +327,6 @@ class Basile(ircbot.SingleServerIRCBot):
         self.ops=self.overops+config_ops
         self.report_bugs_to=config_report_bugs_to
         self.chanlist=config_chanlist
-        self.sockets={}
         self.identities=pickle.load(open("identities.pickle","r"))
         self.stay_channels=config_stay_channels
         self.quiet_channels=config_quiet_channels
@@ -293,11 +369,14 @@ class Basile(ircbot.SingleServerIRCBot):
         serv.nick(config_irc_pseudo)
     
     def on_welcome(self, serv, ev):
+        self.serv=serv # ça serv ira :)
         self.give_me_my_pseudo(serv)
         serv.privmsg("NickServ","identify %s"%(config_irc_password))
         log(self.serveur,"Connected")
         if self.debug:
             self.chanlist=["#bot"]
+        else:
+            serv.privmsg("ChanServ INVITE #note-dev")
         for c in self.chanlist:
             log(self.serveur,"JOIN %s"%(c))
             serv.join(c)
@@ -316,69 +395,11 @@ class Basile(ircbot.SingleServerIRCBot):
             delta=config_time_between_perdu_trigger_delta
             serv.execute_delayed(random.randrange(delay-delta,delay+delta),self.lost,(serv,channel))
     
-    def try_tamere(self,serv,channel,auteur,message):
-        """Essaye de trigger un ta mère"""
-        #pas à chaque fois quand même
-        if random.randrange(4)==0:
-            debuts=u"("+config_regexp_etre+u"|"+config_regexp_etre_avec_c+u")"
-            adjectifs={u"bon(|ne|s|nes)":u"bonne",
-                       u"baisable(|s)":u"baisable",
-                       u"faisable(|s)":u"faisable",
-                       u"pas ch(ère(|s)|er(|s))":u"pas chère",
-                       u"facile(|s)":u"facile",
-                       u"chaud(|e|s|es)":u"chaude",
-                       u"gratuit(|e|s|es)":u"gratuite",
-                       u"payant(|e|s|es)":u"payante",
-                       u"ouvert(|e|s|es)":u"ouverte",
-                       u"open":u"open",
-                       u"plein(|s|es)":u"pleine",
-                       u"bien plein(|e|s|es)":u"bien pleine"}
-            adj_reg=u"(?P<adjectif>"+u"|".join(adjectifs.keys())+u")"
-            reg=u".*(^| )"+debuts+u" "+adj_reg+u"($|,|;|\.| ).*"
-            matched=re.match(reg,message)
-            if matched:
-                # il faut repasser l'adjectif au féminin singulier
-                found=matched.groupdict()["adjectif"]
-                for adj in adjectifs.keys():
-                    if re.match(adj,found):
-                        adjectif=adjectifs[adj]
-                        break
-                serv.privmsg(channel,(u"%s: c'est ta mère qui est %s !"%(auteur,adjectif)).encode("utf8"))
-            elif random.randrange(5)==0:
-                # deuxième type de trigger, mais moins probable
-                matched=re.match(adj_reg,message)
-                if matched:
-                    found=matched.groupdict()["adjectif"]
-                    for adj in adjectifs.keys():
-                        if re.match(adj,found):
-                            adjectif=adjectifs[adj]
-                            break
-                    fille=random.choice([u"mère",u"soœur"])
-                    serv.privmsg(channel,(u"%s: et ta %s, elle est %s ?"%
-                                               (auteur,fille,adjectif)).encode("utf8"))
-                else:
-                    # troisième type de trigger
-                    cpgt=config_premier_groupe_terminaisons
-                    verbes={u"tourn"+cpgt:u"tourne",
-                            u"balad"+cpgt+u" sur le trottoir":u"se balade sur le trottoir",
-                            u"prom(e|è)n"+cpgt+" sur le trottoir":u"se promène sur le trottoir",
-                            u"_srqhbkjjn":""}
-                    vb_reg=u".*(^| )(?P<verbe>"+"|".join(verbes.keys())+")( |,|;|\.|$)"
-                    matched=re.match(vb_reg,message)
-                    if matched:
-                        found=matched.groupdict()["verbe"]
-                        for vb in verbes.keys():
-                            if re.match(vb,found):
-                                verbe=verbes[vb]
-                                break
-                        fille=random.choice([u"mère",u"soœur"])
-                        serv.privmsg(channel,(u"%s: et ta %s, elle %s ?"%
-                                               (auteur,fille,verbe)).encode("utf8"))
     def pourmoi(self, serv, message):
         """renvoie (False,lemessage) ou (True, le message amputé de "pseudo: ")"""
-        pseudo=serv.get_nickname()
+        pseudo=self.nick
         size=len(pseudo)
-        if message[:size]==pseudo and message[size]==":":
+        if message[:size]==pseudo and len(message)>size and message[size]==":":
             return (True,message[size+1:].lstrip(" "))
         else:
             return (False,message)
@@ -390,72 +411,84 @@ class Basile(ircbot.SingleServerIRCBot):
             test=bot_unicode(message)
         except UnicodeBotError:
             serv.privmsg(auteur,
-              "Euh, tu fais de la merde avec ton encodage là, j'ai failli crasher…")
+              "Si je n'avais pas été créé avec la plus grande attention, votre encodage aurait eu raison de moi…")
             return
         message=message.split()
         cmd=message[0].lower()
         notunderstood=False
-        if cmd=="connect":
-            if not len(message) in [2,3]:
-                serv.privmsg(auteur,"Syntaxe : CONNECT [<username>] <password>")
-                return
-            username=auteur
-            if len(message)>2:
-                username=(message[1])
-                password=" ".join(message[2:])
-            else:
-                password=" ".join(message[1:])
-            success,sock=self.new_connection_NK(serv,username,password)
-            if success:
-                self.sockets[username]=sock
-                serv.privmsg(auteur,"Connection successful")
-                log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
-            else:
-                serv.privmsg(auteur,"Connection failed")
-                log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
-
-        elif cmd=="help":
-            helpdico={"connect": """CONNECT [<username>] <password>
- Ouvre une connexion au serveur NoteKfet.
- Si <username> n'est pas précisé, j'utiliserais l'identité sous laquelle je te connais, ou, à défaut, ton pseudo.""", 
-"identify": """IDENTIFY <username> <password>
- Vérifie le mot de passe et me permet de savoir à l'avenir quel est ton pseudo note kfet.
- Sans paramètre, je réponds sous quel pseudo je te connais.""",
-"drop":"""DROP <password>
- Vérifie le mot de passe et me fait d'oublier ton pseudo note kfet."""}
-            helpmsg_default="""Liste des commandes :
- HELP       Affiche de l'aide sur une commande.
- CONNECT    Ouvre une connection au serveur Note Kfet.
- IDENTIFY   Me permet de savoir qui tu es sur la note kfet.
- DROP       Me fait oublier ton identité."""
-            helpmsg_ops="""
- JOIN       Faire rejoindre un chan
- LEAVE      Faire quitter un chan
- QUIET      Se taire sur un chan
- NOQUIET    Opposé de QUIET
- LOST       Perdre sur un chan"""
-            helpmsg_overops="""
- SAY        Fais envoyer un message sur un chan ou à une personne
- STAY       Ignorera les prochains LEAVE pour un chan
- NOSTAY     Opposé de STAY
- DIE        Mourir"""
+        if cmd=="help":
+            helpdico={"help":["""HELP <commande>
+ Affiche de l'aide sur la commande""",None,None],
+"identify": ["""IDENTIFY <username> <password>
+ Vérifie le mot de passe et me permet de savoir à l'avenir quel est votre pseudo note kfet.
+ Sans paramètre, je vous précise sous quel pseudo je vous connais.""",None,None],
+"drop":["""DROP <password>
+ Vérifie le mot de passe et me fait d'oublier votre pseudo note kfet.""",None,None],
+"solde": ["""SOLDE
+ Affiche votre solde, si je connais votre pseudo note kfet.""",
+ """SOLDE <pseudo>
+ Affiche le solde de la personne désignée (par son pseudo note).""",None],
+ "join": [None, """JOIN <channel>
+ Me fait rejoindre le channel""",None],
+ "leave": [None,"""LEAVE <channel>
+ Me fait quitter le channel (sauf s'il est dans ma stay_list).""",None],
+ "quiet": [None,"""QUIET <channel>
+ Me rend silencieux sur le channel.""",None],
+ "noquiet": [None,"""NOQUIET <channel>
+ Me rend la parole sur le channel.""",None],
+ "lost": [None,"""LOST <channel>
+ Me fait perdre sur le channel.""",None],
+ "reconnect": [None,"""RECONNECT
+ Établit à nouveau la connexion avec le serveur NK2015""",None],
+ "say": [None,None,"""SAY <channel> <message>
+ Me fait parler sur le channel."""],
+ "do": [None,None,"""DO <channel> <action>
+ Me fait faitre une action (/me) sur le channel."""],
+ "stay": [None,None,"""STAY <channel>
+ Ajoute le channel à ma stay_list."""],
+ "nostay": [None,None,"""NOSTAY <channel>
+ Retire le channel de ma stay_list."""],
+ "ops": [None,None,"""OPS
+ Affiche la liste des ops."""],
+ "overops": [None,None,"""OVEROPS
+ Affiche la liste des overops."""],
+ "kick": [None,None,"""KICK <channel> <pseudo> [<raison>]
+ Kicke <pseudo> du channel (Il faut bien entendu que j'y sois op)."""],
+ "die": [None,None,"""DIE
+ Me déconnecte du serveur IRC."""]
+ }
+            helpmsg_default="Liste des commandes disponibles :\nHELP IDENTIFY DROP SOLDE"
+            helpmsg_ops=" JOIN LEAVE QUIET NOQUIET LOST RECONNECT"
+            helpmsg_overops=" SAY DO STAY NOSTAY OPS OVEROPS KICK DIE"
+            op,overop=auteur in self.ops, auteur in self.overops
             if len(message)==1:
                 helpmsg=helpmsg_default
-                if auteur in self.ops:
+                if op:
                     helpmsg+=helpmsg_ops
-                if auteur in self.overops:
+                if overop:
                     helpmsg+=helpmsg_overops
             else:
-                helpmsg=helpdico.get(message[1].lower(),"Commande inconnue.")
+                helpmsgs=helpdico.get(message[1].lower(),["Commande inconnue.",None,None])
+                helpmsg=helpmsgs[0]
+                if op and helpmsgs[1]:
+                    if helpmsg:
+                        helpmsg+="\n"+helpmsgs[1]
+                    else:
+                        helpmsg=helpmsgs[1]
+                if overop and helpmsgs[2]:
+                    if helpmsg:
+                        helpmsg+="\n"+helpmsgs[2]
+                    else:
+                        helpmsg=helpmsgs[2]
             for ligne in helpmsg.split("\n"):
                 serv.privmsg(auteur,ligne)
         elif cmd=="identify":
             if len(message)==1:
                 if self.identities.has_key(auteur):
-                    serv.privmsg(auteur,"Je te connais sous le pseudo note %s."%(
+                    serv.privmsg(auteur,"Je vous connais sous le pseudo note %s."%(
                                      self.identities[auteur].encode("utf8")))
                 else:
-                    serv.privmsg(auteur,"Je ne connais pas ton pseudo note.")
+                    serv.privmsg(auteur,"Je ne connais pas votre pseudo note.")
             elif len(message)>=3:
                 username,password=message[1],unicode(" ".join(message[2:]),"utf8")
                 success,_=self.new_connection_NK(serv,username,password)
@@ -463,7 +496,7 @@ class Basile(ircbot.SingleServerIRCBot):
                     log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
                     serv.privmsg(auteur,"Identité enregistrée.")
                     self.identities[auteur]=username
-                    pickle.dump(self.identities,open("identities.pickle","w"))
+                    pickle.dump(Xself.identities,open("identities.pickle","w"))
                 else:
                     log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
                     serv.privmsg(auteur,"Mot de passe invalide. (ou serveur down)")
@@ -504,7 +537,7 @@ class Basile(ircbot.SingleServerIRCBot):
             if auteur in self.ops and len(message)>1:
                 if message[1] in self.chanlist:
                     if not (message[1] in self.stay_channels) or auteur in self.overops:
-                        serv.part(message[1])
+                        self.quitter(message[1]," ".join(message[2:]))
                         self.chanlist.remove(message[1])
                         log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
                     else:
@@ -544,7 +577,25 @@ class Basile(ircbot.SingleServerIRCBot):
         elif cmd=="die":
             if auteur in self.overops:
                 log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
-                self.die()
+                self.mourir()
+            else:
+                notunderstood=True
+        elif cmd=="reconnect":
+            if auteur in self.ops:
+                try:
+                    self.nk=self.new_connection_NK(serv,config_note_pseudo,
+                                            config_note_password,"special")[1]
+                except Exception as exc:
+                    self.nk=None
+                    log(self.serveur,"""Erreur dans on_pubmsg/"cmd in ["reconnect"]\n"""+str(exc))
+                if self.nk!=None:
+                    serv.privmsg(auteur,"%s: done"%(auteur))
+                    log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
+                else:
+                    serv.privmsg(auteur,"%s: failed"%(auteur))
+                    log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
+                    for report in self.report_bugs_to:
+                        serv.privmsg(report,"Connection to NK2015 failed, invalid password ? Server dead ?")
             else:
                 notunderstood=True
         elif cmd=="quiet":
@@ -581,6 +632,22 @@ class Basile(ircbot.SingleServerIRCBot):
                 serv.privmsg(auteur,"Syntaxe : SAY <channel> <message>")
             else:
                 notunderstood=True
+        elif cmd=="do":
+            if auteur in self.overops and len(message)>2:
+                serv.action(message[1]," ".join(message[2:]))
+                log(self.serveur,"priv",auteur," ".join(message))
+            elif len(message)<=2:
+                serv.privmsg(auteur,"Syntaxe : DO <channel> <action>")
+            else:
+                notunderstood=True
+        elif cmd=="kick":
+            if auteur in self.overops and len(message)>2:
+                serv.kick(message[1],message[2]," ".join(message[3:]))
+                log(self.serveur,"priv",auteur," ".join(message))
+            elif len(message)<=2:
+                serv.privmsg(auteur,"Syntaxe : KICK <channel> <pseudo> [<raison>]")
+            else:
+                notunderstood=True
         elif cmd=="lost":
             if auteur in self.ops and len(message)>1:
                 serv.privmsg(message[1],"J'ai perdu !")
@@ -589,10 +656,48 @@ class Basile(ircbot.SingleServerIRCBot):
                 serv.privmsg(auteur,"Syntaxe : LOST <channel>")
             else:
                 notunderstood=True
+        elif cmd=="solde":
+            if len(message)==1:
+                if self.identities.has_key(auteur):
+                    try:
+                        self.nk.write('search ["x",["pseudo"],%s]'%(json.dumps(self.identities[auteur])))
+                        ret=json.loads(self.nk.read())
+                        solde=ret["msg"][0]["solde"]
+                        pseudo=ret["msg"][0]["pseudo"]
+                    except Exception as exc:
+                        print exc
+                        serv.privmsg(auteur,"failed")
+                        log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
+                        return
+                    serv.privmsg(auteur,"%s (%s)"%(float(solde)/100,pseudo.encode("utf8")))
+                    log(self.serveur,"priv",auteur," ".join(message)+"[successful]")
+                else:
+                    serv.privmsg(canal,"Je ne connais pas ton pseudo note.")
+            elif auteur in self.ops:
+                try:
+                    self.nk.write('search ["x",["pseudo"],%s]'%(json.dumps(message[1])))
+                    ret=json.loads(self.nk.read())
+                    solde=ret["msg"][0]["solde"]
+                    pseudo=ret["msg"][0]["pseudo"]
+                except Exception as exc:
+                    serv.privmsg(auteur,"failed")
+                    log(self.serveur,"priv",auteur," ".join(message)+"[failed]")
+                    return
+                serv.privmsg(auteur,"%s (%s)"%(float(solde)/100,pseudo.encode("utf8")))
+        elif cmd=="ops":
+            if auteur in self.overops:
+                serv.privmsg(auteur," ".join(self.ops))
+            else:
+                notunderstood=True
+        elif cmd=="overops":
+            if auteur in self.overops:
+                serv.privmsg(auteur," ".join(self.overops))
+            else:
+                notunderstood=True
         else:
             notunderstood=True
         if notunderstood:
-            serv.privmsg(auteur,"Je n'ai pas compris. Essaye HELP…")
+            serv.privmsg(auteur,"Je n'ai pas compris. Essayez HELP…")
     
     def on_pubmsg(self, serv, ev):
         auteur = irclib.nm_to_n(ev.source())
@@ -601,8 +706,9 @@ class Basile(ircbot.SingleServerIRCBot):
         try:
             test=bot_unicode(message)
         except UnicodeBotError:
-            serv.privmsg(canal,
-              "%s: Euh, tu fais de la merde avec ton encodage là, j'ai failli crasher…"%(auteur))
+            if not canal in self.quiet_channels:
+                serv.privmsg(canal,
+                  "%s: Si je n'avais pas été créé avec la plus grande attention, votre encodage aurait eu raison de moi…"%(auteur))
             return
         pour_moi,message=self.pourmoi(serv,message)
         if pour_moi and message.split()!=[]:
@@ -614,24 +720,27 @@ class Basile(ircbot.SingleServerIRCBot):
             if cmd in ["meurs","die","crève"]:
                 if auteur in self.overops:
                     log(self.serveur,canal,auteur,message+"[successful]")
-                    self.die()
+                    self.mourir()
                 else:
-                    serv.privmsg(canal,"%s: crève !"%(auteur))
+                    serv.privmsg(canal,"%s: mourrez vous-même !"%(auteur))
                     log(self.serveur,canal,auteur,message+"[failed]")
     
-            elif cmd in ["part","leave","dégage"]:
+            elif cmd in ["part","leave","dégage","va-t-en","tut'tiresailleurs,c'estmesgalets"]:
                 if auteur in self.ops and (not (canal in self.stay_channels)
                                            or auteur in self.overops):
-                    serv.part(canal,message="Éjecté par %s"%(auteur))
+                    self.quitter(canal)
                     log(self.serveur,canal,auteur,message+"[successful]")
+                    if canal in self.chanlist:
+                        self.chanlist.remove(canal)
                 else:
-                    serv.privmsg(canal,"%s: Non, je reste !"%(auteur))
+                    serv.privmsg(canal,"%s: Navré, mais je me vois contraint de refuser, je ne peux pas céder aux exigences du premier venu."%(auteur))
                     log(self.serveur,canal,auteur,message+"[failed]")
             
             elif cmd in ["reconnect"]:
                 if auteur in self.ops:
                     try:
-                        self.nk=self.new_connection_NK(serv,config_note_pseudo,config_note_password)[1]
+                        self.nk=self.new_connection_NK(serv,config_note_pseudo,
+                                              config_note_password,"special")[1]
                     except Exception as exc:
                         self.nk=None
                         log(self.serveur,"""Erreur dans on_pubmsg/"cmd in ["reconnect"]\n"""+str(exc))
@@ -642,9 +751,9 @@ class Basile(ircbot.SingleServerIRCBot):
                         serv.privmsg(canal,"%s: failed"%(auteur))
                         log(self.serveur,canal,auteur,message+"[failed]")
                         for report in self.report_bugs_to:
-                            serv.privmsg(report,"Connection to NK2015 failed, invalid password ?")
+                            serv.privmsg(report,"Connection to NK2015 failed, invalid password ? Server dead ?")
                 else:
-                    serv.privmsg(canal,"%s: crève !"%(auteur))
+                    serv.privmsg(canal,"%s: Encore eût-il fallu que je sois programmé pour vous obéir !"%(auteur))
                     log(self.serveur,canal,auteur,message+"[failed]")
 
             elif cmd in ["deviens","pseudo"]:
@@ -653,8 +762,8 @@ class Basile(ircbot.SingleServerIRCBot):
                     serv.nick(become)
                     log(self.serveur,canal,auteur,message+"[successful]")
     
-            elif cmd in ["coucou"] and not canal in self.quiet_channels:
-                serv.privmsg(canal,"%s: coucou"%(auteur))
+            if cmd in ["meur", "meurt","meurre","meurres"] and not canal in self.quiet_channels:
+                serv.privmsg(canal,'%s: Mourir, impératif, 2ème personne du singulier : "meurs" (de rien)'%(auteur))
             elif cmd in ["ping"] and not canal in self.quiet_channels:
                 serv.privmsg(canal,"%s: pong"%(auteur))
 
@@ -673,14 +782,16 @@ class Basile(ircbot.SingleServerIRCBot):
                         serv.privmsg(canal,"%s: %s (%s)"%(auteur,float(solde)/100,pseudo.encode("utf8")))
                         log(self.serveur,canal,auteur,message+"[successful]")
                 else:
-                    serv.privmsg(canal,"%s: Je ne connais pas ton pseudo note."%(auteur))
+                    serv.privmsg(canal,"%s: Je ne connais pas votre pseudo note."%(auteur))
                     log(self.serveur,canal,auteur,message+"[unknown]")
             elif (re.match("!?(pain au chocolat|chocolatine)",message.lower())
                  and not canal in self.quiet_channels):
                 serv.action(canal,"sert un pain au chocolat à %s"%(auteur))
             elif re.match("!?manzana",message.lower()) and not canal in self.quiet_channels:
-                if auteur=="[20-100]":
+                if auteur in config_manzana:
                     serv.action(canal,"sert une bouteille de manzana à %s"%(auteur))
+                elif auteur in config_manzana_bis:
+                    serv.action(canal,"sert un grand verre de jus de pomme à %s : tout le monde sait qu'il ne boit pas."%(auteur))
                 else:
                     serv.action(canal,"sert un verre de manzana à %s"%(auteur))
             if is_insult(message) and not canal in self.quiet_channels:
@@ -692,16 +803,21 @@ class Basile(ircbot.SingleServerIRCBot):
                     answer=random.choice(config_insultes_answers)
                     for ligne in answer.split("\n"):
                         serv.privmsg(canal,"%s: %s"%(auteur,ligne.encode("utf8")))
-            if is_gros(message) and not canal in self.quiet_channels:
+            elif is_compliment(message) and not canal in self.quiet_channels:
+                answer=random.choice(config_compliment_answers)
+                for ligne in answer.split("\n"):
+                    serv.privmsg(canal,"%s: %s"%(auteur,ligne.encode("utf8")))
+            gros_match=is_gros(message)
+            if gros_match and not canal in self.quiet_channels:
                 taille=get_filesize()
-                answer=u"Mais non, je ne suis pas gros, %sKo tout au plus…"%(taille)
+                answer=u"Mais non, je ne suis pas %s, %sKo tout au plus…"%(gros_match.groups()[0],taille)
                 serv.privmsg(canal,"%s: %s"%(auteur,answer.encode("utf8")))
             if is_tesla(message) and not canal in self.quiet_channels:
                 l1,l2=config_tesla_answers,config_tesla_actions
                 n1,n2=len(l1),len(l2)
                 i=random.randrange(n1+n2)
                 if i>=n1:
-                    serv.action(canal,l2[i-n1])
+                    serv.action(canal,l2[i-n1].encode("utf8"))
                 else:
                     serv.privmsg(canal,"%s: %s"%(auteur,l1[i].encode("utf8")))
             if is_tamere(message) and not canal in self.quiet_channels:
@@ -721,56 +837,67 @@ class Basile(ircbot.SingleServerIRCBot):
                 answer=random.choice(config_merci_answers)
                 for ligne in answer.split("\n"):
                     serv.privmsg(canal,"%s: %s"%(auteur,ligne.encode("utf8")))
-            out=re.match(u"^([A-Z[]|\\|[0-9]+|(¹|²|³|⁴|⁵|⁶|⁷|⁸|⁹|⁰)+)(?:| \?| !)$",
+            out=re.match(ur"^([A-Z[]|\\|[0-9]+|(¹|²|³|⁴|⁵|⁶|⁷|⁸|⁹|⁰)+)(?:| \?| !)$",
                          unicode(message.upper(),"utf8"))
+            if re.match("ma bite dans ton oreille",message) and not canal in self.quiet_channels:
+                serv.privmsg(canal,"%s: Seul un olasd peut imiter un olasd dans un de ses grands jours !"%(auteur))
             if out and not canal in self.quiet_channels:
                 out=out.groups()[0]
                 try:
                     out=int(out)
                     serv.privmsg(canal,"%s: %s !"%(auteur,out+1))
-                    if out+1>1000 and random.randrange(4)==0:
-                        serv.privmsg(canal,"%s: Tu sais, je peux continuer longtemps comme ça…"%(auteur))
                     if out==2147483647:
-                        serv.privmsg(canal,"%s: Tu croyais m'avoir sur le maxint ? J'suis en python mon vieux, 'va falloir trouver mieux…"%(auteur))
-                    return
+                        serv.privmsg(canal,"%s: Ciel, un maxint ! Heureusement que je suis en python…"%(auteur))
+                        return
+                    if out+1>1000 and random.randrange(4)==0:
+                        serv.privmsg(canal,"%s: Vous savez, moi et les chiffres…"%(auteur))
+                        return
                 except Exception as exc:
                     pass
                 if re.match("[A-Y]",out):
                     alphabet="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                     serv.privmsg(canal,"%s: %s !"%(auteur,alphabet[alphabet.index(out)+1]))
                 elif out=="Z":
-                    serv.privmsg(canal,"%s: pfff, j'ai l'air malin maintenant… [ ?"%(auteur))
+                    serv.privmsg(canal,"%s: Je ne vous remercie pas, j'ai l'air idiot ainsi… [ ?"%(auteur))
                 elif out in "[\\":
-                    serv.privmsg(canal,"%s: nan mais il faut qu'on arrête, ça va finir par poser des problèmes…"%(auteur))
-                elif re.match(r"(¹|²|³|⁴|⁵|⁶|⁷|⁸|⁹|⁰)+",out):
+                    serv.privmsg(canal,"%s: Nous devrions nous en tenir là, ça va finir par poser des problèmes…"%(auteur))
+                elif re.match(ur"(¹|²|³|⁴|⁵|⁶|⁷|⁸|⁹|⁰)+",out):
                     def translate(mess):
                         return "".join([{u"⁰¹²³⁴⁵⁶⁷⁸⁹0123456789"[i]:u"0123456789⁰¹²³⁴⁵⁶⁷⁸⁹"[i]
                                         for i in range(20)}[j]
                                        for j in mess])
                     out=int(translate(out))
                     serv.privmsg(canal,"%s: %s !"%(auteur,translate(str(out+1)).encode("utf8")))
-            if (not canal in self.quiet_channels
-                and re.match((u"^("+"|".join(config_bonjour)+").*").lower(),message.lower()) ):
-                answer=random.choice(config_bonjour_answers)
+            if is_bonjour(message) and not canal in self.quiet_channels:
+                if is_night():
+                    answer=random.choice(config_night_answers)
+                elif is_day():
+                    answer=random.choice(config_bonjour_answers)
+                else:
+                    answer=random.choice(config_bonsoir_answers)
+                serv.privmsg(canal,answer.format(auteur).encode("utf8"))
+            if is_bonne_nuit(message) and not canal in self.quiet_channels:
+                answer=random.choice(config_bonne_nuit_answers)
                 serv.privmsg(canal,answer.format(auteur).encode("utf8"))
-            if is_pan(message):
-                serv.privmsg(canal,"%s: c'est pas sur moi qu'il faut tirer !"%(auteur))
+            if is_pan(message) and not canal in self.quiet_channels:
+                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))
         else:
             if message in ["!pain au chocolat","!chocolatine"] and not canal in self.quiet_channels:
                 serv.action(canal,"sert un pain au chocolat à %s"%(auteur))
             if message in ["!manzana"] and not canal in self.quiet_channels:
-                if auteur=="[20-100]":
+                if auteur in config_manzana:
                     serv.action(canal,"sert une bouteille de manzana à %s"%(auteur))
+                elif auteur in config_manzana_bis:
+                    serv.action(canal,"sert un grand verre de jus de pomme à %s : tout le monde sait qu'il ne boit pas."%(auteur))
                 else:
                     serv.action(canal,"sert un verre de manzana à %s"%(auteur))
-            if re.match('^(.|§|:|)(w|b) [0-9]+$',message) and not canal in self.quiet_channels:
+            if re.match(u'^ *(.|§|!|/|/|:|)(w|b) [0-9]+$',message.decode("utf8")) and not canal in self.quiet_channels:
                 failanswers=config_buffer_fail_answers
                 answer=random.choice(failanswers)
-                serv.privmsg(canal,"%s: %s"%(auteur,answer))
+                serv.privmsg(canal,("%s: %s"%(auteur,answer)).encode("utf8"))
             if not canal in self.quiet_channels:
-                self.try_tamere(serv,canal,auteur,message)
-                mypseudo=serv.get_nickname()
-                if re.match((u"^("+u"|".join(config_bonjour)
+                mypseudo=self.nick
+                if re.match((u"^("+u"|".join(config_bonjour_triggers)
                                   +u")( {}| all| tout le monde|(|à) tous)(\.|( |)!|)$"
                              ).format(mypseudo).lower(), message.strip().lower()):
                     answer=random.choice(config_bonjour_answers)
@@ -789,15 +916,61 @@ class Basile(ircbot.SingleServerIRCBot):
         action = ev.arguments()[0]
         auteur = irclib.nm_to_n(ev.source())
         channel = ev.target()
-        mypseudo=serv.get_nickname()
-        if is_action_trigger(action,mypseudo):
-            l1,l2=config_action_answers,config_action_actions
+        try:
+            test=bot_unicode(action)
+        except UnicodeBotError:
+            serv.privmsg(channel, 
+                  "%s: Si je n'avais pas été créé avec la plus grande attention, votre encodage m'aurait déjà tué…"%(auteur))
+            return
+        mypseudo=self.nick
+        
+        if is_bad_action_trigger(action,mypseudo) and not channel in self.quiet_channels:
+            l1,l2=config_bad_action_answers,config_bad_action_actions
+            n1,n2=len(l1),len(l2)
+            i=random.randrange(n1+n2)
+            if i>=n1:
+                serv.action(channel,l2[i-n1].format(auteur).encode("utf8"))
+            else:
+                serv.privmsg(channel,l1[i].format(auteur).format(auteur).encode("utf8"))
+        if is_good_action_trigger(action,mypseudo) and not channel in self.quiet_channels:
+            l1,l2=config_good_action_answers,config_good_action_actions
             n1,n2=len(l1),len(l2)
             i=random.randrange(n1+n2)
             if i>=n1:
-                serv.action(channel,l2[i-n1])
+                serv.action(channel,l2[i-n1].format(auteur).format(auteur).encode("utf8"))
             else:
-                serv.privmsg(channel,"%s: %s"%(auteur,l1[i].encode("utf8")))
+                serv.privmsg(channel,l1[i].format(auteur).format(auteur).encode("utf8"))
+    
+    def on_kick(self,serv,ev):
+        auteur = irclib.nm_to_n(ev.source())
+        channel = ev.target()
+        victime = ev.arguments()[0]
+        raison = ev.arguments()[1]
+        if victime==self.nick:
+            log(self.serveur,"%s kické de %s par %s (raison : %s)" %(victime,channel,auteur,raison))
+            time.sleep(2)
+            serv.join(channel)
+            l1,l2=config_kick_answers,config_kick_actions
+            n1,n2=len(l1),len(l2)
+            i=random.randrange(n1+n2)
+            if i>=n1:
+                serv.action(channel,l2[i-n1].format(auteur).encode("utf8"))
+            else:
+                serv.privmsg(channel,l1[i].format(auteur).encode("utf8"))
+    
+    def quitter(self,chan,leave_message=None):
+        if leave_message==None:
+            leave_message=random.choice(config_leave_messages)
+        self.serv.part(chan,message=leave_message.encode("utf8"))
+    
+    def mourir(self):
+        quit_message=random.choice(config_quit_messages)
+        self.die(msg=quit_message.encode("utf8"))
+    
+    def _getnick(self):
+        return self.serv.get_nickname()
+    nick=property(_getnick)
+
 
 if __name__=="__main__":
     import sys