class MSNFTReceive_Base:
# Public
def __init__(self, filename, filesize, userHandle):
- self.connector = None
+ self.consumer = None
self.finished = False
self.error = False
self.buffer = []
self.filename, self.filesize, self.userHandle = filename, filesize, userHandle
def removeMe(self):
- self.connector = None
+ self.consumer = None
def accept(self, yes=True):
pass
def writeTo(self, obj):
- self.connector = obj
+ self.consumer = obj
for data in self.buffer:
- self.connector.write(data)
+ self.consumer.write(data)
self.buffer = []
if self.finished:
- self.connector.close()
+ self.consumer.close()
if self.error:
- self.connector.error()
+ self.consumer.error()
# Private
def write(self, data):
- if self.connector:
- self.connector.write(data)
+ if self.consumer:
+ self.consumer.write(data)
else:
self.buffer.append(data)
def close(self):
self.removeMe()
self.finished = True
- if self.connector:
- self.connector.close()
+ if self.consumer:
+ self.consumer.close()
def gotError(self, ignored=None):
self.removeMe()
self.error = True
- if self.connector:
- self.connector.error()
+ if self.consumer:
+ self.consumer.error()
class MSNFTP_Ports:
self.file.write(data)
+class MSNFTP_FileSend(LineReceiver):
+ """
+ This class provides support for sending files to other contacts.
+
+ @ivar bytesSent: the number of bytes that have currently been sent.
+ @ivar completed: true if the send has completed.
+ @ivar connected: true if a connection has been established.
+ @ivar targetUser: the target user (contact).
+ @ivar segmentSize: the segment (block) size.
+ @ivar auth: the auth cookie (number) to use when sending the
+ transfer invitation
+ """
+
+ def __init__(self, file):
+ """
+ @param file: A string or file object represnting the file to send.
+ """
+
+ if isinstance(file, str) or isinstance(file, unicode):
+ self.file = open(file, 'rb')
+ else:
+ self.file = file
+
+ self.fileSize = 0
+ self.bytesSent = 0
+ self.completed = 0
+ self.connected = 0
+ self.targetUser = None
+ self.segmentSize = 2045
+ self.auth = random.randint(0, 2**30)
+ self._pendingSend = None # :(
+
+ def connectionMade(self):
+ self.connected = 1
+
+ def connectionLost(self, reason):
+ if self._pendingSend:
+ self._pendingSend.cancel()
+ self._pendingSend = None
+ self.connected = 0
+ self.file.close()
+
+ 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)
+ else: self.handle_UNKNOWN(cmd, params)
+
+ def handle_VER(self, params):
+ checkParamLen(len(params), 1, 'VER')
+ if params[0].upper() == "MSNFTP":
+ self.sendLine("VER MSNFTP")
+ else: # they sent some weird version during negotiation, i'm quitting.
+ self.transport.loseConnection()
+
+ def handle_USR(self, params):
+ checkParamLen(len(params), 2, 'USR')
+ self.targetUser = params[0]
+ if self.auth == int(params[1]):
+ self.sendLine("FIL %s" % (self.fileSize))
+ else: # they failed the auth test, disconnecting.
+ self.transport.loseConnection()
+
+ def handle_TFR(self, params):
+ checkParamLen(len(params), 0, 'TFR')
+ # they are ready for me to start sending
+ self.sendPart()
+
+ def handle_BYE(self, params):
+ self.completed = (self.bytesSent == self.fileSize)
+ self.transport.loseConnection()
+
+ def handle_CCL(self, params):
+ self.completed = (self.bytesSent == self.fileSize)
+ self.transport.loseConnection()
+
+ def handle_UNKNOWN(self, cmd, params): log.msg('received unknown command (%s), params: %s' % (cmd, params))
+
+ def makeHeader(self, size):
+ """ make the appropriate header given a specific segment size. """
+ quotient, remainder = divmod(size, 256)
+ return chr(0) + chr(remainder) + chr(quotient)
+
+ def sendPart(self):
+ """ send a segment of data """
+ if not self.connected:
+ self._pendingSend = None
+ return # may be buggy (if handle_CCL/BYE is called but self.connected is still 1)
+ data = self.file.read(self.segmentSize)
+ if data:
+ dataSize = len(data)
+ header = self.makeHeader(dataSize)
+ self.transport.write(header + data)
+ self.bytesSent += dataSize
+ self._pendingSend = reactor.callLater(0, self.sendPart)
+ else:
+ self._pendingSend = None
+ self.completed = 1