1
# Do everything properly, and componentize
2
from twisted.application import internet, service
3
from twisted.internet import protocol, reactor, defer
4
from twisted.words.protocols import irc
5
from twisted.protocols import basic
6
from twisted.python import components
7
from twisted.web import resource, server, static, xmlrpc, microdom
8
from twisted.spread import pb
9
from zope.interface import Interface, implements
10
from OpenSSL import SSL
13
class IFingerService(Interface):
16
"""Return a deferred returning a string"""
19
"""Return a deferred returning a list of strings"""
21
class IFingerSetterService(Interface):
23
def setUser(user, status):
24
"""Set the user's status to something"""
27
return "Internal error in server"
29
class FingerProtocol(basic.LineReceiver):
31
def lineReceived(self, user):
32
d = self.factory.getUser(user)
33
d.addErrback(catchError)
34
def writeValue(value):
35
self.transport.write(value+'\r\n')
36
self.transport.loseConnection()
37
d.addCallback(writeValue)
40
class IFingerFactory(Interface):
43
"""Return a deferred returning a string"""
45
def buildProtocol(addr):
46
"""Return a protocol returning a string"""
49
class FingerFactoryFromService(protocol.ServerFactory):
51
implements(IFingerFactory)
53
protocol = FingerProtocol
55
def __init__(self, service):
56
self.service = service
58
def getUser(self, user):
59
return self.service.getUser(user)
61
components.registerAdapter(FingerFactoryFromService,
65
class FingerSetterProtocol(basic.LineReceiver):
67
def connectionMade(self):
70
def lineReceived(self, line):
71
self.lines.append(line)
73
def connectionLost(self, reason):
74
if len(self.lines) == 2:
75
self.factory.setUser(*self.lines)
78
class IFingerSetterFactory(Interface):
80
def setUser(user, status):
81
"""Return a deferred returning a string"""
83
def buildProtocol(addr):
84
"""Return a protocol returning a string"""
87
class FingerSetterFactoryFromService(protocol.ServerFactory):
89
implements(IFingerSetterFactory)
91
protocol = FingerSetterProtocol
93
def __init__(self, service):
94
self.service = service
96
def setUser(self, user, status):
97
self.service.setUser(user, status)
100
components.registerAdapter(FingerSetterFactoryFromService,
101
IFingerSetterService,
102
IFingerSetterFactory)
104
class IRCReplyBot(irc.IRCClient):
106
def connectionMade(self):
107
self.nickname = self.factory.nickname
108
irc.IRCClient.connectionMade(self)
110
def privmsg(self, user, channel, msg):
111
user = user.split('!')[0]
112
if self.nickname.lower() == channel.lower():
113
d = self.factory.getUser(msg)
114
d.addErrback(catchError)
115
d.addCallback(lambda m: "Status of %s: %s" % (msg, m))
116
d.addCallback(lambda m: self.msg(user, m))
119
class IIRCClientFactory(Interface):
126
"""Return a deferred returning a string"""
128
def buildProtocol(addr):
129
"""Return a protocol"""
132
class IRCClientFactoryFromService(protocol.ClientFactory):
134
implements(IIRCClientFactory)
136
protocol = IRCReplyBot
139
def __init__(self, service):
140
self.service = service
142
def getUser(self, user):
143
return self.service.getUser(user)
145
components.registerAdapter(IRCClientFactoryFromService,
149
class UserStatusTree(resource.Resource):
151
def __init__(self, service):
152
resource.Resource.__init__(self)
155
# add a specific child for the path "RPC2"
156
self.putChild("RPC2", UserStatusXR(self.service))
158
# need to do this for resources at the root of the site
159
self.putChild("", self)
161
def _cb_render_GET(self, users, request):
162
userOutput = ''.join(["<li><a href=\"%s\">%s</a></li>" % (user, user)
165
<html><head><title>Users</title></head><body>
169
</ul></body></html>""" % userOutput)
172
def render_GET(self, request):
173
d = self.service.getUsers()
174
d.addCallback(self._cb_render_GET, request)
176
# signal that the rendering is not complete
177
return server.NOT_DONE_YET
179
def getChild(self, path, request):
180
return UserStatus(user=path, service=self.service)
182
components.registerAdapter(UserStatusTree, IFingerService, resource.IResource)
184
class UserStatus(resource.Resource):
186
def __init__(self, user, service):
187
resource.Resource.__init__(self)
189
self.service = service
191
def _cb_render_GET(self, status, request):
192
request.write("""<html><head><title>%s</title></head>
195
</body></html>""" % (self.user, self.user, status))
198
def render_GET(self, request):
199
d = self.service.getUser(self.user)
200
d.addCallback(self._cb_render_GET, request)
202
# signal that the rendering is not complete
203
return server.NOT_DONE_YET
205
class UserStatusXR(xmlrpc.XMLRPC):
207
def __init__(self, service):
208
xmlrpc.XMLRPC.__init__(self)
209
self.service = service
211
def xmlrpc_getUser(self, user):
212
return self.service.getUser(user)
214
def xmlrpc_getUsers(self):
215
return self.service.getUsers()
218
class IPerspectiveFinger(Interface):
220
def remote_getUser(username):
221
"""return a user's status"""
223
def remote_getUsers():
224
"""return a user's status"""
226
class PerspectiveFingerFromService(pb.Root):
228
implements(IPerspectiveFinger)
230
def __init__(self, service):
231
self.service = service
233
def remote_getUser(self, username):
234
return self.service.getUser(username)
236
def remote_getUsers(self):
237
return self.service.getUsers()
239
components.registerAdapter(PerspectiveFingerFromService,
244
class FingerService(service.Service):
246
implements(IFingerService)
248
def __init__(self, filename):
249
self.filename = filename
255
for line in file(self.filename):
256
user, status = line.split(':', 1)
258
status = status.strip()
259
self.users[user] = status
260
self.call = reactor.callLater(30, self._read)
262
def getUser(self, user):
263
return defer.succeed(self.users.get(user, "No such user"))
266
return defer.succeed(self.users.keys())
269
class ServerContextFactory:
271
def getContext(self):
272
"""Create an SSL context.
274
This is a sample implementation that loads a certificate from a file
275
called 'server.pem'."""
276
ctx = SSL.Context(SSL.SSLv23_METHOD)
277
ctx.use_certificate_file('server.pem')
278
ctx.use_privatekey_file('server.pem')
282
application = service.Application('finger', uid=1, gid=1)
283
f = FingerService('/etc/users')
284
serviceCollection = service.IServiceCollection(application)
285
internet.TCPServer(79, IFingerFactory(f)
286
).setServiceParent(serviceCollection)
287
site = server.Site(resource.IResource(f))
288
internet.TCPServer(8000, site
289
).setServiceParent(serviceCollection)
290
internet.SSLServer(443, site, ServerContextFactory()
291
).setServiceParent(serviceCollection)
292
i = IIRCClientFactory(f)
293
i.nickname = 'fingerbot'
294
internet.TCPClient('irc.freenode.org', 6667, i
295
).setServiceParent(serviceCollection)
296
internet.TCPServer(8889, pb.PBServerFactory(IPerspectiveFinger(f))
297
).setServiceParent(serviceCollection)