3
from zope.interface import Interface, implements
5
from twisted.application import internet, service
6
from twisted.internet import protocol, reactor, defer
7
from twisted.words.protocols import irc
8
from twisted.protocols import basic
9
from twisted.python import components, log
10
from twisted.web import resource, server, xmlrpc
11
from twisted.spread import pb
13
from OpenSSL import SSL
15
class IFingerService(Interface):
18
"""Return a deferred returning a string"""
21
"""Return a deferred returning a list of strings"""
23
class IFingerSetterService(Interface):
25
def setUser(user, status):
26
"""Set the user's status to something"""
29
return "Internal error in server"
31
class FingerProtocol(basic.LineReceiver):
33
def lineReceived(self, user):
34
d = self.factory.getUser(user)
35
d.addErrback(catchError)
36
def writeValue(value):
37
self.transport.write(value+'\n')
38
self.transport.loseConnection()
39
d.addCallback(writeValue)
42
class IFingerFactory(Interface):
45
"""Return a deferred returning a string"""
47
def buildProtocol(addr):
48
"""Return a protocol returning a string"""
51
class FingerFactoryFromService(protocol.ServerFactory):
52
implements(IFingerFactory)
54
protocol = FingerProtocol
56
def __init__(self, service):
57
self.service = service
59
def getUser(self, user):
60
return self.service.getUser(user)
62
components.registerAdapter(FingerFactoryFromService,
66
class FingerSetterProtocol(basic.LineReceiver):
68
def connectionMade(self):
71
def lineReceived(self, line):
72
self.lines.append(line)
74
def connectionLost(self, reason):
75
if len(self.lines) == 2:
76
self.factory.setUser(*self.lines)
79
class IFingerSetterFactory(Interface):
81
def setUser(user, status):
82
"""Return a deferred returning a string"""
84
def buildProtocol(addr):
85
"""Return a protocol returning a string"""
88
class FingerSetterFactoryFromService(protocol.ServerFactory):
90
implements(IFingerSetterFactory)
92
protocol = FingerSetterProtocol
94
def __init__(self, service):
95
self.service = service
97
def setUser(self, user, status):
98
self.service.setUser(user, status)
101
components.registerAdapter(FingerSetterFactoryFromService,
102
IFingerSetterService,
103
IFingerSetterFactory)
105
class IRCReplyBot(irc.IRCClient):
107
def connectionMade(self):
108
self.nickname = self.factory.nickname
109
irc.IRCClient.connectionMade(self)
111
def privmsg(self, user, channel, msg):
112
user = user.split('!')[0]
113
if self.nickname.lower() == channel.lower():
114
d = self.factory.getUser(msg)
115
d.addErrback(catchError)
116
d.addCallback(lambda m: "Status of %s: %s" % (msg, m))
117
d.addCallback(lambda m: self.msg(user, m))
120
class IIRCClientFactory(Interface):
127
"""Return a deferred returning a string"""
129
def buildProtocol(addr):
130
"""Return a protocol"""
133
class IRCClientFactoryFromService(protocol.ClientFactory):
135
implements(IIRCClientFactory)
137
protocol = IRCReplyBot
140
def __init__(self, service):
141
self.service = service
143
def getUser(self, user):
144
return self.service.getUser(user)
146
components.registerAdapter(IRCClientFactoryFromService,
150
class UserStatusTree(resource.Resource):
152
template = """<html><head><title>Users</title></head><body>
160
def __init__(self, service):
161
resource.Resource.__init__(self)
162
self.service = service
164
def getChild(self, path, request):
168
return UserStatusXR(self.service)
170
return UserStatus(path, self.service)
172
def render_GET(self, request):
173
users = self.service.getUsers()
175
request.write(self.template % {'users': ''.join([
176
# Name should be quoted properly these uses.
177
'<li><a href="%s">%s</a></li>' % (name, name)
178
for name in users])})
180
users.addCallback(cbUsers)
182
log.err(err, "UserStatusTree failed")
184
users.addErrback(ebUsers)
185
return server.NOT_DONE_YET
187
components.registerAdapter(UserStatusTree, IFingerService, resource.IResource)
190
class UserStatus(resource.Resource):
192
template='''<html><head><title>%(title)s</title></head>
193
<body><h1>%(name)s</h1><p>%(status)s</p></body></html>'''
195
def __init__(self, user, service):
196
resource.Resource.__init__(self)
198
self.service = service
200
def render_GET(self, request):
201
status = self.service.getUser(self.user)
202
def cbStatus(status):
203
request.write(self.template % {
208
status.addCallback(cbStatus)
210
log.err(err, "UserStatus failed")
212
status.addErrback(ebStatus)
213
return server.NOT_DONE_YET
216
class UserStatusXR(xmlrpc.XMLRPC):
218
def __init__(self, service):
219
xmlrpc.XMLRPC.__init__(self)
220
self.service = service
222
def xmlrpc_getUser(self, user):
223
return self.service.getUser(user)
225
def xmlrpc_getUsers(self):
226
return self.service.getUsers()
229
class IPerspectiveFinger(Interface):
231
def remote_getUser(username):
232
"""return a user's status"""
234
def remote_getUsers():
235
"""return a user's status"""
237
class PerspectiveFingerFromService(pb.Root):
239
implements(IPerspectiveFinger)
241
def __init__(self, service):
242
self.service = service
244
def remote_getUser(self, username):
245
return self.service.getUser(username)
247
def remote_getUsers(self):
248
return self.service.getUsers()
250
components.registerAdapter(PerspectiveFingerFromService,
255
class FingerService(service.Service):
257
implements(IFingerService)
259
def __init__(self, filename):
260
self.filename = filename
265
for line in file(self.filename):
266
user, status = line.split(':', 1)
268
status = status.strip()
269
self.users[user] = status
270
self.call = reactor.callLater(30, self._read)
272
def getUser(self, user):
273
return defer.succeed(self.users.get(user, "No such user"))
276
return defer.succeed(self.users.keys())
279
class ServerContextFactory:
281
def getContext(self):
282
"""Create an SSL context.
284
This is a sample implementation that loads a certificate from a file
285
called 'server.pem'."""
286
ctx = SSL.Context(SSL.SSLv23_METHOD)
287
ctx.use_certificate_file('server.pem')
288
ctx.use_privatekey_file('server.pem')
296
def makeService(config):
298
s = service.MultiService()
299
f = FingerService(config['file'])
300
h = internet.TCPServer(1079, IFingerFactory(f))
301
h.setServiceParent(s)
304
# website on port 8000
305
r = resource.IResource(f)
306
r.templateDirectory = config['templates']
307
site = server.Site(r)
308
j = internet.TCPServer(8000, site)
309
j.setServiceParent(s)
312
# if config.get('ssl'):
313
# k = internet.SSLServer(443, site, ServerContextFactory())
314
# k.setServiceParent(s)
317
if config.has_key('ircnick'):
318
i = IIRCClientFactory(f)
319
i.nickname = config['ircnick']
320
ircserver = config['ircserver']
321
b = internet.TCPClient(ircserver, 6667, i)
322
b.setServiceParent(s)
324
# Pespective Broker on port 8889
325
if config.has_key('pbport'):
326
m = internet.TCPServer(
327
int(config['pbport']),
328
pb.PBServerFactory(IPerspectiveFinger(f)))
329
m.setServiceParent(s)