From 50047526601dc3f2e89eb946920a4a3cc96b01fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=A9munaire?= Date: Mon, 14 May 2012 17:50:11 +0200 Subject: [PATCH] Lot of fixes Use a partner to transform nick to login_x Add questions support into qd.py --- birthday.py | 2 +- events.py | 95 ++++++++++++++++++++++++-- message.py | 43 +++++++++++- nemubot.py | 9 ++- nemuspeak.py | 14 ++-- qd.py | 112 ++++++++++++++++++++++++++---- server.py | 18 +++++ soutenance.py | 34 ++++++++++ watchWebsite.py | 30 ++++---- whereis.py | 177 +++++++++++++++++++++++++++++++++++++++++------- 10 files changed, 462 insertions(+), 72 deletions(-) diff --git a/birthday.py b/birthday.py index 1a2d79d..22462d9 100644 --- a/birthday.py +++ b/birthday.py @@ -134,7 +134,7 @@ def parseanswer(msg): def parseask(msg): msgl = msg.content.lower () - if re.match("^.*(date de naissance|birthday|geburtstag|née?|nee? le|born on).*$", msgl) is not None: + if re.match("^.*(date de naissance|birthday|geburtstag|née? |nee? le|born on).*$", msgl) is not None: try: extDate = msg.extractDate () if extDate is None: diff --git a/events.py b/events.py index 7ae76b7..2219cf2 100644 --- a/events.py +++ b/events.py @@ -6,6 +6,7 @@ from datetime import timedelta from datetime import datetime from datetime import date import time +import threading from xml.dom.minidom import parse from xml.dom.minidom import parseString from xml.dom.minidom import getDOMImplementation @@ -13,6 +14,46 @@ from xml.dom.minidom import getDOMImplementation filename = "" EVENTS = {} STREND = {} +threadManager = None +newStrendEvt = threading.Event() + +class Manager(threading.Thread): + def __init__(self, servers): + self.servers = servers + self.stop = False + threading.Thread.__init__(self) + + def run(self): + global STREND + while not self.stop: + newStrendEvt.clear() + closer = None + #Gets the closer event + for evt in STREND.keys(): + if ((closer is None or closer.end is None) or (STREND[evt].end is not None and STREND[evt].end < closer.end)) and STREND[evt].end is not None and STREND[evt].end > datetime.now(): + closer = STREND[evt] + if closer is not None and closer.end is not None: + #print ("Closer: %s à %s"%(closer.name, closer.end)) + timeleft = (closer.end - datetime.now()).seconds + timer = threading.Timer(timeleft, closer.alertEnd, (self.servers,)) + timer.start() + #print ("Start timer (%ds)"%timeleft) + + newStrendEvt.wait() + + if closer is not None and closer.end is not None and closer.end > datetime.now(): + timer.cancel() + +def launch (servers): + global threadManager + stop() + threadManager = Manager(servers) + threadManager.start() + +def stop (): + if threadManager is not None: + threadManager.stop = True + newStrendEvt.set() class Strend: def __init__(self, item): @@ -20,9 +61,28 @@ class Strend: self.name = item.getAttribute("name") self.start = datetime.fromtimestamp (time.mktime (time.strptime (item.getAttribute("start")[:19], "%Y-%m-%d %H:%M:%S"))) self.proprio = item.getAttribute("proprio") + self.server = item.getAttribute("server") + self.channel = item.getAttribute("channel") + if item.getAttribute("end") is not None and item.getAttribute("end") != "": + try: + self.end = datetime.fromtimestamp (time.mktime (time.strptime (item.getAttribute("end")[:19], "%Y-%m-%d %H:%M:%S"))) + except: + self.end = None + else: + self.end = None else: self.start = datetime.now() + self.end = None + def alertEnd(self, SRVS): + for server in SRVS.keys(): + if server == self.server: + if self.channel == SRVS[server].nick: + SRVS[server].send_msg_usr(self.proprio, "%s: %s arrivé à échéance."%(self.proprio, self.name)) + else: + SRVS[server].send_msg(self.channel, "%s: %s arrivé à échéance."%(self.proprio, self.name)) + del STREND[self.name] + newStrendEvt.set() def xmlparse(node): """Parse the given node and add events to the global list.""" @@ -84,7 +144,10 @@ def save_module(): top = newdoc.documentElement for name in STREND.keys(): - item = parseString ('' % (name, STREND[name].start, STREND[name].proprio)).documentElement + iend = "" + if STREND[name].end is not None: + iend = ' end="%s"'%STREND[name].end + item = parseString ('' % (name, STREND[name].start, STREND[name].proprio, STREND[name].server, STREND[name].channel, iend)).documentElement top.appendChild(item); for name in EVENTS.keys(): @@ -112,7 +175,7 @@ def help_tiny (): return "events manager" def help_full (): - return "This module store a lot of events: ny, we, vacs, " + (", ".join(EVENTS.keys())) + return "This module store a lot of events: ny, we, vacs, " + (", ".join(EVENTS.keys())) + "\n!eventslist: gets list of timer\n!start /something/: launch a timer" def parseanswer(msg): @@ -140,18 +203,38 @@ def parseanswer(msg): elif msg.cmd[0] == "start" and len(msg.cmd) > 1: if msg.cmd[1] not in STREND: STREND[msg.cmd[1]] = Strend(None) + STREND[msg.cmd[1]].server = msg.srv.id + STREND[msg.cmd[1]].channel = msg.channel STREND[msg.cmd[1]].proprio = msg.sender STREND[msg.cmd[1]].name = msg.cmd[1] - - msg.send_snd ("%s commencé le %s"% (msg.cmd[1], datetime.now())) + if len(msg.cmd) > 2: + result = re.match("([0-9]+)([smhdjSMHDJ])?", msg.cmd[2]) + if result is not None: + try: + if result.group(2) is not None and (result.group(2) == "m" or result.group(2) == "M"): + STREND[msg.cmd[1]].end = datetime.now() + timedelta(minutes=int(result.group(1))) + elif result.group(2) is not None and (result.group(2) == "h" or result.group(2) == "H"): + STREND[msg.cmd[1]].end = datetime.now() + timedelta(hours=int(result.group(1))) + elif result.group(2) is not None and (result.group(2) == "d" or result.group(2) == "D" or result.group(2) == "j" or result.group(2) == "J"): + STREND[msg.cmd[1]].end = datetime.now() + timedelta(days=int(result.group(1))) + else: + STREND[msg.cmd[1]].end = datetime.now() + timedelta(seconds=int(result.group(1))) + newStrendEvt.set() + msg.send_snd ("%s commencé le %s et se terminera le %s."% (msg.cmd[1], datetime.now(), STREND[msg.cmd[1]].end)) + except: + msg.send_snd ("Impossible de définir la fin de %s."% (msg.cmd[1])) + msg.send_snd ("%s commencé le %s."% (msg.cmd[1], datetime.now())) + else: + msg.send_snd ("%s commencé le %s"% (msg.cmd[1], datetime.now())) else: msg.send_snd ("%s existe déjà."% (msg.cmd[1])) - elif msg.cmd[0] == "end" and len(msg.cmd) > 1: + elif (msg.cmd[0] == "end" or msg.cmd[0] == "forceend") and len(msg.cmd) > 1: if msg.cmd[1] in STREND: msg.send_chn ("%s a duré %s." % (msg.cmd[1], msg.just_countdown(datetime.now () - STREND[msg.cmd[1]].start))) - if STREND[msg.cmd[1]].proprio == msg.sender: + if STREND[msg.cmd[1]].proprio == msg.sender or (msg.cmd[0] == "forceend" and msg.sender == msg.srv.owner): del STREND[msg.cmd[1]] + newStrendEvt.set() else: msg.send_snd ("Vous ne pouvez pas terminer le compteur %s, créé par %s."% (msg.cmd[1], STREND[msg.cmd[1]].proprio)) else: diff --git a/message.py b/message.py index e1d3a1f..4b9f209 100644 --- a/message.py +++ b/message.py @@ -95,8 +95,23 @@ class Message: if line.find(' PRIVMSG ') != -1: #Call a parsing function complete = line[1:].split(':',1) #Parse the message into useful data info = complete[0].split(' ') - self.cmd = "PRIVMSG" + if len(complete) < 2 or len (info) < 3: + last = "" + info = list() + for lettre in line: + if len(info) > 2: + complete[1] += lettre + elif lettre == ":" or lettre == " ": + if last != "": + info.append(last) + if len(info) > 2: + complete = list() + complete.append(" ".join(info)) + complete.append("") + else: + last += lettre + self.sender = (info[0].split('!'))[0] self.realname = (info[0].split('!'))[1] self.channel = info[2] @@ -149,6 +164,19 @@ class Message: else: self.content = "" + elif line.find(' QUIT ') != -1: + complete = line[1:].split(':',1) #Parse the message into useful data + info = complete[0].split(' ') + + self.cmd = "QUIT" + self.sender = (info[0].split('!'))[0] + self.realname = (info[0].split('!'))[1] + self.channel = info[2] + if len (complete) > 1: + self.content = complete[1] + else: + self.content = "" + elif line.find(' MODE ') != -1: complete = line[1:].split(' ') if len(complete) >= 5: @@ -242,6 +270,10 @@ class Message: now = datetime.now() self.send_chn ("%s: j'envoie ce message à %s:%d:%d."%(self.sender, now.hour, now.minute, now.second)) + elif re.match(".*qui est ([a-zA-Z0-9_-]+)", messagel) is not None: + result = re.match(".*qui est ([a-zA-Z0-9_-]+).*", self.content) + self.send_chn ("!whois %s"%(result.group(1))) + elif re.match(".*di[st] (a|à) ([a-zA-Z0-9_]+) (.+)$", messagel) is not None: result = re.match(".*di[st] (a|à) ([a-zA-Z0-9_]+) (qu(e |'))?(.+)$", self.content) self.send_chn ("%s: %s"%(result.group(2), result.group(5))) @@ -265,10 +297,11 @@ class Message: #Owner commands elif self.content[0] == '`' and self.sender == self.srv.owner: self.cmd = self.content[1:].split(' ') - if self.cmd[0] == "reload": + if self.cmd[0] == "reload" or self.cmd[0] == "reload_nosave": if len(self.cmd) > 1: if self.cmd[1] in mods: - mods[self.cmd[1]].save_module () + if self.cmd[0] == "reload": + mods[self.cmd[1]].save_module () imp.reload(mods[self.cmd[1]]) mods[self.cmd[1]].load_module (self.srv.datas_dir) self.send_snd ("Module %s rechargé avec succès."%self.cmd[1]) @@ -312,8 +345,12 @@ class Message: self.send_snd(" - !help %s: %s" % (im, mods[im].help_tiny ())) for im in mods.keys(): + if im == "alias": + continue if mods[im].parseanswer(self): return + if mods["alias"].parseanswer(self): + return else: for im in mods.keys(): diff --git a/nemubot.py b/nemubot.py index 346aa26..fb7d8bf 100755 --- a/nemubot.py +++ b/nemubot.py @@ -11,7 +11,7 @@ from datetime import timedelta from xml.dom.minidom import parse imports = ["birthday", "qd", "events", "youtube", "watchWebsite", "soutenance", "whereis", "alias"] -imports_launch = ["watchWebsite"] +imports_launch = ["watchWebsite", "events"] mods = {} import server, message @@ -26,6 +26,9 @@ def onSignal(signum, frame): for imp in mods.keys(): mods[imp].save_module () + for imp in imports_launch: + mods[imp].stop () + #Save banlist before quit message.save_module () @@ -39,7 +42,7 @@ else: dom = parse(sys.argv[1]) config = dom.getElementsByTagName('config')[0] -servers = list () +servers = dict () message.load_module (basedir + "/datas/") @@ -51,7 +54,7 @@ for imp in imports: for serveur in config.getElementsByTagName('server'): srv = server.Server(serveur, config.getAttribute('nick'), config.getAttribute('owner'), config.getAttribute('realname')) srv.launch(mods, basedir + "/datas/") - servers.append (srv) + servers[srv.id] = srv for imp in imports_launch: mod = __import__ (imp) diff --git a/nemuspeak.py b/nemuspeak.py index 1fb1f4f..dd0083f 100755 --- a/nemuspeak.py +++ b/nemuspeak.py @@ -176,7 +176,11 @@ class Server: readbuffer = temp.pop( ) for line in temp: - msg = message.Message(self, line) + try: + msg = message.Message(self, line) + except: + continue + if msg.cmd == "PING": self.s.send(("PONG %s\r\n" % msg.content).encode ()) elif msg.cmd == "PRIVMSG" and (self.authorize(msg) or msg.content[0] == '`'): @@ -227,14 +231,16 @@ for server in config.getElementsByTagName('server'): srv.launch() def sighup_h(signum, frame): - print ("Signal reçu...") + global talkEC, stopSpk + sys.stdout.write ("Signal reçu ... ") if os.path.exists("/tmp/isPresent"): - thread.start_new_thread(speak, (0,)) + _thread.start_new_thread(speak, (0,)) + print ("Morning!") else: + print ("Sleeping!") if talkEC == 0: talkEC = 1 stopSpk = 1 - signal.signal(signal.SIGHUP, sighup_h) print ("Nemuspeak ready, waiting for new messages...") diff --git a/qd.py b/qd.py index 7a9602b..412111d 100644 --- a/qd.py +++ b/qd.py @@ -2,7 +2,9 @@ import re import time +import random import sys +import threading from datetime import timedelta from datetime import datetime from datetime import date @@ -13,6 +15,7 @@ from xml.dom.minidom import getDOMImplementation filename = "" channels = "#nemutest #42sh #epitagueule" MANCHE = None +QUESTIONS = list() SCORES = dict () temps = dict () @@ -70,10 +73,14 @@ class Score: def playTwt(self): if self.canPlay(): self.twt += 1 + def playSuite(self): + self.canPlay() + self.twt += 1 + self.great += 1 def playPi(self): if self.canPlay(): self.pi += 1 - def playNoutfound(self): + def playNotfound(self): if self.canPlay(): self.notfound += 1 def playTen(self): @@ -88,6 +95,10 @@ class Score: def playBad(self): if self.canPlay(): self.bad += 1 + def playTriche(self): + self.bad += 5 + def oupsTriche(self): + self.bad -= 5 def toTuple(self): return (self.ftt, self.twt, self.pi, self.notfound, self.tententen, self.leet, self.great, self.bad) @@ -118,6 +129,9 @@ def xmlparse(node): SCORES[item.getAttribute("name")] = Score () SCORES[item.getAttribute("name")].parse(item) + for item in node.getElementsByTagName("question"): + QUESTIONS.append((item.getAttribute("question"),item.getAttribute("regexp"),item.getAttribute("great"))) + manche = node.getElementsByTagName("manche")[0] MANCHE = (int(manche.getAttribute("number")), manche.getAttribute("winner"), @@ -136,7 +150,7 @@ def load_module(datas_path): sys.stdout.write ("Loading 42scores ... ") dom = parse(filename) xmlparse (dom.documentElement) - print ("done (%d loaded, currently in round %d)" % (len(SCORES), -42)) + print ("done (%d loaded, %d questions, currently in round %d)" % (len(SCORES), len(QUESTIONS), -42)) def save_module(): """Save the scores""" @@ -154,6 +168,9 @@ def save_module(): top.appendChild(parseString ('' % MANCHE).documentElement) + for q in QUESTIONS: + top.appendChild(parseString ('' % q).documentElement) + with open(filename, "w") as f: newdoc.writexml (f) print ("done") @@ -174,11 +191,14 @@ def rev (tupl): def parseanswer (msg): if msg.cmd[0] == "42" or msg.cmd[0] == "score" or msg.cmd[0] == "scores": global SCORES, MANCHE - if len(msg.cmd) > 3 and msg.is_owner and (msg.cmd[1] == "merge"): - if msg.cmd[2] in SCORES and msg.cmd[3] in SCORES: - SCORES[msg.cmd[2]].merge (SCORES[msg.cmd[3]]) - del SCORES[msg.cmd[3]] - msg.send_chn ("%s a été correctement fusionné avec %s."%(msg.cmd[3], msg.cmd[2])) + if len(msg.cmd) > 2 and msg.is_owner and ((msg.cmd[1] == "merge" and len(msg.cmd) > 3) or msg.cmd[1] == "oupstriche"): + if msg.cmd[2] in SCORES and (len(msg.cmd) <= 3 or msg.cmd[3] in SCORES): + if msg.cmd[1] == "merge": + SCORES[msg.cmd[2]].merge (SCORES[msg.cmd[3]]) + del SCORES[msg.cmd[3]] + msg.send_chn ("%s a été correctement fusionné avec %s."%(msg.cmd[3], msg.cmd[2])) + elif msg.cmd[1] == "oupstriche": + SCORES[msg.cmd[2]].oupsTriche() else: if msg.cmd[2] not in SCORES: msg.send_chn ("%s n'est pas un joueur connu."%msg.cmd[2]) @@ -202,9 +222,9 @@ def parseanswer (msg): score = scr.score() if score != 0: if phrase == "": - phrase = " *%s: %d*,"%(nom, score) + phrase = " *%s.%s: %d*,"%(nom[0:1], nom[1:len(nom)], score) else: - phrase += " %s: %d,"%(nom, score) + phrase += " %s.%s: %d,"%(nom[0:1], nom[1:len(nom)], score) msg.send_chn ("Scores :%s" % (phrase[0:len(phrase)-1])) return True @@ -231,6 +251,7 @@ def win(msg): SCORES = dict() # SCORES[maxi_name] = (-10, 0, -4, 0, 0, -2, 0) # SCORES[maxi_name] = (0, 0, 0, 0, 0, 0, 0) + SCORES[who] = Score() SCORES[who].newWinner() if who != maxi_name: @@ -245,6 +266,11 @@ def win(msg): def parseask (msg): + if len(DELAYED) > 0: + if msg.sender in DELAYED: + DELAYED[msg.sender].msg = msg.content[9:] + DELAYED[msg.sender].delayEvnt.set() + return True return False @@ -256,8 +282,12 @@ def getUser(name): def parselisten (msg): -# if msg.channel == "#nemutest": - if msg.channel != "#nemutest": +# if msg.channel == "#nemutest" and msg.sender not in DELAYED: + if msg.channel != "#nemutest" and msg.sender not in DELAYED: + if len(DELAYED) > 0: + if msg.sender in DELAYED and not DELAYED[msg.sender].triche(msg.content): + msg.send_chn("%s: n'oublie pas le nemubot: devant ta réponse pour qu'elle soit prise en compte !" % msg.sender) + if (msg.content.strip().startswith("42") and len (msg.content) < 5) or ((msg.content.strip().lower().startswith("quarante-deux") or msg.content.strip().lower().startswith("quarante deux")) and len (msg.content) < 17): if msg.time.minute == 10 and msg.time.second == 10 and msg.time.hour == 10: getUser(msg.sender).playTen() @@ -286,9 +316,8 @@ def parselisten (msg): getUser(msg.sender).playBad() if (msg.content.strip().startswith("12345") and len (msg.content) < 8) or (msg.content.strip().startswith("012345") and len (msg.content) < 9): - if msg.time.hour == 1 and msg.time.minute == 23 and msg.time.second == 45: - getUser(msg.sender).playGreat() - getUser(msg.sender).playTwt() + if msg.time.hour == 1 and msg.time.minute == 23 and (msg.time.second == 45 or (msg.time.second == 46 and msg.time.microsecond < 330000)): + getUser(msg.sender).playSuite() else: getUser(msg.sender).playBad() @@ -319,6 +348,59 @@ def parselisten (msg): if getUser(msg.sender).isWinner(): print ("Nous avons un vainqueur ! Nouvelle manche :p") win(msg) + return True elif getUser(msg.sender).hasChanged(): - save_module () + gu = GameUpdater(msg) + gu.start() + return True return False + +DELAYED = dict() + +class DelayedTuple: + def __init__(self, regexp): + self.delayEvnt = threading.Event() + self.msg = None + self.regexp = regexp + + def triche(self, res): + if res is not None: + return re.match(".*" + self.regexp + ".*", res.lower() + " ") is None + else: + return True + +# +# +# +# +# +# + + def wait(self, timeout): + self.delayEvnt.wait(timeout) + +class GameUpdater(threading.Thread): + def __init__(self, msg): + self.msg = msg + threading.Thread.__init__(self) + + def run(self): + global DELAYED, QUESTIONS + + quest = random.randint(0, len(QUESTIONS) * 2) + if self.msg.channel == "#nemutest": + quest = 9 + + if quest < len(QUESTIONS): + (question, regexp, great) = QUESTIONS[quest] + self.msg.send_chn("%s: %s" % (self.msg.sender, question)) + + DELAYED[self.msg.sender] = DelayedTuple(regexp) + + DELAYED[self.msg.sender].wait(20) + + if DELAYED[self.msg.sender].triche(DELAYED[self.msg.sender].msg): + getUser(self.msg.sender).playTriche() + self.msg.send_chn("%s: Tricheur !" % self.msg.sender) + del DELAYED[self.msg.sender] + save_module () diff --git a/server.py b/server.py index abffefa..c1ede7d 100644 --- a/server.py +++ b/server.py @@ -6,6 +6,11 @@ import time import message +#class WaitedAnswer: +# def __init__(self, channel): +# self.channel = channel +# self.module + class Server: def __init__(self, server, nick, owner, realname): self.nick = nick @@ -25,18 +30,28 @@ class Server: else: self.password = None + self.waited_answer = list() + self.listen_nick = True + self.partner = "nbr23" self.channels = list() for channel in server.getElementsByTagName('channel'): self.channels.append(channel.getAttribute("name")) + @property + def id(self): + return self.host + ":" + str(self.port) + def send_msg_final(self, channel, msg, cmd = "PRIVMSG", endl = "\r\n"): if msg is not None and channel is not None: for line in msg.split("\n"): if line != "": self.s.send (("%s %s :%s%s" % (cmd, channel, line, endl)).encode ()) + def send_msg_prtn (self, msg): + self.send_msg_final(self.partner, msg) + def send_msg_usr (self, user, msg): if user is not None and user[0] != "#": self.send_msg_final(user, msg) @@ -50,6 +65,9 @@ class Server: self.send_msg (channel, msg, cmd, endl) + def register_answer(self, channel, ): + self.waited_answer.append(channel) + def launch(self, mods, datas_dir): self.datas_dir = datas_dir _thread.start_new_thread(self.connect, (mods,)) diff --git a/soutenance.py b/soutenance.py index 17b228b..cd1e315 100644 --- a/soutenance.py +++ b/soutenance.py @@ -4,6 +4,7 @@ import http.client import time import re import _thread +import threading from datetime import date from datetime import datetime from datetime import timedelta @@ -28,6 +29,18 @@ class Soutenance: self.start = None self.end = None +DELAYED = dict() + +class Delayed: + def __init__(self, name): + self.name = name + self.res = None + self.evt = threading.Event() + + def wait(self, timeout): + self.evt.clear() + self.evt.wait(timeout) + class SiteSoutenances: def __init__(self, page): save = False @@ -170,6 +183,15 @@ def startSoutenance (msg): if msg.cmd[0] == "soutenance": soutenance = datas.findClose(name) + if soutenance is None: + global DELAYED + DELAYED[msg] = Delayed(name) + msg.srv.send_msg_prtn ("~whois %s" % name) + DELAYED[msg].wait(5) + if DELAYED[msg].res is not None: + name = DELAYED[msg].res + soutenance = datas.findClose(name) + if soutenance is None: msg.send_chn ("Pas d'horaire de soutenance pour %s."%name) else: @@ -207,6 +229,18 @@ def startSoutenance (msg): def parseask (msg): + if len(DELAYED) > 0 and msg.sender == msg.srv.partner: + treat = False + for part in msg.content.split(';'): + if part is None: + continue + for d in DELAYED.keys(): + if DELAYED[d].res is None and part.find(DELAYED[d].name) >= 0: + result = re.match(".* est (.*[^.])\.?", part) + if result is not None: + DELAYED[d].res = result.group(1) + DELAYED[d].evt.set() + return treat return False def parselisten (msg): diff --git a/watchWebsite.py b/watchWebsite.py index e304635..bd1403f 100644 --- a/watchWebsite.py +++ b/watchWebsite.py @@ -4,8 +4,8 @@ import http.client import hashlib import sys import traceback +import socket import time -import pickle import base64 import _thread from urllib.parse import unquote @@ -36,13 +36,7 @@ class Site: else: self.updateTime = 60 self.lastChange = 0 - if len(item.childNodes) > 0 and item.childNodes[0].nodeValue is not None: - self.lastpage = pickle.loads(base64.b64decode(item.childNodes[0].nodeValue.encode())) - elif item.nodeValue is not None: - self.lastpage = pickle.loads(base64.b64decode(item.nodeValue.encode())) - else: - self.lastpage = None - print (self.server, self.lastpage) + self.lastpage = None self.run = True @@ -57,12 +51,12 @@ class Site: def send_message (self, msg): global SRVS if len(self.channels) > 0: - for server in SRVS: + for server in SRVS.keys(): for chan in self.channels: - server.send_msg (chan, msg) + SRVS[server].send_msg (chan, msg) else: - for server in SRVS: - server.send_global (msg) + for server in SRVS.keys(): + SRVS[server].send_global (msg) def treat_atom (self, content): change=False @@ -103,6 +97,8 @@ class Site: try: # print ("Check %s/%s"%(self.server, self.page)) content = getPage(self.server, self.page) + if content is None: + return if self.type == "atom": (self.lastpage, change) = self.treat_atom (content) @@ -161,6 +157,8 @@ def launch (servers): SRVS = servers for site in SITES: site.start () +def stop(): + return def save_module(): """Save the module state""" @@ -175,8 +173,6 @@ def save_module(): if len(site.channels) > 0: for chan in site.channels: item.appendChild(parseString ('' % (chan)).documentElement); - b64 = base64.b64encode(pickle.dumps(site.lastpage)).decode() - item.appendChild(newdoc.createTextNode(b64)); #print (site.server) top.appendChild(item); @@ -207,7 +203,11 @@ def parselisten (msg): def getPage (s, p): conn = http.client.HTTPConnection(s) - conn.request("GET", "/%s"%(p)) + try: + conn.request("GET", "/%s"%(p)) + except socket.gaierror: + print ("[%s] impossible de récupérer la page %s."%(s, p)) + return None res = conn.getresponse() data = res.read() diff --git a/whereis.py b/whereis.py index 52b5245..3661e67 100644 --- a/whereis.py +++ b/whereis.py @@ -5,6 +5,7 @@ import sys import socket import time import _thread +import threading from datetime import datetime from datetime import date from datetime import timedelta @@ -26,7 +27,9 @@ class UpdatedStorage: if sock != None: for l in list_users(sock): u = User(l) - self.users[u.login] = u + if u.login not in self.users: + self.users[u.login] = list() + self.users[u.login].append(u) sock.close() self.lastUpdate = datetime.now () @@ -48,17 +51,23 @@ class User(object): @property def sm(self): if self.ip.startswith('10.200'): - return 'en SM' + self.ip.split('.')[2] + ip = self.ip.split('.') + if 20 < int(ip[2]) < 30: + return 'SM02' + else: + return 'SM' + self.ip.split('.')[2] + elif self.ip.startswith('10.242'): + return 'bocal' elif self.ip.startswith('10.247'): - return 'en pasteur' + return 'pasteur' elif self.ip.startswith('10.248'): - return 'en srlab' + return 'srlab' elif self.ip.startswith('10.249'): - return 'en midlab' + return 'midlab' elif self.ip.startswith('10.250'): - return 'en cisco' - elif self.ip.startswith('10.41'): - return 'sur le wifi' + return 'cisco' + elif self.ip.startswith('10.41.'): + return 'wifi' else: return None @@ -71,9 +80,13 @@ class User(object): return "chez lui" else: if self.ip.startswith('10.200'): - return self.sm + " poste " + self.ip.split('.')[3] + sm = self.sm + if sm == "SM02": + return "en " + sm + else: + return "en " + sm + " poste " + self.ip.split('.')[3] else: - return self.sm + " rangée " + self.ip.split('.')[2] + " poste " + self.ip.split('.')[3] + return "en " + self.sm + " rangée " + self.ip.split('.')[2] + " poste " + self.ip.split('.')[3] def __cmp__(self, other): return cmp(self.login, other.login) @@ -88,7 +101,7 @@ def connect_to_ns(server, port): s.connect((server, port)) except socket.error: return None - s.recv(8192) # salut ... + s.recv(8192) return s def list_users(sock): @@ -108,10 +121,9 @@ def load_module(datas_path): def save_module(): """Save the module state""" - if THREAD is not None: - THREAD.exit() return + def help_tiny (): """Line inserted in the response to the command !help""" return "Find a user on the PIE" @@ -131,36 +143,138 @@ def startWhereis(msg): msg.send_chn("Hmm c'est embarassant, serait-ce la fin du monde ou juste netsoul qui est mort ?") return - pasla = list() + if msg.cmd[0] == "peoplein": + peoplein(msg) + elif msg.cmd[0] == "whoison": + whoison(msg) + else: + whereis_msg(msg) + THREAD = None + if len(search) > 0: + startWhereis(search.pop()) + +def peoplein(msg): + if len(msg.cmd) > 1: + for sm in msg.cmd: + sm = sm.lower() + if sm == "peoplein": + continue + else: + count = 0 + for userC in datas.users: + for user in datas.users[userC]: + usersm = user.sm + if usersm is not None and usersm.lower() == sm: + count += 1 + if count > 1: + sOrNot = "s" + else: + sOrNot = "" + msg.send_chn ("Il y a %d personne%s en %s." % (count, sOrNot, sm)) + +def whoison(msg): + if len(msg.cmd) > 1: + for pb in msg.cmd: + pc = pb.lower() + if pc == "whoison": + continue + else: + found = list() + print (len(datas.users)) + for userC in datas.users: + for user in datas.users[userC]: + if user.ip[:len(pc)] == pc or user.location.lower() == pc: + found.append(user.login) + if len(found) > 0: + if len(found) <= 15: + msg.send_chn ("%s correspond à %s" % (pb, ", ".join(found))) + else: + msg.send_chn ("%s: %d personnes" % (pb, len(found))) + else: + msg.send_chn ("%s: personne ne match ta demande :(" % (msg.sender)) + +DELAYED = dict() +delayEvnt = threading.Event() + +class Delayed: + def __init__(self): + self.names = dict() + +def whereis_msg(msg): + names = list() for name in msg.cmd: if name == "whereis" or name == "whereare" or name == "ouest" or name == "ousont" or name == "ip": if len(msg.cmd) >= 2: continue else: name = msg.sender + else: + names.append(name) + pasla = whereis(msg, names) + if len(pasla) > 0: + global DELAYED + DELAYED[msg] = Delayed() + for name in pasla: + DELAYED[msg].names[name] = None + #msg.srv.send_msg_prtn ("~whois %s" % name) + msg.srv.send_msg_prtn ("~whois %s" % " ".join(pasla)) + startTime = datetime.now() + names = list() + while len(DELAYED[msg].names) > 0 and startTime + timedelta(seconds=4) > datetime.now(): + delayEvnt.clear() + delayEvnt.wait(2) + rem = list() + for name in DELAYED[msg].names.keys(): + if DELAYED[msg].names[name] is not None: + pasla = whereis(msg, (DELAYED[msg].names[name],)) + if len(pasla) != 0: + names.append(pasla[0]) + rem.append(name) + for r in rem: + del DELAYED[msg].names[r] + for name in DELAYED[msg].names.keys(): + if DELAYED[msg].names[name] is None: + names.append(name) + else: + names.append(DELAYED[msg].names[name]) + if len(names) > 1: + msg.send_chn ("%s ne sont pas connectés sur le PIE." % (", ".join(names))) + else: + for name in names: + msg.send_chn ("%s n'est pas connecté sur le PIE." % name) + +def whereis(msg, names): + pasla = list() + + for name in names: if name in datas.users: if msg.cmd[0] == "ip": - msg.send_chn ("L'ip de %s est %s." %(name, datas.users[name].ip)) + if len(datas.users[name]) == 1: + msg.send_chn ("L'ip de %s est %s." %(name, datas.users[name][0].ip)) + else: + out = "" + for local in datas.users[name]: + out += ", " + local.ip + msg.send_chn ("%s est connecté à plusieurs endroits : %s." %(name, out[2:])) else: - msg.send_chn ("%s est %s (%s)." %(name, datas.users[name].poste, unquote(datas.users[name].location))) + if len(datas.users[name]) == 1: + msg.send_chn ("%s est %s (%s)." %(name, datas.users[name][0].poste, unquote(datas.users[name][0].location))) + else: + out = "" + for local in datas.users[name]: + out += ", " + local.poste + " (" + unquote(local.location) + ")" + msg.send_chn ("%s est %s." %(name, out[2:])) else: pasla.append(name) - if len(pasla) == 1: - msg.send_chn ("%s n'est pas connecté sur le PIE." % pasla[0]) - elif len(pasla) > 1: - msg.send_chn ("%s ne sont pas connectés sur le PIE." % ", ".join(pasla)) - - THREAD = None - if len(search) > 0: - startWhereis(search.pop()) + return pasla def parseanswer (msg): global datas, THREAD, search - if msg.cmd[0] == "whereis" or msg.cmd[0] == "whereare" or msg.cmd[0] == "ouest" or msg.cmd[0] == "ousont" or msg.cmd[0] == "ip": + if msg.cmd[0] == "whereis" or msg.cmd[0] == "whereare" or msg.cmd[0] == "ouest" or msg.cmd[0] == "ousont" or msg.cmd[0] == "ip" or msg.cmd[0] == "peoplein" or msg.cmd[0] == "whoison": if len(msg.cmd) > 10: msg.send_snd ("Demande moi moins de personnes à la fois dans ton !%s" % msg.cmd[0]) return True @@ -173,6 +287,19 @@ def parseanswer (msg): return False def parseask (msg): + if len(DELAYED) > 0 and msg.sender == msg.srv.partner: + treat = False + for part in msg.content.split(';'): + if part is None: + continue + for d in DELAYED.keys(): + for n in DELAYED[d].names.keys(): + if DELAYED[d].names[n] is None and part.find(n) >= 0: + result = re.match(".* est (.*[^.])\.?", part) + if result is not None: + DELAYED[d].names[n] = result.group(1) + delayEvnt.set() + return treat return False def parselisten (msg):