# chatola.py # a simple chat engine from twisted.internet.protocol import ClientCreator, Factory from twisted.protocols.basic import LineReceiver from twisted.python import failure from twisted.cred import portal, checkers, credentials, error from twisted.web import resource from twisted.internet import reactor, defer from nevow import renderer from nevow.tags import * from nevow import liveevil from nevow import guard class IMooCredentials(credentials.ICredentials): pass class MooCredentials: __implements__ = IMooCredentials, def __init__(self, server, port, username, password): self.server = server self.port = port self.username = username self.password = password class MooCredChecker: credentialInterfaces = (IMooCredentials, ) def requestAvatarId(self, credentials): try: port = int(credentials.port) except: return failure.Failure(error.UnauthorizedLogin("Port should be an integer.")) return ClientCreator( reactor, MooProtocol, credentials.username, credentials.password ).connectTCP( credentials.server, port ).addCallback( lambda proto: proto.finishedConnecting.addErrback( lambda reason: failure.Failure( error.UnauthorizedLogin("Login failed: %s" % reason)))) class MooGuard(guard.SessionWrapper): def getCredentials(self, request): arg = lambda S: request.args.get(S)[0] return MooCredentials( arg('server'), arg('port'), arg('user'), arg('password') ) class MooseRealm: """A simple implementor of cred's IRealm. The only interface we support web, this gives us the LoggedIn page. """ __implements__ = portal.IRealm def requestAvatar(self, avatarId, mind, *interfaces): if resource.IResource in interfaces: if avatarId is checkers.ANONYMOUS: return ( resource.IResource, Anonymous(), lambda: None) else: page = MooseClient(avatarId, mind) return resource.IResource, page, lambda: None raise NotImplementedError("Can't support that interface.") class MooProtocol(LineReceiver): def __init__(self, username, password): self.username = username self.password = password self.buffer = [] self.authenticated = False self.outputConduit = None self.finishedConnecting = defer.Deferred() def connectionLost(self, reason): if not self.authenticated: self.finishedConnecting.errback('Connection was dropped.') def lineReceived(self, line): if not self.authenticated: if line.startswith('The lag is'): self.transport.write("co %s %s\r\n" % (self.username, self.password)) if line.startswith('*** Connected ***'): self.authenticated = True self.finishedConnecting.callback(self) elif line.startswith('Either that player does not exist, or has a different password'): self.finishedConnecting.errback('Username or password incorrect') self.transport.loseConnection() if self.outputConduit is None: self.buffer.append(line) else: self.outputConduit.write(line) def outputConnected(self, output): self.outputConduit = output for line in self.buffer: output.write(line) self.buffer = [] class Anonymous(renderer.Renderer): def render_login(self, context, data): return form(action=guard.LOGIN_AVATAR)[ div[label["Server:"], input(type="text", name="server", value="pictwe.com")], div[label["Port:"], input(type="text", name="port", value="4242")], div[label["Username:"], input(type="text", name="user", value="fzzzy")], div[label["Password:"], input(type="password", name="password", value="")], input(type="submit", name="foo", value="bar") ] document = html[ head[ title["log in"] ], body[ render_login ] ] q = lambda it: '"%s"' % it class MooseClient(renderer.HTMLRenderer): templateFile = "Moose.html" client = None # The client will be set to an object which we can use to send and recieve data from the web browser. def __init__(self, connection, client, *args, **kw): renderer.HTMLRenderer.__init__(self, *args, **kw) self.client = client client.addNotification(lambda output: connection.outputConnected(self)) self.connection = connection def render_glue(self, context, data): return liveevil.glue def render_content(self, context, data): return context.tag[div(style="height: 100%")[xml(" ")]] def render_input(self, context, data): return form( style="margin: 1em;", onsubmit=liveevil.handler(self.onTextInput, "getInput();") )[ input(type="text", id="inputline", style="width: 100%") ] def onTextInput(self, client, text): self.connection.transport.write(text+'\r\n') self.client.sendScript("writeContent('