class IMConnection(object): INITIAL = 0 CONNECTING = 1 ACCEPTING = 2 CONNECTED = 3 CLOSED = 4 def __init__(self, reactor): self.reactor = reactor self.closeCallback = None self.inputCallback = None self.state = self.INITIAL self.connectOp = None self.stream = None def setCloseCallback(self, closeCallback): self.closeCallback = closeCallback def setInputCallback(self, inputCallback): self.inputCallback = inputCallback def shutdown(self, notify=False): if self.state == self.CLOSED: return if self.connectOp: self.connectOp.cancel() if self.stream: self.stream.close(deferred=True) self.state = self.CLOSED if notify and self.closeCallback: self.closeCallback() def connectTo(self, peerPubKey, callback=None): assert self.state == self.INITIAL self.connectCallback = callback self.state = self.CONNECTING self.peerPubKey = peerPubKey self.connectOp = tcpConnect(('127.0.0.1', env.port), self.reactor, self._onConnect) def acceptConnection(self, connectionId, callback=None): assert self.state == self.INITIAL self.connectCallback = callback self.state = self.ACCEPTING self.connectionId = connectionId self.connectOp = tcpConnect(('127.0.0.1', env.port), self.reactor, self._onConnect) def writeLine(self, line): self.stream.writeData(line + '\r\n') def _onConnect(self, connector): self.connectOp = None if connector.getError() != 0: self.shutdown(notity=True) return self.stream = TCPLineStream(connector.getSock(), self.reactor) self.stream.setCloseCallback(self._onClose) self.stream.setErrorCallback(self._onError) self.stream.setInputCallback(self._onInput) self.stream.enableRead(True) if self.state == self.CONNECTING: self.stream.writeData('CONNECTPUBKEY %s TextChat\r\n' % self.peerPubKey) else: assert self.state == self.ACCEPTING self.stream.writeData('ACCEPT %s\r\n' % self.connectionId) def _onClose(self): self.shutdown(notify=True) def _onError(self, err, errMsg): self._onClose() def _onInput(self, line): if self.state in (self.CONNECTING, self.ACCEPTING): if not line.startswith('OK'): self.shutdown(notify=True) return self.state = self.CONNECTED if self.connectCallback: self.connectCallback() return elif self.state == self.CONNECTED: self.inputCallback(line) else: self.shutdown(notify=True)
class IMInitializer(object): CONNECTING = 0 GETTINGKEY = 1 NOTIFYING = 2 REGISTERING = 3 REGISTERED = 4 CLOSED = 5 def __init__(self, reactor, callback=None): assert env.isContactAction or env.isIncoming self.reactor = reactor self.op = AsyncOp(callback, self._doCancel) self.state = self.CONNECTING self.connectOp = tcpConnect(('127.0.0.1', env.port), self.reactor, self._onConnect) self.stream = None def getOp(self): return self.op def _doCancel(self): if self.connectOp: self.connectOp.cancel() if self.stream: self.stream.close(deferred=True) self.state = self.CLOSED def _onConnect(self, connector): self.connectOp = None if connector.getError() != 0: self.op.notify(-1, None) return self.stream = TCPLineStream(connector.getSock(), self.reactor) self.stream.setCloseCallback(self._onClose) self.stream.setErrorCallback(self._onError) self.stream.setInputCallback(self._onInput) self.stream.enableRead(True) if env.isContactAction: self.stream.writeData('GETPUBKEY %s\r\n' % env.contactName) else: self.stream.writeData('GETINCOMINGPUBKEY %s\r\n' % env.connectionId) self.state = self.GETTINGKEY def _onClose(self): self._doCancel() self.op.notify(-1, None) def _onError(self, err, errMsg): self._onClose() def _onInput(self, line): if self.state == self.GETTINGKEY: if not line.startswith('OK'): self._doCancel() self.op.notify(-1, None) return self.pubKey = line.split()[1] self.state = self.REGISTERING self.listenerName = 'CSpaceIM-%s' % self.pubKey self.stream.writeData('REGISTERLISTENER %s\r\n' % self.listenerName) elif self.state == self.REGISTERING: if not line.startswith('OK'): self.state = self.NOTIFYING if env.isContactAction: msg = 'CONTACTACTION' else: msg = 'INCOMING %s' % env.connectionId self.stream.writeData('SENDLISTENER %s %s\r\n' % (self.listenerName, msg)) return self.state = self.REGISTERED self.stream.setCloseCallback(None) self.stream.setErrorCallback(None) self.stream.setInputCallback(None) self.op.notify(1, self) elif self.state == self.NOTIFYING: if not line.startswith('OK'): self._doCancel() self.op.notify(-1, None) return self._doCancel() self.op.notify(0, self) else: assert False
class MainWindow( QVBox ) : CONNECTING = 0 CONNECTED = 1 CLOSED = 2 def __init__( self, parent, reactor ) : QVBox.__init__( self, parent ) self.reactor = reactor self.setCaption( 'CSpace Test Applet' ) self.chatOutputView = QTextEdit( self ) self.chatOutputView.setReadOnly( True ) self.chatInputEdit = QLineEdit( self ) self.chatInputEdit.setFocus() self.state = self.CONNECTING self.chatInputEdit.setEnabled( False ) self.isClient = (cspaceEvent == 'CONTACTACTION') self.chatOutputView.append( self.isClient and 'Connecting to %s...' % cspaceContactNickName or 'Accepting connection from %s' % cspacePeerNickName ) addr = ('127.0.0.1',int(cspacePort)) self.tcpConnectOp = tcpConnect( addr, self.reactor, self._onTCPConnect ) self.stream = None def _onTCPConnect( self, connector ) : self.tcpConnectOp = None if connector.getError() != 0 : self.chatOutputView.append( 'ERROR' ) return self.sock = connector.getSock() self.stream = TCPLineStream( self.sock, self.reactor ) self.stream.setCloseCallback( self._onClose ) self.stream.setErrorCallback( self._onError ) self.stream.setInputCallback( self._onInput ) self.stream.enableRead( True ) if self.isClient : self.stream.writeData( 'CONNECT %s test\r\n' % cspaceContactNickName ) else : self.stream.writeData( 'ACCEPT %s\r\n' % cspaceConnectionId ) def shutdown( self ) : if self.tcpConnectOp : self.tcpConnectOp.cancel() if self.stream : self.stream.close() self.state = self.CLOSED def _onClose( self ) : self.chatOutputView.append( 'Connection closed' ) self.shutdown() def _onError( self, err, errMsg ) : self.chatOutputView.append( 'Connection error(%d): %s' % (err,errMsg) ) self.shutdown() def _onInput( self, line ) : if self.state == self.CONNECTING : if line.startswith('ERROR') : self.chatOutputView.append( 'Connection failed' ) return if line.startswith('OK') : self.chatOutputView.append( 'Connected' ) self.state = self.CONNECTED self.chatInputEdit.setEnabled( True ) self.chatInputEdit.setFocus() self.connect( self.chatInputEdit, SIGNAL('returnPressed()'), self._onChatInputReturnPressed ) elif self.state == self.CONNECTED : line = line.strip() self.chatOutputView.append( line ) def _onChatInputReturnPressed( self ) : if self.state != self.CONNECTED : return s = str(self.chatInputEdit.text()).strip() if not s : return self.chatOutputView.append( s ) self.stream.writeData( s + '\r\n' ) self.chatInputEdit.clear()
class IMConnection( object ) : INITIAL = 0 CONNECTING = 1 ACCEPTING = 2 CONNECTED = 3 CLOSED = 4 def __init__( self, reactor ) : self.reactor = reactor self.closeCallback = None self.inputCallback = None self.state = self.INITIAL self.connectOp = None self.stream = None def setCloseCallback( self, closeCallback ) : self.closeCallback = closeCallback def setInputCallback( self, inputCallback ) : self.inputCallback = inputCallback def shutdown( self, notify=False ) : if self.state == self.CLOSED : return if self.connectOp : self.connectOp.cancel() if self.stream : self.stream.close( deferred=True ) self.state = self.CLOSED if notify and self.closeCallback : self.closeCallback() def connectTo( self, peerPubKey, callback=None ) : assert self.state == self.INITIAL self.connectCallback = callback self.state = self.CONNECTING self.peerPubKey = peerPubKey self.connectOp = tcpConnect( ('127.0.0.1',env.port), self.reactor, self._onConnect ) def acceptConnection( self, connectionId, callback=None ) : assert self.state == self.INITIAL self.connectCallback = callback self.state = self.ACCEPTING self.connectionId = connectionId self.connectOp = tcpConnect( ('127.0.0.1',env.port), self.reactor, self._onConnect ) def writeLine( self, line ) : self.stream.writeData( line + '\r\n' ) def _onConnect( self, connector ) : self.connectOp = None if connector.getError() != 0 : self.shutdown( notity=True ) return self.stream = TCPLineStream( connector.getSock(), self.reactor ) self.stream.setCloseCallback( self._onClose ) self.stream.setErrorCallback( self._onError ) self.stream.setInputCallback( self._onInput ) self.stream.enableRead( True ) if self.state == self.CONNECTING : self.stream.writeData( 'CONNECTPUBKEY %s TextChat\r\n' % self.peerPubKey ) else : assert self.state == self.ACCEPTING self.stream.writeData( 'ACCEPT %s\r\n' % self.connectionId ) def _onClose( self ) : self.shutdown( notify=True ) def _onError( self, err, errMsg ) : self._onClose() def _onInput( self, line ) : if self.state in (self.CONNECTING,self.ACCEPTING) : if not line.startswith('OK') : self.shutdown( notify=True ) return self.state = self.CONNECTED if self.connectCallback : self.connectCallback() return elif self.state == self.CONNECTED : self.inputCallback( line ) else : self.shutdown( notify=True )
class IMInitializer( object ) : CONNECTING = 0 GETTINGKEY = 1 NOTIFYING = 2 REGISTERING = 3 REGISTERED = 4 CLOSED = 5 def __init__( self, reactor, callback=None ) : assert env.isContactAction or env.isIncoming self.reactor = reactor self.op = AsyncOp( callback, self._doCancel ) self.state = self.CONNECTING self.connectOp = tcpConnect( ('127.0.0.1',env.port), self.reactor, self._onConnect ) self.stream = None def getOp( self ) : return self.op def _doCancel( self ) : if self.connectOp : self.connectOp.cancel() if self.stream : self.stream.close( deferred=True ) self.state = self.CLOSED def _onConnect( self, connector ) : self.connectOp = None if connector.getError() != 0 : self.op.notify( -1, None ) return self.stream = TCPLineStream( connector.getSock(), self.reactor ) self.stream.setCloseCallback( self._onClose ) self.stream.setErrorCallback( self._onError ) self.stream.setInputCallback( self._onInput ) self.stream.enableRead( True ) if env.isContactAction : self.stream.writeData( 'GETPUBKEY %s\r\n' % env.contactName ) else : self.stream.writeData( 'GETINCOMINGPUBKEY %s\r\n' % env.connectionId ) self.state = self.GETTINGKEY def _onClose( self ) : self._doCancel() self.op.notify( -1, None ) def _onError( self, err, errMsg ) : self._onClose() def _onInput( self, line ) : if self.state == self.GETTINGKEY : if not line.startswith('OK') : self._doCancel() self.op.notify( -1, None ) return self.pubKey = line.split()[1] self.state = self.REGISTERING self.listenerName = 'CSpaceIM-%s' % self.pubKey self.stream.writeData( 'REGISTERLISTENER %s\r\n' % self.listenerName ) elif self.state == self.REGISTERING : if not line.startswith('OK') : self.state = self.NOTIFYING if env.isContactAction : msg = 'CONTACTACTION' else : msg = 'INCOMING %s' % env.connectionId self.stream.writeData( 'SENDLISTENER %s %s\r\n' % (self.listenerName,msg) ) return self.state = self.REGISTERED self.stream.setCloseCallback( None ) self.stream.setErrorCallback( None ) self.stream.setInputCallback( None ) self.op.notify( 1, self ) elif self.state == self.NOTIFYING : if not line.startswith('OK') : self._doCancel() self.op.notify( -1, None ) return self._doCancel() self.op.notify( 0, self ) else : assert False
class AppletConnection( object ) : DEFAULT = 0 CONNECTING = 1 WAITING_BRIDGE = 2 LISTENER = 3 CLOSED = 4 def __init__( self, sock, reactor, appletServer ) : self.reactor = reactor self.stream = TCPLineStream( sock, reactor ) self.appletServer = appletServer self.appletServer.appletConnections[self] = 1 self.session = appletServer.session self.incoming = appletServer.incoming self.state = self.DEFAULT self._writeData = self.stream.writeData rt = {} self.requestTable = rt rt['echo'] = self._doEcho rt['getcontacts'] = self._doGetContacts rt['getpubkey'] = self._doGetPubKey rt['getcontactpubkeys'] = self._doGetContactPubKeys rt['connect'] = self._doConnect rt['connectpubkey'] = self._doConnectPubKey rt['accept'] = self._doAccept rt['getincomingpubkey'] = self._doGetIncomingPubKey rt['registerlistener'] = self._doRegisterListener rt['sendlistener'] = self._doSendListener self.stream.setInputCallback( self._onInput ) self.stream.setCloseCallback( self._onClose ) self.stream.setErrorCallback( self._onError ) self.stream.enableRead( True ) def _setClosed( self ) : del self.appletServer.appletConnections[self] self.state = self.CLOSED def shutdown( self, deferred=False ) : if self.state == self.CONNECTING : self.connectOp.cancel() elif self.state == self.LISTENER : self.appletServer.unregisterListener( self.listenerName ) elif self.state == self.WAITING_BRIDGE : sslAbort( self.peerSSLConn ) self.stream.close( deferred ) self._setClosed() def _onClose( self ) : self.shutdown() def _onError( self, err, errMsg ) : self.shutdown() def _writeLine( self, line ) : self._writeData( line + '\r\n' ) def _writeWords( self, words ) : words = [wordEncode(w) for w in words] self._writeData( ' '.join(words) + '\r\n' ) def _writeError( self, msg ) : self._writeLine( 'ERROR %s' % msg ) def _writeResult( self, words ) : self._writeWords( ['OK'] + words ) def dispatchMessage( self, msg ) : assert self.state == self.LISTENER self._writeWords( ['MSG'] + msg ) def _doEcho( self, words ) : self._writeResult( words ) def _doGetContacts( self, words ) : if len(words) != 0 : self._writeError( 'Malformed request' ) return if not self.session.isOnline() : self._writeError( 'Not online' ) return names = self.session.getProfile().getContactNames() self._writeResult( names ) def _doGetPubKey( self, words ) : if len(words) > 1 : self._writeError( 'Malformed request' ) return if not self.session.isOnline() : self._writeError( 'Not online' ) return if len(words) == 0 : keyData = self.session.getProfile().rsaKey.toDER_PublicKey() self._writeResult( [hexEncode(keyData)] ) return contact = self.session.getProfile().getContactByName( words[0] ) if contact is None : self._writeError( 'Unknown contact' ) return self._writeResult( [hexEncode(contact.publicKeyData)] ) def _doGetContactPubKeys( self, words ) : if len(words) != 0 : self._writeError( 'Malformed request' ) return if not self.session.isOnline() : self._writeError( 'Not online' ) return out = [] profile = self.session.getProfile() for name in profile.getContactNames() : c = profile.getContactByName( name ) out.extend( [c.name,hexEncode(c.publicKeyData)] ) self._writeResult( out ) def _connectInternal( self, publicKey, service ) : def onWriteComplete() : self.stream.shutdown() sock = self.stream.getSock() self.appletServer.bridgeThread.threadQueue.postMessage( ('bridge',sock,self.peerSSLConn) ) self._setClosed() def onConnect( err, sslConn ) : if err < 0 : self._writeError( 'Connect failed' ) self.state = self.DEFAULT return self._writeResult( ['Connected'] ) self.peerSSLConn = sslConn self.state = self.WAITING_BRIDGE self.stream.enableRead( False ) self.stream.setWriteCompleteCallback( onWriteComplete ) self.connectOp = self.session.connectTo( publicKey, service, onConnect ) self.state = self.CONNECTING def _doConnect( self, words ) : if len(words) != 2 : self._writeError( 'Malformed request' ) return contactName, service = words if not self.session.isOnline() : self._writeError( 'Not online' ) return contact = self.session.getProfile().getContactByName( contactName ) if not contact : self._writeError( 'Unknown contact' ) return self._connectInternal( contact.publicKey, service ) def _doConnectPubKey( self, words ) : if len(words) != 2 : self._writeError( 'Malformed request' ) return hexPubKey, service = words if not self.session.isOnline() : self._writeError( 'Not online' ) return try : pubKeyData = hexDecode( hexPubKey ) pubKey = RSAKey() pubKey.fromDER_PublicKey( pubKeyData ) except (HexDecodeError,RSAError) : self._writeError( 'Malformed publickey' ) return self._connectInternal( pubKey, service ) def _doAccept( self, words ) : if len(words) != 1 : self._writeError( 'Malformed request' ) return connectionId = words[0] sslConn = self.incoming.acceptIncoming( connectionId ) if not sslConn : self._writeError( 'Invalid connection' ) return self._writeResult( ['Connected'] ) self.peerSSLConn = sslConn self.state = self.WAITING_BRIDGE self.stream.enableRead( False ) def onWriteComplete() : self.stream.shutdown() sock = self.stream.getSock() self.appletServer.bridgeThread.threadQueue.postMessage( ('bridge',sock,self.peerSSLConn) ) self._setClosed() self.stream.setWriteCompleteCallback( onWriteComplete ) def _doGetIncomingPubKey( self, words ) : if len(words) != 1 : self._writeError( 'Malformed request' ) return connectionId = words[0] peerKey = self.incoming.getPeerKey( connectionId ) if not peerKey : self._writeError( 'Invalid connection' ) return self._writeResult( [hexEncode(peerKey.toDER_PublicKey())] ) def _doRegisterListener( self, words ) : if len(words) != 1 : self._writeError( 'Malformed request' ) return listenerName = words[0] result = self.appletServer.registerListener( listenerName, self ) if not result : self._writeError( 'Listener already registered' ) return self.listenerName = listenerName self.state = self.LISTENER self._writeResult( ['Registered'] ) def _doSendListener( self, words ) : if len(words) <= 1 : self._writeError( 'Malformed request' ) return listenerName = words[0] listener = self.appletServer.getListener( listenerName ) if listener is None : self._writeError( 'No such listener' ) return listener.dispatchMessage( words[1:] ) self._writeResult( ['Sent'] ) def _onInput( self, line ) : assert self.state in (self.DEFAULT,self.CONNECTING,self.LISTENER) if self.state in (self.CONNECTING,self.LISTENER) : self._writeError( 'Junk received' ) self.shutdown( deferred=True ) return words = line.strip().split() if len(words) == 0 : return try : words = [wordDecode(w) for w in words] except WordDecodeError : self._writeError( 'Malformed request' ) return cmd = words[0].lower() handler = self.requestTable.get( cmd, None ) if not handler : self._writeError( 'Unknown request' ) return handler( words[1:] )
class MainWindow(QVBox): CONNECTING = 0 CONNECTED = 1 CLOSED = 2 def __init__(self, parent, reactor): QVBox.__init__(self, parent) self.reactor = reactor self.setCaption('CSpace Test Applet') self.chatOutputView = QTextEdit(self) self.chatOutputView.setReadOnly(True) self.chatInputEdit = QLineEdit(self) self.chatInputEdit.setFocus() self.state = self.CONNECTING self.chatInputEdit.setEnabled(False) self.isClient = (cspaceEvent == 'CONTACTACTION') self.chatOutputView.append( self.isClient and 'Connecting to %s...' % cspaceContactNickName or 'Accepting connection from %s' % cspacePeerNickName) addr = ('127.0.0.1', int(cspacePort)) self.tcpConnectOp = tcpConnect(addr, self.reactor, self._onTCPConnect) self.stream = None def _onTCPConnect(self, connector): self.tcpConnectOp = None if connector.getError() != 0: self.chatOutputView.append('ERROR') return self.sock = connector.getSock() self.stream = TCPLineStream(self.sock, self.reactor) self.stream.setCloseCallback(self._onClose) self.stream.setErrorCallback(self._onError) self.stream.setInputCallback(self._onInput) self.stream.enableRead(True) if self.isClient: self.stream.writeData('CONNECT %s test\r\n' % cspaceContactNickName) else: self.stream.writeData('ACCEPT %s\r\n' % cspaceConnectionId) def shutdown(self): if self.tcpConnectOp: self.tcpConnectOp.cancel() if self.stream: self.stream.close() self.state = self.CLOSED def _onClose(self): self.chatOutputView.append('Connection closed') self.shutdown() def _onError(self, err, errMsg): self.chatOutputView.append('Connection error(%d): %s' % (err, errMsg)) self.shutdown() def _onInput(self, line): if self.state == self.CONNECTING: if line.startswith('ERROR'): self.chatOutputView.append('Connection failed') return if line.startswith('OK'): self.chatOutputView.append('Connected') self.state = self.CONNECTED self.chatInputEdit.setEnabled(True) self.chatInputEdit.setFocus() self.connect(self.chatInputEdit, SIGNAL('returnPressed()'), self._onChatInputReturnPressed) elif self.state == self.CONNECTED: line = line.strip() self.chatOutputView.append(line) def _onChatInputReturnPressed(self): if self.state != self.CONNECTED: return s = str(self.chatInputEdit.text()).strip() if not s: return self.chatOutputView.append(s) self.stream.writeData(s + '\r\n') self.chatInputEdit.clear()