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
8
from zope.interface import Interface, implements
11
class IFingerService(Interface):
14
"""Return a deferred returning a string"""
17
"""Return a deferred returning a list of strings"""
19
class IFingerSetterService(Interface):
21
def setUser(user, status):
22
"""Set the user's status to something"""
25
return "Internal error in server"
27
class FingerProtocol(basic.LineReceiver):
29
def lineReceived(self, user):
30
d = self.factory.getUser(user)
31
d.addErrback(catchError)
32
def writeValue(value):
33
self.transport.write(value+'\r\n')
34
self.transport.loseConnection()
35
d.addCallback(writeValue)
38
class IFingerFactory(Interface):
41
"""Return a deferred returning a string"""
43
def buildProtocol(addr):
44
"""Return a protocol returning a string"""
47
class FingerFactoryFromService(protocol.ServerFactory):
49
implements(IFingerFactory)
51
protocol = FingerProtocol
53
def __init__(self, service):
54
self.service = service
56
def getUser(self, user):
57
return self.service.getUser(user)
59
components.registerAdapter(FingerFactoryFromService,
63
class FingerSetterProtocol(basic.LineReceiver):
65
def connectionMade(self):
68
def lineReceived(self, line):
69
self.lines.append(line)
71
def connectionLost(self, reason):
72
if len(self.lines) == 2:
73
self.factory.setUser(*self.lines)
76
class IFingerSetterFactory(Interface):
78
def setUser(user, status):
79
"""Return a deferred returning a string"""
81
def buildProtocol(addr):
82
"""Return a protocol returning a string"""
85
class FingerSetterFactoryFromService(protocol.ServerFactory):
87
implements(IFingerSetterFactory)
89
protocol = FingerSetterProtocol
91
def __init__(self, service):
92
self.service = service
94
def setUser(self, user, status):
95
self.service.setUser(user, status)
98
components.registerAdapter(FingerSetterFactoryFromService,
100
IFingerSetterFactory)
102
class IRCReplyBot(irc.IRCClient):
104
def connectionMade(self):
105
self.nickname = self.factory.nickname
106
irc.IRCClient.connectionMade(self)
108
def privmsg(self, user, channel, msg):
109
user = user.split('!')[0]
110
if self.nickname.lower() == channel.lower():
111
d = self.factory.getUser(msg)
112
d.addErrback(catchError)
113
d.addCallback(lambda m: "Status of %s: %s" % (msg, m))
114
d.addCallback(lambda m: self.msg(user, m))
117
class IIRCClientFactory(Interface):
124
"""Return a deferred returning a string"""
126
def buildProtocol(addr):
127
"""Return a protocol"""
130
class IRCClientFactoryFromService(protocol.ClientFactory):
132
implements(IIRCClientFactory)
134
protocol = IRCReplyBot
137
def __init__(self, service):
138
self.service = service
140
def getUser(self, user):
141
return self.service.getUser(user)
143
components.registerAdapter(IRCClientFactoryFromService,
147
class UserStatusTree(resource.Resource):
149
implements(resource.IResource)
151
def __init__(self, service):
152
resource.Resource.__init__(self)
153
self.service = service
154
self.putChild('RPC2', UserStatusXR(self.service))
156
def render_GET(self, request):
157
d = self.service.getUsers()
158
def formatUsers(users):
159
l = ['<li><a href="%s">%s</a></li>' % (user, user)
161
return '<ul>'+''.join(l)+'</ul>'
162
d.addCallback(formatUsers)
163
d.addCallback(request.write)
164
d.addCallback(lambda _: request.finish())
165
return server.NOT_DONE_YET
167
def getChild(self, path, request):
169
return UserStatusTree(self.service)
171
return UserStatus(path, self.service)
173
components.registerAdapter(UserStatusTree, IFingerService,
176
class UserStatus(resource.Resource):
178
def __init__(self, user, service):
179
resource.Resource.__init__(self)
181
self.service = service
183
def render_GET(self, request):
184
d = self.service.getUser(self.user)
185
d.addCallback(cgi.escape)
186
d.addCallback(lambda m:
187
'<h1>%s</h1>'%self.user+'<p>%s</p>'%m)
188
d.addCallback(request.write)
189
d.addCallback(lambda _: request.finish())
190
return server.NOT_DONE_YET
193
class UserStatusXR(xmlrpc.XMLRPC):
195
def __init__(self, service):
196
xmlrpc.XMLRPC.__init__(self)
197
self.service = service
199
def xmlrpc_getUser(self, user):
200
return self.service.getUser(user)
203
class FingerService(service.Service):
205
implements(IFingerService)
207
def __init__(self, filename):
208
self.filename = filename
214
for line in file(self.filename):
215
user, status = line.split(':', 1)
217
status = status.strip()
218
self.users[user] = status
219
self.call = reactor.callLater(30, self._read)
221
def getUser(self, user):
222
return defer.succeed(self.users.get(user, "No such user"))
225
return defer.succeed(self.users.keys())
228
application = service.Application('finger', uid=1, gid=1)
229
f = FingerService('/etc/users')
230
serviceCollection = service.IServiceCollection(application)
231
internet.TCPServer(79, IFingerFactory(f)
232
).setServiceParent(serviceCollection)
233
internet.TCPServer(8000, server.Site(resource.IResource(f))
234
).setServiceParent(serviceCollection)
235
i = IIRCClientFactory(f)
236
i.nickname = 'fingerbot'
237
internet.TCPClient('irc.freenode.org', 6667, i
238
).setServiceParent(serviceCollection)