# 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:
def removeMe(self):
self.connector = None
- def accept(self, yes):
+ def accept(self, yes=True):
pass
def writeTo(self, obj):
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):
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)
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):
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)