Example #1
0
 def _onAccept(self, err, sock):
     if err < 0:
         self._setError('Error accepting connection from %s.' %
                        env.displayName)
         return
     self.rpcConn = RPCConnection(sock, self.reactor)
     self.fileClient = FileClient(self.rpcConn)
     self._setStatus('Fetching file list from %s...' % env.displayName)
     self.fileClient.callList('/', self._onList)
Example #2
0
 def onTCPConnect( connector ) :
     self.connectOp = None
     if connector.getError() != 0 :
         self.state = self.CLOSED
         connectCallback( False )
         return
     self.rpcConn = RPCConnection( connector.getSock(), self.reactor )
     self.rpcConn.setCloseCallback( self._onClose )
     self.state = self.CONNECTED
     connectCallback( True )
Example #3
0
 def __init__( self, sock, reactor, routerState ) :
     self.rpcConn = RPCConnection( sock, reactor )
     self.reactor = reactor
     self.routerState = routerState
     self.rpcConn.setCloseCallback( self.close )
     self.rpcConn.setRequestCallback( self._onRequest )
     self.requestTable = {}
     for msg in 'Ping Register Connect Accept'.split() :
         self.requestTable[msg] = getattr( self, '_do%s' % msg )
     self.routerState.handlers[self] = 1
     self.state = self.INITIAL
     self._lastActiveTime = time()
Example #4
0
    def _doOfferFiles(self, sock):
        self._setStatus('Sending request ...')
        self.state = self.OFFERINGFILES
        fileList = []
        for row in range(self.ui.fileList.count()):
            item = self.ui.fileList.item(row)
            fileList.append(self.fileItems[item][0])
        self.rpcConn = RPCConnection(sock, self.reactor)
        self.switchboard = RPCSwitchboard(self.rpcConn)
        self.fs = FlatFS(fileList)
        self.fileServer = FileServer(self.fs, self.switchboard)

        pending = {}
        for i, f in enumerate(fileList):
            pending[os.path.split(f)[1].lower()] = i

        def onClose():
            if pending:
                self._setError('Disconnected.')
            else:
                self._setStatus('Completed.')

        def onTransferStatus(payload):
            if type(payload) is not ListType: return
            if len(payload) != 4: return
            for x in payload:
                if type(x) is not IntType: return
                if x < 0: return
            fileId, numFiles, transferred, fileSize = payload
            if numFiles != len(fileList): return
            if not (1 <= fileId <= numFiles): return
            if transferred > fileSize: return
            fname = os.path.split(fileList[fileId - 1])[1]
            lfname = fname.lower()
            pos = pending.get(lfname, None)
            if pos is None: return
            if transferred == fileSize:
                percent = 100
                del pending[lfname]
            else:
                percent = transferred * 100 / fileSize
            self._setStatus('Sending file (%d/%d): %s (%d%%)' %
                            (pos + 1, len(fileList), fname, percent))

        self.switchboard.addOnewayAgent('TransferStatus', onTransferStatus)
        self.rpcConn.setCloseCallback(onClose)
Example #5
0
 def onTCPConnect( connector ) :
     obj.op = None
     if connector.getError() != 0 :
         onError()
         return
     obj.rpcConn = RPCConnection( connector.getSock(), reactor )
     obj.rpcConn.setCloseCallback( onError )
     obj.op = _doRPCCall( obj.rpcConn, 'Connect', [routerId], onRouterConnect )
Example #6
0
 def _onAccept( self, err, sock ) :
     if err < 0 :
         self._setError( 'Error accepting connection from %s.' % env.displayName )
         return
     self.rpcConn = RPCConnection( sock, self.reactor )
     self.fileClient = FileClient( self.rpcConn )
     self._setStatus( 'Fetching file list from %s...' % env.displayName )
     self.fileClient.callList( '/', self._onList )
Example #7
0
 def __init__( self, sock, reactor, routerState ) :
     self.rpcConn = RPCConnection( sock, reactor )
     self.reactor = reactor
     self.routerState = routerState
     self.rpcConn.setCloseCallback( self.close )
     self.rpcConn.setRequestCallback( self._onRequest )
     self.requestTable = {}
     for msg in 'Ping Register Connect Accept'.split() :
         self.requestTable[msg] = getattr( self, '_do%s' % msg )
     self.routerState.handlers[self] = 1
     self.state = self.INITIAL
     self._lastActiveTime = time()
Example #8
0
    def _doOfferFiles( self, sock ) :
        self._setStatus( 'Sending request ...' )
        self.state = self.OFFERINGFILES
        fileList = []
        for row in range(self.ui.fileList.count()) :
            item = self.ui.fileList.item( row )
            fileList.append( self.fileItems[item][0] )
        self.rpcConn = RPCConnection( sock, self.reactor )
        self.switchboard = RPCSwitchboard( self.rpcConn )
        self.fs = FlatFS( fileList )
        self.fileServer = FileServer( self.fs, self.switchboard )

        pending = {}
        for i,f in enumerate(fileList) :
            pending[os.path.split(f)[1].lower()] = i
        def onClose() :
            if pending :
                self._setError( 'Disconnected.' )
            else :
                self._setStatus( 'Completed.' )
        def onTransferStatus( payload ) :
            if type(payload) is not ListType : return
            if len(payload) != 4 : return
            for x in payload :
                if type(x) is not IntType : return
                if x < 0 : return
            fileId,numFiles,transferred,fileSize = payload
            if numFiles != len(fileList) : return
            if not (1 <= fileId <= numFiles) : return
            if transferred > fileSize : return
            fname = os.path.split(fileList[fileId-1])[1]
            lfname = fname.lower()
            pos = pending.get( lfname, None )
            if pos is None : return
            if transferred == fileSize :
                percent = 100
                del pending[lfname]
            else :
                percent = transferred*100 / fileSize
            self._setStatus( 'Sending file (%d/%d): %s (%d%%)'
                    % (pos+1,len(fileList),fname,percent) )
        self.switchboard.addOnewayAgent( 'TransferStatus', onTransferStatus )
        self.rpcConn.setCloseCallback( onClose )
Example #9
0
class FileReceiverWindow(QWidget, FlashWindow):
    def __init__(self, reactor):
        QWidget.__init__(self)
        FlashWindow.__init__(self, reactor)
        self.ui = Ui_FileReceiverWindow()
        self.ui.setupUi(self)
        self.reactor = reactor
        self.setWindowTitle(env.displayName + ' - ' + str(self.windowTitle()))
        self.connect(self.ui.acceptButton, SIGNAL('clicked()'),
                     self._onAcceptFiles)
        self.connect(self.ui.cancelButton, SIGNAL('clicked()'), self.close)
        tcpConnect(('127.0.0.1', env.port), self.reactor, self._onConnect)
        self._setStatus('Connecting to CSpace...')
        self.disconnected = False

    def _setStatus(self, text, isError=False):
        lines = text.split('\n')
        text = '<b>%s</b>' % '<br/>'.join(lines)
        if isError:
            text = '<font color=red>%s</font>' % text
        self.ui.status.setText(text)

    def _setError(self, text):
        self._setStatus(text, True)
        self.ui.cancelButton.setText('&Close')

    def _onConnect(self, connector):
        if connector.getError() != 0:
            self._setError('Error connecting to CSpace.')
            return
        sock = connector.getSock()
        self._setStatus('Accepting connection from %s.' % env.displayName)
        CSpaceAcceptor(sock, env.connectionId, self.reactor, self._onAccept)

    def _onAccept(self, err, sock):
        if err < 0:
            self._setError('Error accepting connection from %s.' %
                           env.displayName)
            return
        self.rpcConn = RPCConnection(sock, self.reactor)
        self.fileClient = FileClient(self.rpcConn)
        self._setStatus('Fetching file list from %s...' % env.displayName)
        self.fileClient.callList('/', self._onList)

    def _onList(self, err, result):
        if err != 0:
            self._setError('Error fetching file list from %s.' %
                           env.displayName)
            return
        self.files = []
        for x in result:
            if not x.endswith('/'):
                self.files.append(x)
                self.ui.fileList.addItem(x)
        self._setStatus(('%s is sending the following files.\n' %
                         env.displayName) + 'Would you like to accept?')
        self.ui.acceptButton.setEnabled(True)
        self.rpcConn.setCloseCallback(self._onClose)
        self.flash()

    def _onClose(self):
        self.disconnected = True
        self._setError('Disconnected.')
        self.ui.acceptButton.setEnabled(False)

    def _chooseTargetDir(self):
        defaultDir = os.path.expanduser('~/Desktop')
        if not os.path.isdir(defaultDir):
            defaultDir = QString()
        dir = localSettings().getString('Settings/FileReceiverSaveDir')
        if (not dir) or (not os.path.isdir(dir)):
            dir = defaultDir
        while True:
            dir = QFileDialog.getExistingDirectory(
                self, 'Choose directory to save the file(s)', dir)
            if dir.isEmpty(): return None
            dir = str(dir)
            existing = []
            for f in self.files:
                if os.path.exists(os.path.join(dir, f)): existing.append(f)
            if not existing: break
            msg = 'The following file(s) already exist in\n%s.\nWould you like to overwrite?\n%s' % (
                dir, '\n'.join(existing))
            result = QMessageBox.question(
                self, 'Overwrite Prompt', msg, QMessageBox.Yes, QMessageBox.No,
                QMessageBox.Cancel | QMessageBox.Escape)
            if result == QMessageBox.Yes: break
            if result == QMessageBox.No: continue
            assert result == QMessageBox.Cancel
            return None
        localSettings().setString('Settings/FileReceiverSaveDir', dir)
        return dir

    def _onAcceptFiles(self):
        self.ui.acceptButton.setEnabled(False)
        targetDir = self._chooseTargetDir()
        if self.disconnected: return
        if not targetDir:
            self.ui.acceptButton.setEnabled(True)
            return
        self.targetDir = targetDir
        self.curFileId = 0
        self.rpcConn.setCloseCallback(None)
        self.statusStub = RPCStub(self.rpcConn, 'TransferStatus')
        self._doTransfer()

    def _doTransfer(self):
        if self.curFileId >= len(self.files):
            self._setStatus('Completed.')
            self.ui.cancelButton.setText('&Close')
            self.rpcConn.close(deferred=True)
            return
        fname = self.files[self.curFileId]
        self.curFileId += 1
        self._setStatus('Receiving file(%d/%d): %s' %
                        (self.curFileId, len(self.files), fname))
        remotePath = '/' + fname
        localPath = os.path.join(self.targetDir, fname)
        try:
            self.fetcher = FileFetcher(self.fileClient, remotePath, localPath,
                                       self._onTransfer)
        except (OSError, IOError), e:
            self._setError('Error saving file: %s' % localPath)
            return
Example #10
0
class RouterServerHandler( object ) :
    (INITIAL,REGISTERED,CONNECTING,CLOSED) = range(4)
    def __init__( self, sock, reactor, routerState ) :
        self.rpcConn = RPCConnection( sock, reactor )
        self.reactor = reactor
        self.routerState = routerState
        self.rpcConn.setCloseCallback( self.close )
        self.rpcConn.setRequestCallback( self._onRequest )
        self.requestTable = {}
        for msg in 'Ping Register Connect Accept'.split() :
            self.requestTable[msg] = getattr( self, '_do%s' % msg )
        self.routerState.handlers[self] = 1
        self.state = self.INITIAL
        self._lastActiveTime = time()

    def close( self ) :
        self.rpcConn.close()
        del self.routerState.handlers[self]
        if self.state == self.REGISTERED :
            del self.routerState.registered[self.routerId]
        elif self.state == self.CONNECTING :
            del self.routerState.connecting[self.connectionId]
        self.state = self.CLOSED

    def lastActiveTime( self ) :
        return self._lastActiveTime

    def sendIncoming( self, connectionId ) :
        assert self.state == self.REGISTERED
        self.rpcConn.oneway( connectionId )

    def _onRequest( self, payload, ctx ) :
        self._lastActiveTime = time()
        try :
            assert type(payload) is list
            assert len(payload) >= 1
            msg = payload.pop( 0 )
            assert type(msg) is str
            handler = self.requestTable.get( msg )
            assert handler is not None
        except :
            ctx.response( [-1] )
            return
        handler( payload, ctx )

    def _doPing( self, args, ctx ) :
        try :
            peerAddr = self.rpcConn.getSock().getpeername()
        except sock_error :
            ctx.response( [-1] )
            return
        ctx.response( (0,peerAddr) )

    def _doRegister( self, args, ctx ) :
        try :
            assert self.state == self.INITIAL
            assert len(args) == 0
        except :
            ctx.response( (-1,'') )
            return
        while True :
            routerId = rand_bytes( 20 )
            if routerId not in self.routerState.registered : break
        self.routerId = routerId
        self.state = self.REGISTERED
        self.routerState.registered[routerId] = self
        ctx.response( (0,self.routerId) )

    def _doConnect( self, args, ctx ) :
        try :
            assert self.state == self.INITIAL
            assert len(args) == 1
            routerId = args[0]
            assert type(routerId) is str
            handler = self.routerState.registered.get( routerId )
            assert handler is not None
        except :
            ctx.response( [-1] )
            return
        while True :
            connectionId = rand_bytes( 20 )
            if connectionId not in self.routerState.connecting : break
        self.connectionId = connectionId
        self.connectCtx = ctx
        self.state = self.CONNECTING
        self.routerState.connecting[connectionId] = self
        handler.sendIncoming( connectionId )

    def finishConnect( self ) :
        assert self.state == self.CONNECTING
        self.connectCtx.response( [0] )
        del self.routerState.connecting[self.connectionId]
        del self.routerState.handlers[self]
        sock = self.rpcConn.getSock()
        pendingWrite = self.rpcConn.getPendingWrite()
        self.rpcConn.shutdown()
        self.state = self.CLOSED
        return (sock,pendingWrite)

    def _doAccept( self, args, ctx ) :
        try :
            assert self.state == self.INITIAL
            assert len(args) == 1
            connectionId = args[0]
            assert type(connectionId) is str
            handler = self.routerState.connecting.get( connectionId )
            assert handler is not None
        except :
            ctx.response( [-1] )
            return
        sock1,pendingWrite1 = handler.finishConnect()
        ctx.response( [0] )
        del self.routerState.handlers[self]
        sock2 = self.rpcConn.getSock()
        pendingWrite2 = self.rpcConn.getPendingWrite()
        self.rpcConn.shutdown()
        self.state = self.CLOSED
        BridgeInitiator( sock1, pendingWrite1, sock2, pendingWrite2, self.reactor, self.routerState )
Example #11
0
class FileSenderWindow( QWidget ) :
    SELECTINGFILES = 0
    CONNECTINGCSPACE = 1
    CONNECTINGUSER = 2
    OFFERINGFILES = 3
    def __init__( self, reactor ) :
        QWidget.__init__( self )
        self.ui = Ui_FileSenderWindow()
        self.ui.setupUi( self )
        self.reactor = reactor
        self._setStatus( 'Drag and drop files to be sent...' )
        self.setWindowTitle( env.contactName + ' - ' + str(self.windowTitle()) )
        self.setAcceptDrops( True )
        self.files = {}
        self.fileItems = {}
        self.connect( self.ui.fileList, SIGNAL('itemSelectionChanged()'), self._onFileSelectionChanged )
        self.connect( self.ui.addFilesButton, SIGNAL('clicked()'), self._onAddClicked )
        self.connect( self.ui.removeFilesButton, SIGNAL('clicked()'), self._onRemoveClicked )
        self.connect( self.ui.removeAllButton, SIGNAL('clicked()'), self._onRemoveAllClicked )
        self.connect( self.ui.sendFilesButton, SIGNAL('clicked()'), self._onSendFilesClicked )
        self.connect( self.ui.closeButton, SIGNAL('clicked()'), self.close )
        self.state = self.SELECTINGFILES

    def _setStatus( self, text, isError=False ) :
        lines = text.split( '\n' )
        text = '<b>%s</b>' % '<br>'.join(lines)
        if isError :
            text = '<font color=red>%s</font>' % text
        self.ui.status.setText( text )

    def _setError( self, text ) :
        self._setStatus( text, True )

    def _removeFile( self, item ) :
        info = self.fileItems.pop( item )
        self.ui.fileList.takeItem( self.ui.fileList.row(item) )
        fname = os.path.split( info[0] )[1]
        del self.files[fname.lower()]
        if not self.files :
            self.ui.sendFilesButton.setEnabled( False )
            self.ui.removeAllButton.setEnabled( False )

    def _addFile( self, f ) :
        if not os.path.isfile(f) : return False
        fname = os.path.split(f)[1]
        k = fname.lower()
        info = self.files.get( k, None )
        if info is not None :
            self._removeFile( info[1] )
        item = QListWidgetItem( fname, self.ui.fileList )
        info = [f,item]
        self.files[k] = info
        self.fileItems[item] = info
        self.ui.sendFilesButton.setEnabled( True )
        self.ui.removeAllButton.setEnabled( True )

    def _onFileSelectionChanged( self ) :
        if self.state != self.SELECTINGFILES : return
        selectCount = 0
        for item in self.fileItems.keys() :
            if self.ui.fileList.isItemSelected(item) :
                selectCount += 1
        self.ui.removeFilesButton.setEnabled( selectCount > 0 )

    def dragEnterEvent( self, ev ) :
        if self.state != self.SELECTINGFILES :
            return
        mimeData = ev.mimeData()
        if mimeData.hasUrls() :
            isLocal = True
            for url in mimeData.urls() :
                if url.toLocalFile().isEmpty() :
                    isLocal = False
            if isLocal :
                ev.acceptProposedAction()

    def dropEvent( self, ev ) :
        if self.state != self.SELECTINGFILES : return
        mimeData = ev.mimeData()
        if mimeData.hasUrls() :
            for url in mimeData.urls() :
                f = url.toLocalFile()
                if not f.isEmpty() :
                    self._addFile( str(f) )
            self._onFileSelectionChanged()
            ev.acceptProposedAction()

    def _onAddClicked( self ) :
        defaultDir = os.path.expanduser( '~/Desktop' )
        if not os.path.isdir(defaultDir) :
            defaultDir = ''
        openDir = localSettings().getString( 'Settings/FileSenderOpenDir' )
        if (not openDir) or (not os.path.isdir(openDir)) :
            openDir = defaultDir
        fileList = QFileDialog.getOpenFileNames( self, 'Select file(s) to add...', openDir )
        for f in fileList :
            self._addFile( str(f) )
        if len(fileList) :
            openDir = os.path.split( str(fileList[0]) )[0]
            localSettings().setString( 'Settings/FileSenderOpenDir', openDir )
        self._onFileSelectionChanged()

    def _onRemoveClicked( self ) :
        selItems = [ i for i in self.fileItems.keys() if self.ui.fileList.isItemSelected(i) ]
        for item in selItems :
            self._removeFile( item )
        self._onFileSelectionChanged()

    def _onRemoveAllClicked( self ) :
        for item in self.fileItems.keys() :
            self._removeFile( item )
        self._onFileSelectionChanged()

    def _onSendFilesClicked( self ) :
        self.setAcceptDrops( False )
        self.ui.fileList.clearSelection()
        self.ui.fileList.setSelectionMode( QAbstractItemView.NoSelection )
        self.ui.addFilesButton.setEnabled( False )
        self.ui.removeFilesButton.setEnabled( False )
        self.ui.removeAllButton.setEnabled( False )
        self.ui.sendFilesButton.setEnabled( False )
        self._doConnect()

    def _doConnect( self ) :
        def onConnect( connector ) :
            self.connectOp = None
            if connector.getError() != 0 :
                self._setError( 'Unable to connect to CSpace.' )
                return
            self._doConnectUser( connector.getSock() )
        self.connectOp = tcpConnect( ('127.0.0.1',env.port), self.reactor, onConnect )
        self._setStatus( 'Connecting to CSpace...' )
        self.state = self.CONNECTINGCSPACE

    def _doConnectUser( self, sock ) :
        self._setStatus( 'Connecting to %s...' % env.contactName )
        self.state = self.CONNECTINGUSER
        def onConnect( err, sock ) :
            if err < 0 :
                self._setError( 'Error connecting to %s.' % env.contactName )
                return
            self._doOfferFiles( sock )
        connector = CSpaceConnector( sock, env.contactName, 'FileTransfer',
                self.reactor, onConnect )
        self.connectOp = connector.getOp()

    def _doOfferFiles( self, sock ) :
        self._setStatus( 'Sending request ...' )
        self.state = self.OFFERINGFILES
        fileList = []
        for row in range(self.ui.fileList.count()) :
            item = self.ui.fileList.item( row )
            fileList.append( self.fileItems[item][0] )
        self.rpcConn = RPCConnection( sock, self.reactor )
        self.switchboard = RPCSwitchboard( self.rpcConn )
        self.fs = FlatFS( fileList )
        self.fileServer = FileServer( self.fs, self.switchboard )

        pending = {}
        for i,f in enumerate(fileList) :
            pending[os.path.split(f)[1].lower()] = i
        def onClose() :
            if pending :
                self._setError( 'Disconnected.' )
            else :
                self._setStatus( 'Completed.' )
        def onTransferStatus( payload ) :
            if type(payload) is not ListType : return
            if len(payload) != 4 : return
            for x in payload :
                if type(x) is not IntType : return
                if x < 0 : return
            fileId,numFiles,transferred,fileSize = payload
            if numFiles != len(fileList) : return
            if not (1 <= fileId <= numFiles) : return
            if transferred > fileSize : return
            fname = os.path.split(fileList[fileId-1])[1]
            lfname = fname.lower()
            pos = pending.get( lfname, None )
            if pos is None : return
            if transferred == fileSize :
                percent = 100
                del pending[lfname]
            else :
                percent = transferred*100 / fileSize
            self._setStatus( 'Sending file (%d/%d): %s (%d%%)'
                    % (pos+1,len(fileList),fname,percent) )
        self.switchboard.addOnewayAgent( 'TransferStatus', onTransferStatus )
        self.rpcConn.setCloseCallback( onClose )

    def closeEvent( self, ev ) :
        ev.accept()
        delaygc( self )
Example #12
0
class FileSenderWindow(QWidget):
    SELECTINGFILES = 0
    CONNECTINGCSPACE = 1
    CONNECTINGUSER = 2
    OFFERINGFILES = 3

    def __init__(self, reactor):
        QWidget.__init__(self)
        self.ui = Ui_FileSenderWindow()
        self.ui.setupUi(self)
        self.reactor = reactor
        self._setStatus('Drag and drop files to be sent...')
        self.setWindowTitle(env.contactName + ' - ' + str(self.windowTitle()))
        self.setAcceptDrops(True)
        self.files = {}
        self.fileItems = {}
        self.connect(self.ui.fileList, SIGNAL('itemSelectionChanged()'),
                     self._onFileSelectionChanged)
        self.connect(self.ui.addFilesButton, SIGNAL('clicked()'),
                     self._onAddClicked)
        self.connect(self.ui.removeFilesButton, SIGNAL('clicked()'),
                     self._onRemoveClicked)
        self.connect(self.ui.removeAllButton, SIGNAL('clicked()'),
                     self._onRemoveAllClicked)
        self.connect(self.ui.sendFilesButton, SIGNAL('clicked()'),
                     self._onSendFilesClicked)
        self.connect(self.ui.closeButton, SIGNAL('clicked()'), self.close)
        self.state = self.SELECTINGFILES

    def _setStatus(self, text, isError=False):
        lines = text.split('\n')
        text = '<b>%s</b>' % '<br>'.join(lines)
        if isError:
            text = '<font color=red>%s</font>' % text
        self.ui.status.setText(text)

    def _setError(self, text):
        self._setStatus(text, True)

    def _removeFile(self, item):
        info = self.fileItems.pop(item)
        self.ui.fileList.takeItem(self.ui.fileList.row(item))
        fname = os.path.split(info[0])[1]
        del self.files[fname.lower()]
        if not self.files:
            self.ui.sendFilesButton.setEnabled(False)
            self.ui.removeAllButton.setEnabled(False)

    def _addFile(self, f):
        if not os.path.isfile(f): return False
        fname = os.path.split(f)[1]
        k = fname.lower()
        info = self.files.get(k, None)
        if info is not None:
            self._removeFile(info[1])
        item = QListWidgetItem(fname, self.ui.fileList)
        info = [f, item]
        self.files[k] = info
        self.fileItems[item] = info
        self.ui.sendFilesButton.setEnabled(True)
        self.ui.removeAllButton.setEnabled(True)

    def _onFileSelectionChanged(self):
        if self.state != self.SELECTINGFILES: return
        selectCount = 0
        for item in self.fileItems.keys():
            if self.ui.fileList.isItemSelected(item):
                selectCount += 1
        self.ui.removeFilesButton.setEnabled(selectCount > 0)

    def dragEnterEvent(self, ev):
        if self.state != self.SELECTINGFILES:
            return
        mimeData = ev.mimeData()
        if mimeData.hasUrls():
            isLocal = True
            for url in mimeData.urls():
                if url.toLocalFile().isEmpty():
                    isLocal = False
            if isLocal:
                ev.acceptProposedAction()

    def dropEvent(self, ev):
        if self.state != self.SELECTINGFILES: return
        mimeData = ev.mimeData()
        if mimeData.hasUrls():
            for url in mimeData.urls():
                f = url.toLocalFile()
                if not f.isEmpty():
                    self._addFile(str(f))
            self._onFileSelectionChanged()
            ev.acceptProposedAction()

    def _onAddClicked(self):
        defaultDir = os.path.expanduser('~/Desktop')
        if not os.path.isdir(defaultDir):
            defaultDir = ''
        openDir = localSettings().getString('Settings/FileSenderOpenDir')
        if (not openDir) or (not os.path.isdir(openDir)):
            openDir = defaultDir
        fileList = QFileDialog.getOpenFileNames(self,
                                                'Select file(s) to add...',
                                                openDir)
        for f in fileList:
            self._addFile(str(f))
        if len(fileList):
            openDir = os.path.split(str(fileList[0]))[0]
            localSettings().setString('Settings/FileSenderOpenDir', openDir)
        self._onFileSelectionChanged()

    def _onRemoveClicked(self):
        selItems = [
            i for i in self.fileItems.keys()
            if self.ui.fileList.isItemSelected(i)
        ]
        for item in selItems:
            self._removeFile(item)
        self._onFileSelectionChanged()

    def _onRemoveAllClicked(self):
        for item in self.fileItems.keys():
            self._removeFile(item)
        self._onFileSelectionChanged()

    def _onSendFilesClicked(self):
        self.setAcceptDrops(False)
        self.ui.fileList.clearSelection()
        self.ui.fileList.setSelectionMode(QAbstractItemView.NoSelection)
        self.ui.addFilesButton.setEnabled(False)
        self.ui.removeFilesButton.setEnabled(False)
        self.ui.removeAllButton.setEnabled(False)
        self.ui.sendFilesButton.setEnabled(False)
        self._doConnect()

    def _doConnect(self):
        def onConnect(connector):
            self.connectOp = None
            if connector.getError() != 0:
                self._setError('Unable to connect to CSpace.')
                return
            self._doConnectUser(connector.getSock())

        self.connectOp = tcpConnect(('127.0.0.1', env.port), self.reactor,
                                    onConnect)
        self._setStatus('Connecting to CSpace...')
        self.state = self.CONNECTINGCSPACE

    def _doConnectUser(self, sock):
        self._setStatus('Connecting to %s...' % env.contactName)
        self.state = self.CONNECTINGUSER

        def onConnect(err, sock):
            if err < 0:
                self._setError('Error connecting to %s.' % env.contactName)
                return
            self._doOfferFiles(sock)

        connector = CSpaceConnector(sock, env.contactName, 'FileTransfer',
                                    self.reactor, onConnect)
        self.connectOp = connector.getOp()

    def _doOfferFiles(self, sock):
        self._setStatus('Sending request ...')
        self.state = self.OFFERINGFILES
        fileList = []
        for row in range(self.ui.fileList.count()):
            item = self.ui.fileList.item(row)
            fileList.append(self.fileItems[item][0])
        self.rpcConn = RPCConnection(sock, self.reactor)
        self.switchboard = RPCSwitchboard(self.rpcConn)
        self.fs = FlatFS(fileList)
        self.fileServer = FileServer(self.fs, self.switchboard)

        pending = {}
        for i, f in enumerate(fileList):
            pending[os.path.split(f)[1].lower()] = i

        def onClose():
            if pending:
                self._setError('Disconnected.')
            else:
                self._setStatus('Completed.')

        def onTransferStatus(payload):
            if type(payload) is not ListType: return
            if len(payload) != 4: return
            for x in payload:
                if type(x) is not IntType: return
                if x < 0: return
            fileId, numFiles, transferred, fileSize = payload
            if numFiles != len(fileList): return
            if not (1 <= fileId <= numFiles): return
            if transferred > fileSize: return
            fname = os.path.split(fileList[fileId - 1])[1]
            lfname = fname.lower()
            pos = pending.get(lfname, None)
            if pos is None: return
            if transferred == fileSize:
                percent = 100
                del pending[lfname]
            else:
                percent = transferred * 100 / fileSize
            self._setStatus('Sending file (%d/%d): %s (%d%%)' %
                            (pos + 1, len(fileList), fname, percent))

        self.switchboard.addOnewayAgent('TransferStatus', onTransferStatus)
        self.rpcConn.setCloseCallback(onClose)

    def closeEvent(self, ev):
        ev.accept()
        delaygc(self)
Example #13
0
class RouterClient( object ) :
    (CLOSED,CONNECTING,CONNECTED,REGISTERING,REGISTERED) = range(5)
    def __init__( self, routerAddr, reactor ) :
        self.routerAddr = routerAddr
        self.reactor = reactor
        self.state = self.CLOSED
        self.connectOp = None
        self.rpcConn = None
        self.pingOps = {}
        self.registerOp = None
        self.closeCallback = None

    def setCloseCallback( self, closeCallback ) :
        self.closeCallback = closeCallback

    def close( self ) :
        if self.state == self.CONNECTING :
            self.connectOp.cancel()
            self.connectOp = None
        else :
            for pingOp in self.pingOps.keys() :
                pingOp.cancel()
            self.pingOps.clear()
            if self.state == self.REGISTERING :
                self.registerOp.cancel()
                self.registerOp = None
            if self.state in (self.CONNECTED,self.REGISTERING,self.REGISTERED) :
                self.rpcConn.close()
                self.rpcConn = None
        self.state = self.CLOSED

    def enableIncoming( self, flag ) :
        assert self.state == self.REGISTERED
        self.rpcConn.allowIncoming( flag )

    def setIncomingCallback( self, incomingCallback ) :
        assert self.state == self.REGISTERED
        self.incomingCallback = incomingCallback

    def getRouterAddr( self ) : return self.routerAddr

    def _onClose( self ) :
        self.close()
        if self.closeCallback :
            self.closeCallback()

    def connect( self, connectCallback ) :
        assert self.state == self.CLOSED
        def onTCPConnect( connector ) :
            self.connectOp = None
            if connector.getError() != 0 :
                self.state = self.CLOSED
                connectCallback( False )
                return
            self.rpcConn = RPCConnection( connector.getSock(), self.reactor )
            self.rpcConn.setCloseCallback( self._onClose )
            self.state = self.CONNECTED
            connectCallback( True )
        self.connectOp = tcpConnect( self.routerAddr, self.reactor, onTCPConnect )
        self.state = self.CONNECTING

    def callPing( self, pingCallback ) :
        assert self.state in (self.CONNECTED,self.REGISTERING,self.REGISTERED)
        def onResult( err, result) :
            del self.pingOps[pingOp]
            if err < 0 :
                pingCallback( None )
                return
            assert type(result) is list
            if (len(result) != 1) or (type(result[0]) is not list) :
                pingCallback( None )
                return
            addr = tuple(result[0])
            try :
                validateInetAddress( addr )
            except :
                pingCallback( None )
                return
            pingCallback( addr )
        pingOp = _doRPCCall( self.rpcConn, 'Ping', [], onResult )
        self.pingOps[pingOp] = 1

    def callRegister( self, registerCallback, incomingCallback ) :
        assert self.state == self.CONNECTED
        def onResult( err, result ) :
            self.registerOp = None
            if err < 0 :
                self.state = self.CONNECTED
                registerCallback( None )
                return
            if (len(result) != 1) or \
                    (type(result[0]) is not str) or (not result[0]) :
                self.state = self.CONNECTED
                registerCallback( None )
                return
            self.state = self.REGISTERED
            self.routerId = result[0]
            self.rpcConn.setOnewayCallback( self._onOneway )
            self.incomingCallback = incomingCallback
            registerCallback( self.routerId )
        self.registerOp = _doRPCCall( self.rpcConn, 'Register', [], onResult )
        self.state = self.REGISTERING

    def _onOneway( self, payload ) :
        assert self.state == self.REGISTERED
        print 'oneway payload =', payload
        if (type(payload) is not str) or (not payload) :
            return
        connectionId = payload
        self.incomingCallback( connectionId )
Example #14
0
class FileReceiverWindow( QWidget, FlashWindow ) :
    def __init__( self, reactor ) :
        QWidget.__init__( self )
        FlashWindow.__init__( self, reactor )
        self.ui = Ui_FileReceiverWindow()
        self.ui.setupUi( self )
        self.reactor = reactor
        self.setWindowTitle( env.displayName + ' - ' + str(self.windowTitle()) )
        self.connect( self.ui.acceptButton, SIGNAL('clicked()'), self._onAcceptFiles )
        self.connect( self.ui.cancelButton, SIGNAL('clicked()'), self.close )
        tcpConnect( ('127.0.0.1',env.port), self.reactor, self._onConnect )
        self._setStatus( 'Connecting to CSpace...' )
        self.disconnected = False

    def _setStatus( self, text, isError=False ) :
        lines = text.split( '\n' )
        text = '<b>%s</b>' % '<br/>'.join(lines)
        if isError :
            text = '<font color=red>%s</font>' % text
        self.ui.status.setText( text )

    def _setError( self, text ) :
        self._setStatus( text, True )
        self.ui.cancelButton.setText( '&Close' )

    def _onConnect( self, connector ) :
        if connector.getError() != 0 :
            self._setError( 'Error connecting to CSpace.' )
            return
        sock = connector.getSock()
        self._setStatus( 'Accepting connection from %s.' % env.displayName )
        CSpaceAcceptor( sock, env.connectionId, self.reactor, self._onAccept )

    def _onAccept( self, err, sock ) :
        if err < 0 :
            self._setError( 'Error accepting connection from %s.' % env.displayName )
            return
        self.rpcConn = RPCConnection( sock, self.reactor )
        self.fileClient = FileClient( self.rpcConn )
        self._setStatus( 'Fetching file list from %s...' % env.displayName )
        self.fileClient.callList( '/', self._onList )

    def _onList( self, err, result ) :
        if err != 0 :
            self._setError( 'Error fetching file list from %s.' % env.displayName )
            return
        self.files = []
        for x in result :
            if not x.endswith('/') :
                self.files.append( x )
                self.ui.fileList.addItem( x )
        self._setStatus( ('%s is sending the following files.\n' % env.displayName ) + 
                'Would you like to accept?' )
        self.ui.acceptButton.setEnabled( True )
        self.rpcConn.setCloseCallback( self._onClose )
        self.flash()

    def _onClose( self ) :
        self.disconnected = True
        self._setError( 'Disconnected.' )
        self.ui.acceptButton.setEnabled( False )

    def _chooseTargetDir( self ) :
        defaultDir = os.path.expanduser( '~/Desktop' )
        if not os.path.isdir(defaultDir) :
            defaultDir = QString()
        dir = localSettings().getString( 'Settings/FileReceiverSaveDir' )
        if (not dir) or (not os.path.isdir(dir)) :
            dir = defaultDir
        while True :
            dir = QFileDialog.getExistingDirectory( self, 'Choose directory to save the file(s)',
                    dir )
            if dir.isEmpty() : return None
            dir = str(dir)
            existing = []
            for f in self.files :
                if os.path.exists(os.path.join(dir,f)) : existing.append(f)
            if not existing : break
            msg = 'The following file(s) already exist in\n%s.\nWould you like to overwrite?\n%s' % (dir,'\n'.join(existing))
            result = QMessageBox.question( self, 'Overwrite Prompt', msg, QMessageBox.Yes, QMessageBox.No, QMessageBox.Cancel|QMessageBox.Escape )
            if result == QMessageBox.Yes : break
            if result == QMessageBox.No : continue
            assert result == QMessageBox.Cancel
            return None
        localSettings().setString( 'Settings/FileReceiverSaveDir', dir )
        return dir

    def _onAcceptFiles( self ) :
        self.ui.acceptButton.setEnabled( False )
        targetDir = self._chooseTargetDir()
        if self.disconnected : return
        if not targetDir :
            self.ui.acceptButton.setEnabled( True )
            return
        self.targetDir = targetDir
        self.curFileId = 0
        self.rpcConn.setCloseCallback( None )
        self.statusStub = RPCStub( self.rpcConn, 'TransferStatus' )
        self._doTransfer()

    def _doTransfer( self ) :
        if self.curFileId >= len(self.files) :
            self._setStatus( 'Completed.' )
            self.ui.cancelButton.setText( '&Close' )
            self.rpcConn.close( deferred=True )
            return
        fname = self.files[self.curFileId]
        self.curFileId += 1
        self._setStatus( 'Receiving file(%d/%d): %s'
                % (self.curFileId,len(self.files),fname) )
        remotePath = '/' + fname
        localPath = os.path.join( self.targetDir, fname )
        try :
            self.fetcher = FileFetcher( self.fileClient,
                    remotePath, localPath, self._onTransfer )
        except (OSError, IOError), e :
            self._setError( 'Error saving file: %s' % localPath )
            return
Example #15
0
class RouterServerHandler( object ) :
    (INITIAL,REGISTERED,CONNECTING,CLOSED) = range(4)
    def __init__( self, sock, reactor, routerState ) :
        self.rpcConn = RPCConnection( sock, reactor )
        self.reactor = reactor
        self.routerState = routerState
        self.rpcConn.setCloseCallback( self.close )
        self.rpcConn.setRequestCallback( self._onRequest )
        self.requestTable = {}
        for msg in 'Ping Register Connect Accept'.split() :
            self.requestTable[msg] = getattr( self, '_do%s' % msg )
        self.routerState.handlers[self] = 1
        self.state = self.INITIAL
        self._lastActiveTime = time()

    def close( self ) :
        self.rpcConn.close()
        del self.routerState.handlers[self]
        if self.state == self.REGISTERED :
            del self.routerState.registered[self.routerId]
        elif self.state == self.CONNECTING :
            del self.routerState.connecting[self.connectionId]
        self.state = self.CLOSED

    def lastActiveTime( self ) :
        return self._lastActiveTime

    def sendIncoming( self, connectionId ) :
        assert self.state == self.REGISTERED
        self.rpcConn.oneway( connectionId )

    def _onRequest( self, payload, ctx ) :
        self._lastActiveTime = time()
        try :
            assert type(payload) is list
            assert len(payload) >= 1
            msg = payload.pop( 0 )
            assert type(msg) is str
            handler = self.requestTable.get( msg )
            assert handler is not None
        except :
            ctx.response( [-1] )
            return
        handler( payload, ctx )

    def _doPing( self, args, ctx ) :
        try :
            peerAddr = self.rpcConn.getSock().getpeername()
        except sock_error :
            ctx.response( [-1] )
            return
        ctx.response( (0,peerAddr) )

    def _doRegister( self, args, ctx ) :
        try :
            assert self.state == self.INITIAL
            assert len(args) == 0
        except :
            ctx.response( (-1,'') )
            return
        while True :
            routerId = rand_bytes( 20 )
            if routerId not in self.routerState.registered : break
        self.routerId = routerId
        self.state = self.REGISTERED
        self.routerState.registered[routerId] = self
        ctx.response( (0,self.routerId) )

    def _doConnect( self, args, ctx ) :
        try :
            assert self.state == self.INITIAL
            assert len(args) == 1
            routerId = args[0]
            assert type(routerId) is str
            handler = self.routerState.registered.get( routerId )
            assert handler is not None
        except :
            ctx.response( [-1] )
            return
        while True :
            connectionId = rand_bytes( 20 )
            if connectionId not in self.routerState.connecting : break
        self.connectionId = connectionId
        self.connectCtx = ctx
        self.state = self.CONNECTING
        self.routerState.connecting[connectionId] = self
        handler.sendIncoming( connectionId )

    def finishConnect( self ) :
        assert self.state == self.CONNECTING
        self.connectCtx.response( [0] )
        del self.routerState.connecting[self.connectionId]
        del self.routerState.handlers[self]
        sock = self.rpcConn.getSock()
        pendingWrite = self.rpcConn.getPendingWrite()
        self.rpcConn.shutdown()
        self.state = self.CLOSED
        return (sock,pendingWrite)

    def _doAccept( self, args, ctx ) :
        try :
            assert self.state == self.INITIAL
            assert len(args) == 1
            connectionId = args[0]
            assert type(connectionId) is str
            handler = self.routerState.connecting.get( connectionId )
            assert handler is not None
        except :
            ctx.response( [-1] )
            return
        sock1,pendingWrite1 = handler.finishConnect()
        ctx.response( [0] )
        del self.routerState.handlers[self]
        sock2 = self.rpcConn.getSock()
        pendingWrite2 = self.rpcConn.getPendingWrite()
        self.rpcConn.shutdown()
        self.state = self.CLOSED
        BridgeInitiator( sock1, pendingWrite1, sock2, pendingWrite2, self.reactor, self.routerState )