1
# Do everything properly, and componentize
2
from twisted.application import internet, service
3
from twisted.internet import protocol, reactor, defer, utils
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
8
from zope.interface import Interface, implements
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"""
26
class IFingerSetterService(Interface):
28
def setUser(user, status):
29
"""Set the user's status to something"""
32
return "Internal error in server"
34
class FingerProtocol(basic.LineReceiver):
36
def lineReceived(self, user):
37
d = self.factory.getUser(user)
38
d.addErrback(catchError)
39
def writeValue(value):
40
self.transport.write(value+'\r\n')
41
self.transport.loseConnection()
42
d.addCallback(writeValue)
45
class IFingerFactory(Interface):
48
"""Return a deferred returning a string"""
50
def buildProtocol(addr):
51
"""Return a protocol returning a string"""
54
class FingerFactoryFromService(protocol.ServerFactory):
56
implements(IFingerFactory)
58
protocol = FingerProtocol
60
def __init__(self, service):
61
self.service = service
63
def getUser(self, user):
64
return self.service.getUser(user)
66
components.registerAdapter(FingerFactoryFromService,
70
class FingerSetterProtocol(basic.LineReceiver):
72
def connectionMade(self):
75
def lineReceived(self, line):
76
self.lines.append(line)
78
def connectionLost(self, reason):
79
if len(self.lines) == 2:
80
self.factory.setUser(*self.lines)
83
class IFingerSetterFactory(Interface):
85
def setUser(user, status):
86
"""Return a deferred returning a string"""
88
def buildProtocol(addr):
89
"""Return a protocol returning a string"""
92
class FingerSetterFactoryFromService(protocol.ServerFactory):
94
implements(IFingerSetterFactory)
96
protocol = FingerSetterProtocol
98
def __init__(self, service):
99
self.service = service
101
def setUser(self, user, status):
102
self.service.setUser(user, status)
105
components.registerAdapter(FingerSetterFactoryFromService,
106
IFingerSetterService,
107
IFingerSetterFactory)
109
class IRCReplyBot(irc.IRCClient):
111
def connectionMade():
112
self.nickname = self.factory.nickname
113
irc.IRCClient.connectionMade(self)
115
def privmsg(self, user, channel, msg):
116
user = user.split('!')[0]
117
if self.nickname.lower() == channel.lower():
118
d = self.factory.getUser(msg)
119
d.addErrback(catchError)
120
d.addCallback(lambda m: "Status of %s: %s" % (msg, m))
121
d.addCallback(lambda m: self.msg(user, m))
124
class IIRCClientFactory(Interface):
131
"""Return a deferred returning a string"""
133
def buildProtocol(addr):
134
"""Return a protocol"""
137
class IRCClientFactoryFromService(protocol.ClientFactory):
139
implements(IIRCClientFactory)
141
protocol = IRCReplyBot
144
def __init__(self, service):
145
self.service = service
147
def getUser(self, user):
148
return self.service.getUser(user)
150
components.registerAdapter(IRCClientFactoryFromService,
154
class UserStatusTree(resource.Resource):
156
implements(resource.IResource)
158
def __init__(self, service):
159
resource.Resource.__init__(self)
160
self.service = service
161
self.putChild('RPC2', UserStatusXR(self.service))
163
def render_GET(self, request):
164
d = self.service.getUsers()
165
def formatUsers(users):
166
l = ['<li><a href="%s">%s</a></li>' % (user, user)
168
return '<ul>'+''.join(l)+'</ul>'
169
d.addCallback(formatUsers)
170
d.addCallback(request.write)
171
d.addCallback(lambda _: request.finish())
172
return server.NOT_DONE_YET
174
def getChild(self, path, request):
176
return UserStatusTree(self.service)
178
return UserStatus(path, self.service)
180
components.registerAdapter(UserStatusTree, IFingerService,
183
class UserStatus(resource.Resource):
185
def __init__(self, user, service):
186
resource.Resource.__init__(self)
188
self.service = service
190
def render_GET(self, request):
191
d = self.service.getUser(self.user)
192
d.addCallback(cgi.escape)
193
d.addCallback(lambda m:
194
'<h1>%s</h1>'%self.user+'<p>%s</p>'%m)
195
d.addCallback(request.write)
196
d.addCallback(lambda _: request.finish())
197
return server.NOT_DONE_YET
200
class UserStatusXR(xmlrpc.XMLRPC):
202
def __init__(self, service):
203
xmlrpc.XMLRPC.__init__(self)
204
self.service = service
206
def xmlrpc_getUser(self, user):
207
return self.service.getUser(user)
210
class FingerService(service.Service):
212
implements(IFingerService)
214
def __init__(self, filename):
215
self.filename = filename
221
for line in file(self.filename):
222
user, status = line.split(':', 1)
224
status = status.strip()
225
self.users[user] = status
226
self.call = reactor.callLater(30, self._read)
228
def getUser(self, user):
229
return defer.succeed(self.users.get(user, "No such user"))
232
return defer.succeed(self.users.keys())
234
# Yet another back-end
236
class LocalFingerService(service.Service):
238
implements(IFingerService)
240
def getUser(self, user):
243
entry = pwd.getpwnam(user)
245
return defer.succeed("No such user")
247
f = file(os.path.join(entry[5],'.plan'))
248
except (IOError, OSError):
249
return defer.succeed("No such user")
253
return defer.succeed(data)
256
return defer.succeed([])
259
application = service.Application('finger', uid=1, gid=1)
260
f = LocalFingerService()
261
serviceCollection = service.IServiceCollection(application)
262
internet.TCPServer(79, IFingerFactory(f)
263
).setServiceParent(serviceCollection)
264
internet.TCPServer(8000, server.Site(resource.IResource(f))
265
).setServiceParent(serviceCollection)
266
i = IIRCClientFactory(f)
267
i.nickname = 'fingerbot'
268
internet.TCPClient('irc.freenode.org', 6667, i
269
).setServiceParent(serviceCollection)