manager: fix unicode regression
[grn.git] / frn / clienttracker.py
blobee7414db14574be0e8d9a356ce7e498ab73021fe
1 # -*- coding: utf-8 -*-
3 # Copyright 2010 Maurizio Porrato <maurizio.porrato@gmail.com>
4 # See LICENSE.txt for copyright info
6 import shelve
7 from twisted.python import log
8 from frn.user import FRNUser
10 CLIENTS_ORDER = ['Crosslink', 'Parrot', 'Gateway', 'PC Only']
12 def client_cmp(a, b):
13 try:
14 ta = CLIENTS_ORDER.index(a.BC)
15 except:
16 ta = CLIENTS_ORDER.index('Gateway')
17 try:
18 tb = CLIENTS_ORDER.index(b.BC)
19 except:
20 tb = CLIENTS_ORDER.index('Gateway')
21 if ta < tb:
22 r = -1
23 elif ta > tb:
24 r = 1
25 else:
26 if a.ON < b.ON:
27 r = -1
28 elif a.ON > b.ON:
29 r = 1
30 else:
31 r = 0
32 return r
35 class ClientTracker(object):
37 def __init__(self, filename, cbClient, cbNet, cbMute, cbBlock, cbAdmin):
38 self._clientData = {}
39 self._net = {}
40 self._mute = {}
41 self._block = {}
42 self._admin = {}
43 self._acl = {}
44 self.cbClient = cbClient
45 self.cbNet = cbNet
46 self.cbMute = cbMute
47 self.cbBlock = cbBlock
48 self.cbAdmin = cbAdmin
49 self.filename = filename
50 self.load()
52 def load(self, filename=None):
53 s = shelve.open(filename or self.filename)
54 try:
55 self._mute = s['mute']
56 self._block = s['block']
57 self._admin = s['admin']
58 self._acl = s['acl']
59 except KeyError: pass
60 s.close()
62 def save(self, filename=None):
63 s = shelve.open(filename or self.filename)
64 s['mute'] = self._mute
65 s['block'] = self._block
66 s['admin'] = self._admin
67 s['acl'] = self._acl
68 s.close()
70 def isLoggedIn(self, clientId):
71 return clientId in self._clientData
73 def getClient(self, clientId):
74 return self._clientData[clientId].user
76 def getClientProtocol(self, clientId):
77 return self._clientData[clientId]
79 def getClientIndex(self, clientId):
80 net = self.getClient(clientId).NT
81 l = [x.ID for x in self.getClientList(net)]
82 return l.index(clientId)+1
84 def getNetworkList(self):
85 return sorted(set(self._net.keys())|set(self._acl.keys()))
87 def getClientList(self, network=[]):
88 if network:
89 allClients = self._net.get(network, [])
90 else:
91 allClients = self._clientData.keys()
92 return [self._clientData[x].user
93 for x in allClients]
95 def getMuteList(self, network=[]):
96 if network:
97 return [x for x in self._mute.values()
98 if self._mute[x.ID].NT in network]
99 else:
100 return [x for x in self._mute.values()]
102 def getBlockList(self):
103 return self._block.values()
105 def getAdminList(self):
106 return self._admin.values()
108 def isMute(self, clientId):
109 return clientId in self._mute
111 def isBlocked(self, clientId):
112 return clientId in self._block
114 def isAdmin(self, clientId):
115 return clientId in self._admin
117 def login(self, client, status=0):
118 clientId = client.user.ID
119 if clientId not in self._clientData:
120 if not self.aclTalkOk(client.user.NT, client.user.EA) and status < 1:
121 client.user.S = 1
122 else:
123 client.user.S = status
124 self._clientData[clientId] = client
125 net = client.user.NT
126 nc = self._net.get(net, [])
127 ni = None
128 for i, c in enumerate(nc):
129 if client_cmp(client.user, self._clientData[c].user) < 0:
130 ni = i
131 break
132 if ni is None:
133 ni = len(nc)
134 nc.insert(ni, clientId)
135 self._net[net] = nc
136 if clientId in self._mute:
137 client.user.M = 1
138 a = self._mute[clientId].AI
139 self._mute[clientId].update(**client.user.dict())
140 self._mute[clientId].AI = a
141 else:
142 client.user.M = 0
143 if not self.canLogin(client.user):
144 client.role = "BLOCK"
145 else:
146 self.aclUpdate(client.user)
147 if client.user.EA in self._admin:
148 client.role = "ADMIN"
149 self._admin[client.user.EA].update(client.user.dict())
150 self.save()
151 if len(nc) == 1:
152 self.cbNet(self.getNetworkList())
153 self.cbClient(net, self.getClientList(net))
155 def logout(self, client):
156 if client.user is None:
157 return
158 clientId = client.user.ID
159 log.msg("Client logout: %s" % (clientId,))
160 if clientId in self._clientData:
161 del self._clientData[clientId]
162 net = client.user.NT
163 self._net[net].remove(clientId)
164 if not self._net[net]:
165 del self._net[net]
166 self.cbNet(self.getNetworkList())
167 self.save()
168 self.cbClient(net, self.getClientList(net))
170 def setStatus(self, clientId, status):
171 user = self.getClient(clientId)
172 oldStatus = user.S
173 if not self.aclTalkOk(user.NT, user.EA) and status < 1:
174 status = 1
175 if oldStatus != str(status):
176 self._clientData[clientId].user.S = status
177 self.cbClient(user.NT, self.getClientList(user.NT))
179 def mute(self, admin, clientId):
180 if clientId not in self._mute:
181 self._mute[clientId] = self.getClient(clientId).copy(AI=admin.ON)
182 self._clientData[clientId].user.M = 1
183 self.save()
184 net = self.getClient(clientId).NT
185 self.cbClient(net, self.getClientList(net))
186 self.cbMute(self.getMuteList())
188 def unMute(self, clientId):
189 if clientId in self._mute:
190 del self._mute[clientId]
191 if clientId in self._clientData:
192 self._clientData[clientId].user.M = 0
193 net = self._clientData[clientId].user.NT
194 self.cbClient(net, self.getClientList(net))
195 self.save()
196 self.cbMute(self.getMuteList())
198 def block(self, admin, clientId):
199 if clientId not in self._block:
200 self._block[clientId] = self.getClient(clientId).copy(AI=admin.ON)
201 if clientId in self._clientData:
202 net = self._clientData[clientId].user.NT
203 self.save()
204 self.cbBlock(self.getBlockList())
206 def unBlock(self, clientId):
207 if clientId in self._block:
208 del self._block[clientId]
209 self.save()
210 self.cbBlock(self.getBlockList())
212 def admin(self, clientId):
213 if clientId not in self._admin:
214 self._admin[clientId] = self.getClient(clientId).copy()
215 self.save()
216 self.cbAdmin(self.getAdminList())
218 def unAdmin(self, clientId):
219 if clientId in self._admin:
220 del self._admin[clientId]
221 self.save()
222 self.cbAdmin(self.getAdminList())
224 def _getAcl(self, network):
225 return self._acl.get(network, (False, False, {}))
227 def _setAcl(self, network, ac, tx, l):
228 log.msg("Changing ACL for %s" % network)
229 if ac == tx == False and len(l) == 0:
230 log.msg("Default settings detected")
231 if network in self._acl:
232 log.msg("Deleting")
233 del self._acl[network]
234 else:
235 log.msg("Setting ACL for %s to %s" % (network, str((ac,tx,l))))
236 self._acl[network] = (ac, tx, l)
237 self.save()
239 def getAcl(self, network):
240 ac, tx, l = self._getAcl(network)
241 return l.values()
243 def getAclFlags(self, network):
244 ac, tx, l = self._getAcl(network)
245 return (ac, tx)
247 def setAclFlags(self, network, ac, tx):
248 oac, otx, l = self._getAcl(network)
249 self._setAcl(network, ac, tx, l)
251 def addAcl(self, network, email):
252 log.msg("Adding %s to ACL for %s" % (email, network))
253 ac, tx, l = self._getAcl(network)
254 if email not in l:
255 knownUsers = dict([(x.EA, x) for x in [y.user for y in self._clientData.values()] + self._mute.values() + self._block.values()])
256 user = knownUsers.get(email, FRNUser(EA=email)).copy(ID=email, AI=1)
257 l[email] = user
258 self._setAcl(network, ac, tx, l)
260 def delAcl(self, network, email):
261 log.msg("Removing %s from ACL for %s" % (email, network))
262 ac, tx, l = self._getAcl(network)
263 if email in l:
264 del l[email]
265 self._setAcl(network, ac, tx, l)
267 def setAclTx(self, network, email, tx):
268 oac, otx, l = self._getAcl(network)
269 if email in l:
270 if tx:
271 l[email].AI = 0
272 else:
273 l[email].AI = 1
274 self._setAcl(network, oac, otx, l)
276 def aclUpdate(self, user):
277 network = user.NT
278 email = user.EA
279 ac, tx, l = self._getAcl(network)
280 if email in l:
281 old = l[email]
282 new = user.copy(ID=email, AI=old.AI)
283 l[email] = new
284 self._setAcl(network, ac, tx, l)
286 def aclLoginOk(self, network, email):
287 ac, tx, l = self._getAcl(network)
288 if not ac:
289 return True
290 return email in l
292 def aclTalkOk(self, network, email):
293 ac, tx, l = self._getAcl(network)
294 if not tx:
295 return True
296 if email not in l:
297 return False
298 return l[email].AI == '0'
300 def canLogin(self, user):
301 if self.isBlocked(user.ID):
302 return False
303 return self.aclLoginOk(user.NT, user.EA)
305 def canTalk(self, clientId):
306 if self.isMute(clientId):
307 return False
308 u = self.getClient(clientId)
309 return self.aclTalkOk(u.NT, u.EA)
311 # vim: set et ai sw=4 ts=4 sts=4: