1
0
Fork 0
nemubot/whereis.py

336 lines
9.6 KiB
Python

# coding=utf-8
import re
import sys
import socket
import time
import _thread
import threading
from datetime import datetime
from datetime import date
from datetime import timedelta
from urllib.parse import unquote
from xml.dom.minidom import parse
from xml.dom.minidom import parseString
from xml.dom.minidom import getDOMImplementation
NS_SERVER = 'ns-server.epita.fr'
NS_PORT = 4242
THREAD = None
search = list()
class UpdatedStorage:
def __init__(self):
sock = connect_to_ns(NS_SERVER, NS_PORT)
self.users = dict()
if sock != None:
for l in list_users(sock):
u = User(l)
if u.login not in self.users:
self.users[u.login] = list()
self.users[u.login].append(u)
sock.close()
self.lastUpdate = datetime.now ()
def update(self):
if datetime.now () - self.lastUpdate < timedelta(minutes=10):
return self
else:
return None
class User(object):
def __init__(self, line):
fields = line.split()
self.login = fields[1]
self.ip = fields[2]
self.location = fields[8]
self.promo = fields[9]
@property
def sm(self):
if self.ip.startswith('10.200'):
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 'pasteur'
elif self.ip.startswith('10.248'):
return 'srlab'
elif self.ip.startswith('10.249'):
return 'midlab'
elif self.ip.startswith('10.250'):
return 'cisco'
elif self.ip.startswith('10.41.'):
return 'wifi'
elif self.ip.startswith('10.223.3.'):
return 'épimac'
elif self.ip.startswith('10.223.4.'):
return 'wcube'
elif self.ip.startswith('10.223.5.'):
return 'cycom'
elif self.ip.startswith('10.223.6.'):
return 'epitv'
elif self.ip.startswith('10.223.7.'):
return 'prologin'
elif self.ip.startswith('10.223'):
return 'assos'
elif self.ip.startswith('10.226.7.'):
return 'gistre'
elif self.ip.startswith('10.224.1.'):
return 'astek'
elif self.ip.startswith('10.224.2.'):
return 'acu'
elif self.ip.startswith('10.224.4.'):
return 'lse'
elif self.ip.startswith('10.224.8.'):
return 'eip'
elif self.ip.startswith('10.224.16.'):
return 'evolutek'
elif self.ip.startswith('10.224.18.'):
return 'mslab'
elif self.ip.startswith('10.2.'):
return 'adm'
elif self.ip.startswith('10.10.'):
return 'vpn'
else:
return None
@property
def poste(self):
if self.sm is None:
if self.ip.startswith('10.'):
return 'quelque part sur le PIE (%s)'%self.ip
else:
return "chez lui"
else:
if self.ip.startswith('10.247') or self.ip.startswith('10.248') or self.ip.startswith('10.249') or self.ip.startswith('10.250'):
return "en " + self.sm + " rangée " + self.ip.split('.')[2] + " poste " + self.ip.split('.')[3]
else:
return "en " + self.sm
def __cmp__(self, other):
return cmp(self.login, other.login)
def __hash__(self):
return hash(self.login)
def connect_to_ns(server, port):
try:
s = socket.socket()
s.settimeout(1)
s.connect((server, port))
except socket.error:
return None
s.recv(8192)
return s
def list_users(sock):
sock.send('list_users\n'.encode())
buf = ''
while True:
tmp = sock.recv(8192).decode()
buf += tmp
if '\nrep 002' in tmp or tmp == '':
break
return buf.split('\n')[:-2]
def load_module(datas_path):
"""Load this module"""
return
def save_module():
"""Save the module state"""
return
def help_tiny ():
"""Line inserted in the response to the command !help"""
return "Find a user on the PIE"
def help_full ():
return "!whereis /who/: gives the position of /who/.\n!whereare /who/ [/other who/ ...]: gives the position of /who/."
datas = None
def startWhereis(msg):
global datas, THREAD, search
if datas is not None:
datas = datas.update ()
if datas is None:
datas = UpdatedStorage()
if datas is None:
msg.send_chn("Hmm c'est embarassant, serait-ce la fin du monde ou juste netsoul qui est mort ?")
return
if msg.cmd[0] == "peoplein":
peoplein(msg)
elif msg.cmd[0] == "whoison" or msg.cmd[0] == "whoisin":
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" or pc == "whoisin":
continue
else:
found = list()
print (len(datas.users))
for userC in datas.users:
for user in datas.users[userC]:
if (msg.cmd[0] == "whoison" and (user.ip[:len(pc)] == pc or user.location.lower() == pc)) or (msg.cmd[0] == "whoisin" and user.sm == pc):
found.append(user.login)
if len(found) > 0:
if len(found) <= 15:
if pc == "whoisin":
msg.send_chn ("En %s, il y a %s" % (pb, ", ".join(found)))
else:
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":
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:
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)
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" or msg.cmd[0] == "peoplein" or msg.cmd[0] == "whoison" or msg.cmd[0] == "whoisin":
if len(msg.cmd) > 10:
msg.send_snd ("Demande moi moins de personnes à la fois dans ton !%s" % msg.cmd[0])
return True
if THREAD is None:
THREAD = _thread.start_new_thread (startWhereis, (msg,))
else:
search.append(msg)
return True
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):
return False