# -*- coding: utf-8 -*- # # Copyright 2010 Maurizio Porrato # See LICENSE.txt for copyright info import shelve from twisted.python import log from frn.user import FRNUser CLIENTS_ORDER = ['Crosslink', 'Parrot', 'Gateway', 'PC Only'] def client_cmp(a, b): try: ta = CLIENTS_ORDER.index(a.BC) except: ta = CLIENTS_ORDER.index('Gateway') try: tb = CLIENTS_ORDER.index(b.BC) except: tb = CLIENTS_ORDER.index('Gateway') if ta < tb: r = -1 elif ta > tb: r = 1 else: if a.ON < b.ON: r = -1 elif a.ON > b.ON: r = 1 else: r = 0 return r class ClientTracker(object): def __init__(self, filename, cbClient, cbNet, cbMute, cbBlock, cbAdmin): self._clientData = {} self._net = {} self._mute = {} self._block = {} self._admin = {} self._acl = {} self.cbClient = cbClient self.cbNet = cbNet self.cbMute = cbMute self.cbBlock = cbBlock self.cbAdmin = cbAdmin self.filename = filename self.load() def load(self, filename=None): s = shelve.open(filename or self.filename) try: self._mute = s['mute'] self._block = s['block'] self._admin = s['admin'] self._acl = s['acl'] except KeyError: pass s.close() def save(self, filename=None): s = shelve.open(filename or self.filename) s['mute'] = self._mute s['block'] = self._block s['admin'] = self._admin s['acl'] = self._acl s.close() def isLoggedIn(self, clientId): return clientId in self._clientData def getClient(self, clientId): return self._clientData[clientId].user def getClientProtocol(self, clientId): return self._clientData[clientId] def getClientIndex(self, clientId): net = self.getClient(clientId).NT l = [x.ID for x in self.getClientList(net)] return l.index(clientId)+1 def getNetworkList(self): return sorted(set(self._net.keys())|set(self._acl.keys())) def getClientList(self, network=[]): if network: allClients = self._net.get(network, []) else: allClients = self._clientData.keys() return [self._clientData[x].user for x in allClients] def getMuteList(self, network=[]): if network: return [x for x in self._mute.values() if self._mute[x.ID].NT in network] else: return [x for x in self._mute.values()] def getBlockList(self): return self._block.values() def getAdminList(self): return self._admin.values() def isMute(self, clientId): return clientId in self._mute def isBlocked(self, clientId): return clientId in self._block def isAdmin(self, clientId): return clientId in self._admin def login(self, client, status=0): clientId = client.user.ID if clientId not in self._clientData: if not self.aclTalkOk(client.user.NT, client.user.EA) and status < 1: client.user.S = 1 else: client.user.S = status self._clientData[clientId] = client net = client.user.NT nc = self._net.get(net, []) ni = None for i, c in enumerate(nc): if client_cmp(client.user, self._clientData[c].user) < 0: ni = i break if ni is None: ni = len(nc) nc.insert(ni, clientId) self._net[net] = nc if clientId in self._mute: client.user.M = 1 a = self._mute[clientId].AI self._mute[clientId].update(**client.user.dict()) self._mute[clientId].AI = a else: client.user.M = 0 if not self.canLogin(client.user): client.role = "BLOCK" else: self.aclUpdate(client.user) if client.user.EA in self._admin: client.role = "ADMIN" self._admin[client.user.EA].update(client.user.dict()) self.save() if len(nc) == 1: self.cbNet(self.getNetworkList()) self.cbClient(net, self.getClientList(net)) def logout(self, client): if client.user is None: return clientId = client.user.ID log.msg("Client logout: %s" % (clientId,)) if clientId in self._clientData: del self._clientData[clientId] net = client.user.NT self._net[net].remove(clientId) if not self._net[net]: del self._net[net] self.cbNet(self.getNetworkList()) self.save() self.cbClient(net, self.getClientList(net)) def setStatus(self, clientId, status): user = self.getClient(clientId) oldStatus = user.S if not self.aclTalkOk(user.NT, user.EA) and status < 1: status = 1 if oldStatus != str(status): self._clientData[clientId].user.S = status self.cbClient(user.NT, self.getClientList(user.NT)) def mute(self, admin, clientId): if clientId not in self._mute: self._mute[clientId] = self.getClient(clientId).copy(AI=admin.ON) self._clientData[clientId].user.M = 1 self.save() net = self.getClient(clientId).NT self.cbClient(net, self.getClientList(net)) self.cbMute(self.getMuteList()) def unMute(self, clientId): if clientId in self._mute: del self._mute[clientId] if clientId in self._clientData: self._clientData[clientId].user.M = 0 net = self._clientData[clientId].user.NT self.cbClient(net, self.getClientList(net)) self.save() self.cbMute(self.getMuteList()) def block(self, admin, clientId): if clientId not in self._block: self._block[clientId] = self.getClient(clientId).copy(AI=admin.ON) if clientId in self._clientData: net = self._clientData[clientId].user.NT self.save() self.cbBlock(self.getBlockList()) def unBlock(self, clientId): if clientId in self._block: del self._block[clientId] self.save() self.cbBlock(self.getBlockList()) def admin(self, clientId): if clientId not in self._admin: self._admin[clientId] = self.getClient(clientId).copy() self.save() self.cbAdmin(self.getAdminList()) def unAdmin(self, clientId): if clientId in self._admin: del self._admin[clientId] self.save() self.cbAdmin(self.getAdminList()) def _getAcl(self, network): return self._acl.get(network, (False, False, {})) def _setAcl(self, network, ac, tx, l): log.msg("Changing ACL for %s" % network) if ac == tx == False and len(l) == 0: log.msg("Default settings detected") if network in self._acl: log.msg("Deleting") del self._acl[network] else: log.msg("Setting ACL for %s to %s" % (network, str((ac,tx,l)))) self._acl[network] = (ac, tx, l) self.save() def getAcl(self, network): ac, tx, l = self._getAcl(network) return l.values() def getAclFlags(self, network): ac, tx, l = self._getAcl(network) return (ac, tx) def setAclFlags(self, network, ac, tx): oac, otx, l = self._getAcl(network) self._setAcl(network, ac, tx, l) def addAcl(self, network, email): log.msg("Adding %s to ACL for %s" % (email, network)) ac, tx, l = self._getAcl(network) if email not in l: knownUsers = dict([(x.EA, x) for x in [y.user for y in self._clientData.values()] + self._mute.values() + self._block.values()]) user = knownUsers.get(email, FRNUser(EA=email)).copy(ID=email, AI=1) l[email] = user self._setAcl(network, ac, tx, l) def delAcl(self, network, email): log.msg("Removing %s from ACL for %s" % (email, network)) ac, tx, l = self._getAcl(network) if email in l: del l[email] self._setAcl(network, ac, tx, l) def setAclTx(self, network, email, tx): oac, otx, l = self._getAcl(network) if email in l: if tx: l[email].AI = 0 else: l[email].AI = 1 self._setAcl(network, oac, otx, l) def aclUpdate(self, user): network = user.NT email = user.EA ac, tx, l = self._getAcl(network) if email in l: old = l[email] new = user.copy(ID=email, AI=old.AI) l[email] = new self._setAcl(network, ac, tx, l) def aclLoginOk(self, network, email): ac, tx, l = self._getAcl(network) if not ac: return True return email in l def aclTalkOk(self, network, email): ac, tx, l = self._getAcl(network) if not tx: return True if email not in l: return False return l[email].AI == '0' def canLogin(self, user): if self.isBlocked(user.ID): return False return self.aclLoginOk(user.NT, user.EA) def canTalk(self, clientId): if self.isMute(clientId): return False u = self.getClient(clientId) return self.aclTalkOk(u.NT, u.EA) # vim: set et ai sw=4 ts=4 sts=4: