312 lines
9.7 KiB
Python
312 lines
9.7 KiB
Python
# -*- coding: utf-8 -*-
|
|
#
|
|
# Copyright 2010 Maurizio Porrato <maurizio.porrato@gmail.com>
|
|
# 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:
|