manager: fix unicode regression
[grn.git] / twisted / plugins / frncrosslink.py
blobe9d1996a4cdf9cc307ad3f09e2e0d29d3b7b523c
1 # -*- coding: utf-8 -*-
3 # Copyright 2010 Maurizio Porrato <maurizio.porrato@gmail.com>
4 # See LICENSE.txt for copyright info
6 from twisted.application.service import MultiService
7 from zope.interface import implements
8 from twisted.plugin import IPlugin
9 from twisted.application.service import IServiceMaker
10 from twisted.application import internet
11 from twisted.python import usage
12 from ConfigParser import ConfigParser
13 from frn.protocol.client import FRNClient, FRNClientFactory
14 from frn.user import FRNUser
15 from twisted.python import log
16 from os.path import curdir, join as pjoin
18 cType = {'PC Only': 'O', 'Crosslink': 'C', 'Parrot': 'P'}
19 cStatus = {'0': 'T', '1': 'R', '2': 'N'}
21 clients = []
22 talking = None
23 lastMessages = []
25 class FRNCrosslinkClient(FRNClient):
27 def connectionMade(self):
28 self.txOk = False
29 self.txReq = False
30 self.clientId = None
31 from twisted.internet import reactor
32 self.reactor = reactor
33 FRNClient.connectionMade(self)
35 def getClientName(self, client_id):
36 if self.clientsById.has_key(client_id):
37 return self.clientsById[client_id]['ON']
38 else:
39 return client_id
41 def sendMultiLineTextMessage(self, client, lines, maxLen=15):
42 chunks = [lines[i*maxLen:(i+1)*maxLen]
43 for i in range((len(lines)+maxLen-1)/maxLen)]
44 for m in chunks:
45 reply = '<br>'.join(m)
46 self.sendTextMessage(client, reply)
48 def textMessageReceived(self, client, message, target):
49 global clients, talking, lastMessages
50 if target == 'A':
51 msg = "[%s] %s" % (self.getClientName(client), message)
52 if client != self.clientId:
53 for _, _, _, factory in clients:
54 if factory != self.factory:
55 factory.connection.sendTextMessage('', msg)
56 else:
57 if message.startswith('!'):
58 cmd = message[1:]
59 if cmd == "who":
60 for server, port, u, factory in clients:
61 cl = []
62 cl.append("<u>%s@%s:%d</u>" % (u.NT,server,port))
63 role = factory.connection.serverdata.get('AL', None)
64 if role in ['OK', 'ADMIN', 'OWNER']:
65 for c in factory.connection.clients:
66 ss = cStatus.get(c['S'], '?')
67 if c['M'] != '0':
68 ss = ss.lower()
69 cl.append(" %s%s %s " % (
70 cType.get(c['BC'], 'G'),
71 ss,
72 c['ON'].replace('<', '&lt;'),
74 else:
75 cl.append(" :!: DISCONNECTED :!: ")
76 self.sendMultiLineTextMessage(client, cl)
77 elif cmd == "last":
78 ml = []
79 ml.append("Last active talkers (most recent first):")
80 for n in lastMessages:
81 ml.append(" - "+n)
82 self.sendMultiLineTextMessage(client, ml)
84 def decodeTX(self, my_id):
85 log.msg("Got TX ack for %s" % self.user.ON)
86 self.txOk = True
88 def stopTransmission(self):
89 FRNClient.stopTransmission(self)
90 log.msg("Stopped TX on %s" % self.user.ON)
92 def goIdle(self):
93 global talking, lastMessages
94 self.txReq = False
95 self.txOk = False
96 talking = None
97 self.stopTransmission()
99 def audioFrameReceived(self, from_id, frames):
100 global clients, talking, lastMessages
101 if talking is None or talking == self:
102 talking = self
103 talkingUser = self.clients[from_id-1]['ON']
104 if len(lastMessages) > 0:
105 if lastMessages[0] == talkingUser:
106 talkingUser = None
107 if talkingUser is not None:
108 lastMessages.insert(0, talkingUser)
109 lastMessages = lastMessages[:5]
110 for _, _, _, factory in clients:
111 conn = factory.connection
112 if conn != self:
113 role = conn.serverdata.get('AL', None)
114 if role in ['OK', 'ADMIN', 'OWNER']:
115 if conn.txOk:
116 conn.txReq = False
117 conn.sendAudioFrame(frames)
118 conn.busyTimer.reset(2.0)
119 else:
120 if not conn.txReq:
121 log.msg("Requesting TX for %s" % conn.user.ON)
122 conn.startTransmission()
123 conn.txReq = True
124 conn.busyTimer = self.reactor.callLater(
125 5.0, conn.goIdle)
126 self.pong()
128 def loginResponse(self, info):
129 log.msg("%s login: %s" % (self.user.ON, info['AL']))
131 def clientsListUpdated(self, clients):
132 self.clients = clients
133 self.clientsById = dict([(i['ID'], i) for i in clients])
134 if self.clientId is None:
135 for c in clients:
136 if c['ON'] == self.user.ON and c['BC'] == self.user.BC:
137 self.clientId = c['ID']
139 class FRNCrosslinkClientFactory(FRNClientFactory):
140 protocol = FRNCrosslinkClient
142 def buildProtocol(self, addr):
143 p = FRNClientFactory.buildProtocol(self, addr)
144 self.connection = p
145 return p
148 class Options(usage.Options):
150 optParameters = [
151 ["confdir", "c", curdir, "Directory containing config files"]
154 def parseArgs(self, *serverdefs):
155 basedir = self['confdir']
156 acfg = ConfigParser()
157 acfg.read(['/etc/grn/accounts.conf',
158 pjoin(basedir,'accounts.conf'), 'accounts.conf'])
160 scfg = ConfigParser()
161 scfg.read(['/etc/grn/servers.conf',
162 pjoin(basedir,'servers.conf'), 'servers.conf'])
164 clients = []
165 for serverdef in serverdefs:
166 account_name, server_name, network_name = serverdef.split(':', 2)
168 sd = {}
169 sd['server'] = scfg.get(server_name, 'server')
170 sd['port'] = scfg.getint(server_name, 'port')
171 sd['backup_server'] = scfg.get(server_name, 'backup_server')
172 sd['backup_port'] = scfg.getint(server_name, 'backup_port')
173 sd['operator'] = acfg.get(account_name, 'operator')
174 sd['email'] = acfg.get(account_name, 'email')
175 sd['password'] = acfg.get(account_name, 'password')
176 sd['description'] = acfg.get(account_name, 'description')
177 sd['country'] = acfg.get(account_name, 'country')
178 sd['city'] = acfg.get(account_name, 'city')
179 sd['network'] = network_name
180 clients.append(sd)
181 self['clients'] = clients
184 class FRNCrosslinkServiceMaker(object):
185 implements(IServiceMaker, IPlugin)
186 tapname = "frncrosslink"
187 description = "Freeradionetwork crosslink"
188 options = Options
190 def makeService(self, options):
191 s = MultiService()
192 global clients # FIXME: Get rid of this hack
193 for c in options['clients']:
194 user = FRNUser(
195 EA=c['email'],
196 PW=c['password'], ON=c['operator'],
197 # BC=c['transmission'], DS=c['description'],
198 BC="Crosslink", DS=c['description'],
199 NN=c['country'], CT=c['city'], NT=c['network'])
200 factory = FRNCrosslinkClientFactory(user)
201 clients.append((c['server'], c['port'], user, factory))
202 s.addService(
203 internet.TCPClient(c['server'], c['port'], factory))
204 return s
207 serviceMaker = FRNCrosslinkServiceMaker()
209 # vim: set et ai sw=4 ts=4 sts=4: