]> code.delx.au - pymsnt/commitdiff
File transfer fixes. Still not working in my tests. But it should be\!
authorjamesbunton <jamesbunton@55fbd22a-6204-0410-b2f0-b6c764c7e90a>
Wed, 2 Nov 2005 01:00:58 +0000 (01:00 +0000)
committerjamesbunton <jamesbunton@55fbd22a-6204-0410-b2f0-b6c764c7e90a>
Wed, 2 Nov 2005 01:00:58 +0000 (01:00 +0000)
git-svn-id: http://delx.cjb.net/svn/pymsnt/trunk@18 55fbd22a-6204-0410-b2f0-b6c764c7e90a

committer: jamesbunton <jamesbunton@55fbd22a-6204-0410-b2f0-b6c764c7e90a>

PyMSNt
config-example.xml
src/ft.py
src/tlib/msn.py
src/tlib/msnft.py

diff --git a/PyMSNt b/PyMSNt
index c341c1ff607a3a7c720de7a08bd509adcf1c688d..396f91a8a28346f414c0966e8317b0516f2a45ae 100755 (executable)
--- a/PyMSNt
+++ b/PyMSNt
@@ -1,7 +1,5 @@
 #!/bin/bash
 
-exec -a PyMSNt python main.py $*
-
 # Comment out the above line and use the below for twistd
-#PPATH="/usr/local/PyMSNt"
-#twistd -oy "$PPATH/PyMSNt.tac" -r poll --pidfile "$PPATH/PyMSNt.pid" -l "$PPATH/debug.log"
+PPATH="/usr/local/PyMSNt"
+twistd -oy "$PPATH/PyMSNt.tac" -r poll --pidfile "$PPATH/PyMSNt.pid" -l "$PPATH/debug.log"
index 1175a0da03e0bf0efcfcc785384d8b09d6400849..4aaf4adbb1f6423992d34709860269e2dc727f75 100644 (file)
@@ -5,7 +5,7 @@
 <!-- The JabberID of the transport -->
 <jid>msn</jid>
 <!-- The public IP of the machine the transport is running on -->
-<ip>129.129.129.129</ip>
+<ip>127.0.0.1</ip>
 <!-- The component JID of the transport. Unless you're doing clustering, leave this alone -->
 <!-- <compjid>msn1</compjid> -->
 
index b0fd50ee10d0f812270b43001ae262dfce714bb7..6cc6bade3e0051defb93560fbbb0de21e9788840 100644 (file)
--- a/src/ft.py
+++ b/src/ft.py
@@ -31,7 +31,7 @@ class FTReceive:
 
        def __init__(self, session, senderJID, legacyftp):
                self.session = session
-               self.toJID = self.session.jabberID + "/" + self.session.highestResource
+               self.toJID = self.session.jabberID + "/" + self.session.highestResource()
                self.senderJID = senderJID
                self.legacyftp = legacyftp
                LogEvent(INFO)
@@ -69,18 +69,22 @@ class FTReceive:
                LogEvent(ERROR)
 
        def messageOobMode(self):
-               global oobSite
-               self.legacyftp.accept()
-               filename = str(random.randint(0, sys.maxint))
-               oobSite.resource.putFile(self, filename)
-               m = Element((None, "message"))
-               m.attributes["to"] = self.session.jabberID
-               m.attributes["from"] = self.senderJID
-               m.addElement("body").addContent(config.ftOOBRoot + "/" + filename)
-               x = m.addElement("x")
-               x.attributes["xmlns"] = disco.XOOB
-               x.addElement("url").addContent(config.ftOOBRoot + "/" + filename)
-               self.session.pytrans.send(m)
+               d = self.legacyftp.accept()
+               d.addCallback(messageOobModeCB)
+               d.addErrback(self.error)
+
+               def messageOobModeCB():
+                       global oobSite
+                       filename = str(random.randint(0, sys.maxint))
+                       oobSite.resource.putFile(self, filename)
+                       m = Element((None, "message"))
+                       m.attributes["to"] = self.session.jabberID
+                       m.attributes["from"] = self.senderJID
+                       m.addElement("body").addContent(config.ftOOBRoot + "/" + filename)
+                       x = m.addElement("x")
+                       x.attributes["xmlns"] = disco.XOOB
+                       x.addElement("url").addContent(config.ftOOBRoot + "/" + filename)
+                       self.session.pytrans.send(m)
        
        def error(self):
                #FIXME
index d1250bee5b149a7c03f05ac6a9db419e89e31fcf..33c5e91ccc1835ebbecf115d33962cba88862ffb 100644 (file)
@@ -98,7 +98,6 @@ if(utils.checkTwisted()):
 else:
        from twisted.protocols.http import HTTPClient
 import msnp11chl
-import msnft
 import msnp2p
 
 # Twisted imports
@@ -154,7 +153,8 @@ STATUS_LUNCH   = 'LUN'
 CR = "\r"
 LF = "\n"
 
-LINEDEBUG = False
+LINEDEBUG = True
+MESSAGEDEBUG = True
 
 def getVal(inp):
     return inp.split('=')[1]
@@ -633,11 +633,11 @@ class MSNEventBase(LineReceiver):
         raise NotImplementedError
 
     def sendLine(self, line):
-        if(LINEDEBUG): print ">> " + line
+        if(LINEDEBUG): log.msg(">> " + line)
         LineReceiver.sendLine(self, line)
 
     def lineReceived(self, line):
-        if(LINEDEBUG): print "<< " + line
+        if(LINEDEBUG): log.msg("<< " + line)
         if self.currentMessage:
             self.currentMessage.readPos += len(line+CR+LF)
             try:
@@ -688,6 +688,7 @@ class MSNEventBase(LineReceiver):
         del self.currentMessage.readPos
         m = self.currentMessage
         self.currentMessage = None
+        if MESSAGEDEBUG: log.msg(m.message)
         if not self.checkMessage(m):
             self.setLineMode(extra)
             return
@@ -1938,12 +1939,14 @@ class SwitchboardClient(MSNEventBase):
         if not info.get('Application-GUID', '').upper() == MSN_MSNFTP_GUID: return 0
         try:
             cookie = info['Invitation-Cookie']
-            fileName = info['Application-File']
-            fileSize = int(info['Application-FileSize'])
+            filename = info['Application-File']
+            filesize = int(info['Application-FileSize'])
+            connectivity = (info.get('Connectivity').lower() == 'y')
         except KeyError:
             log.msg('Received munged file transfer request ... ignoring.')
             return 0
-        self.gotSendRequest(msnft.MSNFTP_Receive(fileName, fileSize, message.userHandle, cookie, self))
+        import msnft
+        self.gotSendRequest(msnft.MSNFTP_Receive(filename, filesize, message.userHandle, cookie, connectivity, self))
         return 1
 
     def _checkP2PMessage(self, message, ctypes):
@@ -2152,6 +2155,7 @@ class SwitchboardClient(MSNEventBase):
             self.sendLine("%s: %s" % (header[0], header[1]))
         self.transport.write(CR+LF)
         self.transport.write(message.message)
+        if MESSAGEDEBUG: log.msg(message.message)
         return d
 
     def sendAvatarRequest(self, userHandle, msnobj):
index 37da03367762afd8d3c7e410e84d3e2638c95c58..74422d6f4aebd888bbd642bba57304027be7596b 100644 (file)
@@ -2,16 +2,20 @@
 # Licensed for distribution under the GPL version 2, check COPYING for details
 
 from twisted.internet import reactor
+from twisted.internet.defer import Deferred
 from twisted.protocols.basic import LineReceiver
 from twisted.internet.protocol import ClientFactory
+from twisted.python import log
 
-#from msn import MSNMessage
+from msn import checkParamLen, MSNMessage
 
 from debug import LogEvent, INFO, WARN, ERROR
 import config
 
 import random
-import sys
+
+MAXAUTHCOOKIE = 2**32-1
+MAXAUTHCOOKIE = 1000
 
 
 class MSNFTReceive_Base:
@@ -26,7 +30,7 @@ class MSNFTReceive_Base:
        def removeMe(self):
                self.connector = None
        
-       def accept(self, yes):
+       def accept(self, yes=True):
                pass
        
        def writeTo(self, obj):
@@ -70,14 +74,14 @@ class MSNFTP_Ports:
                        lowPort = 6891
                        highPort = 6899
                self.ports = [lowPort+x for x in xrange(highPort-lowPort)]
-               self.portFree = [False] * len(self.ports)
+               self.portFree = [True] * len(self.ports)
        
        def requestPort(self):
                for i in xrange(len(self.ports)):
                        if self.portFree[i]:
                                self.portFree[i] = False
                                LogEvent(INFO, "", "Reserved a port")
-                               return self.port[i]
+                               return self.ports[i]
                LogEvent(INFO, "", "Out of ports")
 
        def freePort(self, port):
@@ -88,37 +92,47 @@ class MSNFTP_Ports:
 msnports = MSNFTP_Ports()
 
 class MSNFTP_Receive(ClientFactory, MSNFTReceive_Base):
-       def __init__(self, filename, filesize, userHandle, iCookie, switchboard):
+       def __init__(self, filename, filesize, userHandle, iCookie, connectivity, switchboard):
                MSNFTReceive_Base.__init__(self, filename, filesize, userHandle)
                self.iCookie = iCookie
                self.switchboard = switchboard
                self.serverSocket = None
                self.timeout = None
-               self.authCookie = str(random.randint(0, sys.maxint))
+               self.authCookie = str(random.randint(1, MAXAUTHCOOKIE))
+               self.port = None
+               self.d = None
                LogEvent(INFO, self.switchboard.userHandle)
        
        def removeMe(self):
                if self.serverSocket:
                        self.serverSocket.stopListening()
-               if self.timeout:
+               if self.timeout and not self.timeout.called:
                        self.timeout.cancel()
+               if self.port:
+                       global msnports
+                       msnports.freePort(self.port)
+                       self.port = None
+               if self.d:
+                       self.d.errback()
+                       self.d = None
                LogEvent(INFO, self.switchboard.userHandle)
-               
+
        def accept(self, yes=True):
                LogEvent(INFO, self.switchboard.userHandle)
                global msnports
-               port = msnports.requestPort()
-               if not port:
+               self.port = msnports.requestPort()
+               if not self.port:
                        yes = False
                        self.gotError()
+               LogEvent(INFO, self.switchboard.userHandle)
        
                from msn import MSNMessage
                m = MSNMessage()
                m.setHeader('Content-Type', 'text/x-msmsgsinvite; charset=UTF-8')
                if yes:
                        m.message += 'IP-Address: %s\r\n' % str(config.ip)
-                       m.message += 'Port: %s\r\n' % str(port)
-                       m.message += 'AuthCookie %s\r\n' % authCookie
+                       m.message += 'Port: %s\r\n' % str(self.port)
+                       m.message += 'AuthCookie %s\r\n' % self.authCookie
                        m.message += 'Sender-Connect: TRUE\r\n'
                        m.message += 'Invitation-Command: ACCEPT\r\n'
                        m.message += 'Invitation-Cookie: %s\r\n' % str(self.iCookie)
@@ -132,7 +146,8 @@ class MSNFTP_Receive(ClientFactory, MSNFTReceive_Base):
                self.switchboard.sendMessage(m)
 
                if yes:
-                       self.serverSocket = reactor.listenTCP(port, self)
+                       self.d = Deferred()
+                       self.serverSocket = reactor.listenTCP(self.port, self)
                        self.timeout = reactor.callLater(20, self.gotError)
        
        def buildProtocol(self, addr):
@@ -141,143 +156,151 @@ class MSNFTP_Receive(ClientFactory, MSNFTReceive_Base):
                self.serverSocket = None
                self.timeout.cancel()
                self.timeout = None
-               return MSNFTP_FileReceive(authCookie, self.switchboard.userHandle, self)
+               self.d.callback()
+               self.d = None
+               return MSNFTP_FileReceive(self.authCookie, self.switchboard.userHandle, self)
                
 
 class MSNFTP_FileReceive(LineReceiver):
-    """
-    This class provides support for receiving files from contacts.
-
-    @ivar fileSize: the size of the receiving file. (you will have to set this)
-    @ivar connected: true if a connection has been established.
-    @ivar completed: true if the transfer is complete.
-    @ivar bytesReceived: number of bytes (of the file) received.
-                         This does not include header data.
-    """
-
-    def __init__(self, auth, myUserHandle, file, directory="", overwrite=0):
-        """
-        @param auth: auth string received in the file invitation.
-        @param myUserHandle: your userhandle.
-        @param file: A string or file object represnting the file
-                     to save data to.
-        @param directory: optional parameter specifiying the directory.
-                          Defaults to the current directory.
-        @param overwrite: if true and a file of the same name exists on
-                          your system, it will be overwritten. (0 by default)
-        """
-        self.auth = auth
-        self.myUserHandle = myUserHandle
-        self.fileSize = 0
-        self.connected = 0
-        self.completed = 0
-        self.directory = directory
-        self.bytesReceived = 0
-        self.overwrite = overwrite
-
-        # used for handling current received state
-        self.state = 'CONNECTING'
-        self.segmentLength = 0
-        self.buffer = ''
-        
-        if isinstance(file, types.StringType):
-            path = os.path.join(directory, file)
-            if os.path.exists(path) and not self.overwrite:
-                log.msg('File already exists...')
-                raise IOError, "File Exists" # is this all we should do here?
-            self.file = open(os.path.join(directory, file), 'wb')
-        else:
-            self.file = file
-
-    def connectionMade(self):
-        self.connected = 1
-        self.state = 'INHEADER'
-        self.sendLine('VER MSNFTP')
-
-    def connectionLost(self, reason):
-        self.connected = 0
-        self.file.close()
-
-    def parseHeader(self, header):
-        """ parse the header of each 'message' to obtain the segment length """
-
-        if ord(header[0]) != 0: # they requested that we close the connection
-            self.transport.loseConnection()
-            return
-        try:
-            extra, factor = header[1:]
-        except ValueError:
-            # munged header, ending transfer
-            self.transport.loseConnection()
-            raise
-        extra  = ord(extra)
-        factor = ord(factor)
-        return factor * 256 + extra
-
-    def lineReceived(self, line):
-        temp = line.split(' ')
-        if len(temp) == 1: params = []
-        else: params = temp[1:]
-        cmd = temp[0]
-        handler = getattr(self, "handle_%s" % cmd.upper(), None)
-        if handler: handler(params) # try/except
-        else: self.handle_UNKNOWN(cmd, params)
-
-    def rawDataReceived(self, data):
-        bufferLen = len(self.buffer)
-        if self.state == 'INHEADER':
-            delim = 3-bufferLen
-            self.buffer += data[:delim]
-            if len(self.buffer) == 3:
-                self.segmentLength = self.parseHeader(self.buffer)
-                if not self.segmentLength: return # hrm
-                self.buffer = ""
-                self.state = 'INSEGMENT'
-            extra = data[delim:]
-            if len(extra) > 0: self.rawDataReceived(extra)
-            return
-
-        elif self.state == 'INSEGMENT':
-            dataSeg = data[:(self.segmentLength-bufferLen)]
-            self.buffer += dataSeg
-            self.bytesReceived += len(dataSeg)
-            if len(self.buffer) == self.segmentLength:
-                self.gotSegment(self.buffer)
-                self.buffer = ""
-                if self.bytesReceived == self.fileSize:
-                    self.completed = 1
-                    self.buffer = ""
-                    self.file.close()
-                    self.sendLine("BYE 16777989")
-                    return
-                self.state = 'INHEADER'
-                extra = data[(self.segmentLength-bufferLen):]
-                if len(extra) > 0: self.rawDataReceived(extra)
-                return
-
-    def handle_VER(self, params):
-        checkParamLen(len(params), 1, 'VER')
-        if params[0].upper() == "MSNFTP":
-            self.sendLine("USR %s %s" % (self.myUserHandle, self.auth))
-        else:
-            log.msg('they sent the wrong version, time to quit this transfer')
-            self.transport.loseConnection()
-
-    def handle_FIL(self, params):
-        checkParamLen(len(params), 1, 'FIL')
-        try:
-            self.fileSize = int(params[0])
-        except ValueError: # they sent the wrong file size - probably want to log this
-            self.transport.loseConnection()
-            return
-        self.setRawMode()
-        self.sendLine("TFR")
-
-    def handle_UNKNOWN(self, cmd, params):
-        log.msg('received unknown command (%s), params: %s' % (cmd, params))
-
-    def gotSegment(self, data):
-        """ called when a segment (block) of data arrives. """
-        self.file.write(data)
+       """
+       This class provides support for receiving files from contacts.
+
+       @ivar fileSize: the size of the receiving file. (you will have to set this)
+       @ivar connected: true if a connection has been established.
+       @ivar completed: true if the transfer is complete.
+       @ivar bytesReceived: number of bytes (of the file) received.
+                                                This does not include header data.
+       """
+
+       def __init__(self, auth, myUserHandle, file, directory="", overwrite=0):
+               """
+               @param auth: auth string received in the file invitation.
+               @param myUserHandle: your userhandle.
+               @param file: A string or file object represnting the file
+                                        to save data to.
+               @param directory: optional parameter specifiying the directory.
+                                                 Defaults to the current directory.
+               @param overwrite: if true and a file of the same name exists on
+                                                 your system, it will be overwritten. (0 by default)
+               """
+               self.auth = auth
+               self.myUserHandle = myUserHandle
+               self.fileSize = 0
+               self.connected = 0
+               self.completed = 0
+               self.directory = directory
+               self.bytesReceived = 0
+               self.overwrite = overwrite
+
+               # used for handling current received state
+               self.state = 'CONNECTING'
+               self.segmentLength = 0
+               self.buffer = ''
+               
+               if isinstance(file, str):
+                       path = os.path.join(directory, file)
+                       if os.path.exists(path) and not self.overwrite:
+                               log.msg('File already exists...')
+                               raise IOError, "File Exists" # is this all we should do here?
+                       self.file = open(os.path.join(directory, file), 'wb')
+               else:
+                       self.file = file
+
+       def connectionMade(self):
+               self.connected = 1
+               self.state = 'INHEADER'
+               self.sendLine('VER MSNFTP')
+
+       def connectionLost(self, reason):
+               self.connected = 0
+               self.file.close()
+
+       def parseHeader(self, header):
+               """ parse the header of each 'message' to obtain the segment length """
+
+               if ord(header[0]) != 0: # they requested that we close the connection
+                       self.transport.loseConnection()
+                       return
+               try:
+                       extra, factor = header[1:]
+               except ValueError:
+                       # munged header, ending transfer
+                       self.transport.loseConnection()
+                       raise
+               extra  = ord(extra)
+               factor = ord(factor)
+               return factor * 256 + extra
+
+       def sendLine(self, line):
+               log.msg("SENDING LINE!!!    " + line)
+               LineReceiver.sendLine(self, line)
+
+       def lineReceived(self, line):
+               temp = line.split(' ')
+               if len(temp) == 1: params = []
+               else: params = temp[1:]
+               cmd = temp[0]
+               log.msg("GOT A LINE!!!    " + line)
+               handler = getattr(self, "handle_%s" % cmd.upper(), None)
+               if handler: handler(params) # try/except
+               else: self.handle_UNKNOWN(cmd, params)
+
+       def rawDataReceived(self, data):
+               bufferLen = len(self.buffer)
+               log.msg("RAW DATA: " + data)
+               if self.state == 'INHEADER':
+                       delim = 3-bufferLen
+                       self.buffer += data[:delim]
+                       if len(self.buffer) == 3:
+                               self.segmentLength = self.parseHeader(self.buffer)
+                               if not self.segmentLength: return # hrm
+                               self.buffer = ""
+                               self.state = 'INSEGMENT'
+                       extra = data[delim:]
+                       if len(extra) > 0: self.rawDataReceived(extra)
+                       return
+
+               elif self.state == 'INSEGMENT':
+                       dataSeg = data[:(self.segmentLength-bufferLen)]
+                       self.buffer += dataSeg
+                       self.bytesReceived += len(dataSeg)
+                       if len(self.buffer) == self.segmentLength:
+                               self.gotSegment(self.buffer)
+                               self.buffer = ""
+                               if self.bytesReceived == self.fileSize:
+                                       self.completed = 1
+                                       self.buffer = ""
+                                       self.file.close()
+                                       self.sendLine("BYE 16777989")
+                                       return
+                               self.state = 'INHEADER'
+                               extra = data[(self.segmentLength-bufferLen):]
+                               if len(extra) > 0: self.rawDataReceived(extra)
+                               return
+
+       def handle_VER(self, params):
+               checkParamLen(len(params), 1, 'VER')
+               if params[0].upper() == "MSNFTP":
+                       self.sendLine("USR %s %s" % (self.myUserHandle, self.auth))
+               else:
+                       log.msg('they sent the wrong version, time to quit this transfer')
+                       self.transport.loseConnection()
+
+       def handle_FIL(self, params):
+               checkParamLen(len(params), 1, 'FIL')
+               try:
+                       self.fileSize = int(params[0])
+               except ValueError: # they sent the wrong file size - probably want to log this
+                       self.transport.loseConnection()
+                       return
+               self.setRawMode()
+               self.sendLine("TFR")
+
+       def handle_UNKNOWN(self, cmd, params):
+               log.msg('received unknown command (%s), params: %s' % (cmd, params))
+
+       def gotSegment(self, data):
+               """ called when a segment (block) of data arrives. """
+               self.file.write(data)