]> gitweb.pimeys.fr Git - bots/basile.git/blobdiff - basile.py
Meteo : bot mort et enterré depuis longtemps
[bots/basile.git] / basile.py
index 00a1c39fc40eb9c87d95454f172662f6d5998c02..ad22ab649f74ded43ca500733377546a6cc20634 100755 (executable)
--- a/basile.py
+++ b/basile.py
@@ -17,6 +17,8 @@ import sys
 # Oui, j'ai recodé ma version d'irclib pour pouvoir rattrapper les SIGHUP
 sys.path.insert(0, "/home/vincent/scripts/python-myirclib")
 import irclib
+# On veut réagir sur la partie du whois qui dit qu'un nick est registered
+irclib.numeric_events['307'] = "whoisregnick"
 import ircbot
 
 from commands import getstatusoutput as ex
@@ -29,10 +31,11 @@ import nk
 import isit
 #: Module définissant les erreurs
 import errors
+#: Module de gestion des utilisateurs
+import users
 
 # la partie qui réfère au fichier lui-même est mieux ici
 # sinon on réfère la config et pas le fichier lui-même
-import os
 config.thisfile = os.path.realpath(__file__)
 
 def get_config_logfile(serveur):
@@ -92,10 +95,12 @@ class Basile(ircbot.SingleServerIRCBot):
         self.ops = self.overops + config.ops
         self.report_bugs_to = config.report_bugs_to
         self.chanlist = config.chanlist
-        self.identities = json.load(open(config.identities_file, "r"))
         self.stay_channels = config.stay_channels
         self.quiet_channels = config.quiet_channels
         self.last_perdu = 0
+        # On charge la base de données d'utilisateurs
+        self.users = users.UserDB()
+        self.users.load()
     
     ### Communication NK
     def new_connection_NK(self, serv, username, password, typ="bdd"):
@@ -159,10 +164,10 @@ class Basile(ircbot.SingleServerIRCBot):
         if self.last_perdu + config.time_between_perdu < time.time() or forced:
             if not channel in self.quiet_channels or forced:
                 serv.privmsg(channel, "J'ai perdu !")
-            self.last_perdu=time.time()
-            delay=config.time_between_perdu_trigger
-            delta=config.time_between_perdu_trigger_delta
-            serv.execute_delayed(random.randrange(delay-delta,delay+delta),self.lost,(serv,channel))
+            self.last_perdu = time.time()
+            delay = config.time_between_perdu_trigger
+            delta = config.time_between_perdu_trigger_delta
+            serv.execute_delayed(random.randrange(delay - delta, delay + delta), self.lost, (serv, channel))
     
     def quitter(self, chan, leave_message=None):
         """Quitter un channel avec un message customisable."""
@@ -208,6 +213,11 @@ class Basile(ircbot.SingleServerIRCBot):
             self.serv.privmsg(place, message)
         log(self.serveur, place, auteur, something + "%r" % params + ("[successful]" if success else "[failed]"))
     
+    def whois(self, pseudo, askedwhy, askedby):
+        """Demande un whois sur ``pseudo``. La réponse sera handled par une autre fonction."""
+        self.users.pending_whois[pseudo] = ["pending", askedwhy, askedby, None]
+        self.serv.whois([pseudo])
+    
     ### Surcharge des events du Bot
     def on_welcome(self, serv, ev):
         """À l'arrivée sur le serveur."""
@@ -226,6 +236,42 @@ class Basile(ircbot.SingleServerIRCBot):
             for report in self.report_bugs_to:
                 serv.privmsg(report, "Connection to NK2015 failed, invalid password ?")
 
+    def on_whoisregnick(self, serv, ev):
+        """Appelée sur une réponse à un whois au moment où ça dit "is a registered nick".
+           J'ai vérifié, "is a registered nick" ça inclu le fiat qu'il est identified correctement.
+           
+           On stocke l'information comme quoi cette personne est registered, et quand c'était."""
+        pseudo, phrase = ev.arguments()
+        if phrase == 'is a registered nick':
+            # Le whois n'est plus "pending"
+            if self.users.pending_whois.has_key(pseudo):
+                self.users.pending_whois[pseudo][0] = "registered"
+                self.users.pending_whois[pseudo][3] = time.time()
+                _, askedwhy, askedby, _ = self.users.pending_whois[pseudo]
+                if askedwhy == "cmd WHOIS":
+                    # Ce whois a été demandé par quelqu'un, on lui répond
+                    self.serv.privmsg(askedby, "%s is a registered nick" % (pseudo,))
+    
+    def on_endofwhois(self, serv, ev):
+        """Si on arrive à la fin du whois, on va voir si on n'a pas reçu "is a registered nick"
+           c'est que le pseudo n'est pas identifié. """
+        pseudo = ev.arguments()[0]
+        # On laisse le temps au bot de souffler un coup
+        serv.execute_delayed(config.whois_timeout, self.fail_whoisregnick, (pseudo,))
+
+    def fail_whoisregnick(self, pseudo):
+        """Maintenant qu'on a laissé quelques secondes au bot pour gérer les affaires courantes,
+           on considère que le pseudo n'est pas registered. """
+        # Attention, parce qu'il se pourrait qu'on n'ait pas sollicité ce whois
+        # et que donc pending_whois n'ai pas été peuplé en conséquence
+        if self.users.pending_whois.has_key(pseudo):
+            status, askedwhy, askedby, _ = self.users.pending_whois[pseudo]
+            if status == "pending":
+                # Si le status est encore pending, on n'a pas eu de réponse positive, donc elle est négative
+                self.users.pending_whois[pseudo] = "notregistered"
+                if askedwhy == "cmd WHOIS":
+                    self.serv.privmsg(askedby, "%s is NOT a registered nick" % (pseudo,))
+    
     def on_privmsg(self, serv, ev):
         """À la réception d'un message en privé."""
         if ignore_event(serv, ev):
@@ -262,23 +308,25 @@ class Basile(ircbot.SingleServerIRCBot):
                         helpmsg += "\n" + helpmsgs[2]
                     else:
                         helpmsg = helpmsgs[2]
+                if not helpmsg: # Un non-op a demandé de l'aide sur une commande dont il n'est pas censé connaître l'existence
+                    helpmsg = "Commande inacessible."
             for ligne in helpmsg.split("\n"):
                 serv.privmsg(auteur, ligne.encode("utf-8"))
         elif cmd == u"identify":
             if len(message) == 1:
-                if self.identities.has_key(auteur):
-                    serv.privmsg(auteur, "Je vous connais sous le pseudo note %s." % (
-                                     self.identities[auteur]["pseudo"].encode("utf8")))
+                if self.users.has(auteur):
+                    infos = self.users[auteur].get_infos(self.nk, serv, auteur)
+                    serv.privmsg(auteur, (u"Vous avez le compte note n°%(idbde)s, pseudo : %(pseudo)s." % infos
+                                     ).encode("utf8"))
                 else:
-                    serv.privmsg(auteur, "Je ne connais pas votre pseudo note.")
+                    serv.privmsg(auteur, "Je ne connais pas votre note.")
             elif len(message) >= 3:
                 username, password = message[1], " ".join(message[2:])
                 success, info, _ = self.new_connection_NK(serv, username, password)
                 if success:
                     log(self.serveur, "priv", auteur, " ".join(message) + "[successful]")
-                    serv.privmsg(auteur, "Identité enregistrée.")
-                    self.identities[auteur] = info
-                    json.dump(self.identities, open(config.identities_file,"w"))
+                    self.users.add(auteur, info["idbde"])
+                    serv.privmsg(auteur, "Pseudo enregistré.")
                 else:
                     log(self.serveur, "priv", auteur, " ".join(message) + "[failed]")
                     serv.privmsg(auteur, "Mot de passe invalide. (ou serveur down)")
@@ -286,26 +334,26 @@ class Basile(ircbot.SingleServerIRCBot):
                 serv.privmsg(auteur, "Syntaxe : IDENTIFY [<username> <password>]")
         elif cmd == u"drop":
             if len(message) > 1:
-                if self.identities.has_key(auteur):
+                if self.users.has(auteur):
+                    idbde = self.users[auteur].idbde
                     password = " ".join(message[1:])
-                    success, _, _ = self.new_connection_NK(serv, self.identities[auteur], password)
+                    success, _, _ = self.new_connection_NK(serv, "#%s" % idbde, password)
                     if success:
-                        del self.identities[auteur]
+                        self.users.drop(idbde)
                         log(self.serveur, "priv", auteur, " ".join(message) + "[successful]")
-                        json.dump(self.identities, open(config.identities_file, "w"))
-                        serv.privmsg(auteur, "Identité oubliée.")
+                        serv.privmsg(auteur, "Pseudo oublié.")
                     else:
                         log(self.serveur, "priv", auteur, " ".join(message) + "[failed]")
                         serv.privmsg(auteur, "Mot de passe invalide. (ou serveur down)")
                 else:
-                    serv.privmsg(auteur, "Je ne connais pas ton pseudo note.")
+                    serv.privmsg(auteur, "Je ne connais pas votre note.")
             else:
                 serv.privmsg(auteur, "Syntaxe : DROP <password>")
         elif cmd == u"join":
             if auteur in self.ops:
                 if len(message) > 1:
                     if message[1] in self.chanlist:
-                        serv.privmsg(auteur, "Je suis déjà sur %s" % (message[1]))
+                        serv.privmsg(auteur, (u"Je suis déjà sur %s" % (message[1])).encode("utf-8"))
                     else:
                         serv.join(message[1])
                         self.chanlist.append(message[1])
@@ -450,13 +498,13 @@ class Basile(ircbot.SingleServerIRCBot):
                 notunderstood = True
         elif cmd == u"solde":
             if len(message) == 1:
-                if self.identities.has_key(auteur):
-                    success, solde, pseudo = nk.get_solde(self.nk, self.identities[auteur]["idbde"], serv, auteur)
+                if self.users.has(auteur):
+                    success, solde, pseudo = nk.get_solde(self.nk, self.users[auteur].idbde, serv, auteur)
                     if success:
                         serv.privmsg(auteur, "%.2f (%s)" % (solde/100.0, pseudo.encode("utf8")))
                     log(self.serveur, "priv", auteur, " ".join(message) + ("[successful]" if success else "[failed]"))
                 else:
-                    serv.privmsg(canal, "Je ne connais pas ton pseudo note.")
+                    serv.privmsg(auteur, "Je ne connais pas votre note.")
         elif cmd == u"ops":
             if auteur in self.overops:
                 serv.privmsg(auteur, " ".join(self.ops))
@@ -467,6 +515,11 @@ class Basile(ircbot.SingleServerIRCBot):
                 serv.privmsg(auteur, " ".join(self.overops))
             else:
                 notunderstood = True
+        elif cmd == u"whois":
+            if auteur in self.ops and len(message) > 1:
+                self.whois(message[1], askedwhy="cmd WHOIS", askedby=auteur)
+            else:
+                notunderstood = True
         else:
             notunderstood = True
         if notunderstood:
@@ -548,14 +601,14 @@ class Basile(ircbot.SingleServerIRCBot):
                 serv.privmsg(canal, "%s: pong" % (auteur))
 
             elif cmd in [u"solde", u"!solde", u"!coca"] or cmd.startswith("!"):
-                if self.identities.has_key(auteur):
-                    idbde = self.identities[auteur]["idbde"]
+                if self.users.has(auteur):
+                    idbde = self.users[auteur].idbde
                     if cmd in [u"solde", u"!solde"]:
-                        success, solde, pseudo = nk.get_solde(self.nk, self.identities[auteur]["idbde"], serv, canal)
+                        success, solde, pseudo = nk.get_solde(self.nk, idbde, serv, canal)
                         if success:
                             serv.privmsg(canal, "%s: %s (%s)" % (auteur, float(solde)/100, pseudo.encode("utf8")))
                     elif cmd in [u"!coca"] or cmd.startswith("!"):
-                        success = nk.consomme(self.nk, self.identities[auteur]["idbde"], message[1:], serv, canal)
+                        success = nk.consomme(self.nk, idbde, message[1:], serv, canal)
                     log(self.serveur, canal, auteur, message + ("[successful]" if success else "[failed]"))
                 else:
                     serv.privmsg(canal, "%s: Je ne connais pas votre pseudo note." % (auteur))
@@ -666,7 +719,7 @@ class Basile(ircbot.SingleServerIRCBot):
                     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(u'^ *(.|§|!|/|/|:|)(w|b) [0-9]+$', message) and not canal in self.quiet_channels:
+            if re.match(config.buffer_fail_regexp, message, flags=re.UNICODE) and not canal in self.quiet_channels:
                 failanswers = config.buffer_fail_answers
                 answer = random.choice(failanswers)
                 serv.privmsg(canal, ("%s: %s"%(auteur,answer)).encode("utf8"))
@@ -726,7 +779,7 @@ class Basile(ircbot.SingleServerIRCBot):
         victime = ev.arguments()[0]
         raison = ev.arguments()[1]
         if victime == self.nick:
-            log(self.serveur, u"%s kické de %s par %s (raison : %s)" % (victime, channel.decode("utf-8"), auteur, raison))
+            log(self.serveur, ("%s kické de %s par %s (raison : %s)" % (victime, channel, auteur, raison)).decode("utf-8"))
             time.sleep(2)
             serv.join(channel)
             l1, l2 = config.kick_answers, config.kick_actions
@@ -754,7 +807,7 @@ class Logger(object):
         f.close()
 
 def main():
-    """Exécution principal : lecture des paramètres et lancement du bot."""
+    """Exécution principale : lecture des paramètres et lancement du bot."""
     if len(sys.argv) == 1:
         print "Usage : basile.py <serveur> [--debug] [--no-output] [--daemon [--pidfile]] [--outfile]"
         print "        --outfile sans --no-output ni --daemon n'a aucun effet"