+++ /dev/null
-# Copyright 2005 James Bunton <james@delx.cjb.net>
-# Licensed for distribution under the GPL version 2, check COPYING for details
-
-import struct
-import random
-import sha
-import base64
-import sys
-
-from tlib import xmlw
-
-MSNP2P_DEBUG = False
-
-def b64enc(s):
- return base64.encodestring(s).replace("\n", "")
-
-def random_guid():
- format = "{%4X%4X-%4X-%4X-%4X-%4X%4X%4X}"
- data = []
- for x in xrange(8):
- data.append(random.random() * 0xAAFF + 0x1111)
- data = tuple(data)
-
- return format % data
-
-
-class MSNOBJ:
- def __init__(self, s=""):
- self.creator = ""
- self.imageData = ""
- self.size = 0
- self.type = 0
- self.location = ""
- self.friendly = ""
- self.sha1d = ""
- self.text = ""
- if s:
- self.parse(s)
-
- def setData(self, creator, imageData):
- self.creator = creator
- self.imageData = imageData
- self.size = len(imageData)
- self.type = 3
- self.location = "TMP" + str(random.randint(1000,9999))
- self.friendly = "AAA="
- self.sha1d = b64enc(sha.sha(imageData).digest())
- self.makeText()
-
- def setNull(self):
- self.creator = ""
- self.imageData = ""
- self.size = 0
- self.type = 0
- self.location = ""
- self.friendly = ""
- self.sha1d = ""
- self.text = ""
-
- def makeText(self):
- h = []
- h.append("Creator")
- h.append(self.creator)
- h.append("Size")
- h.append(str(self.size))
- h.append("Type")
- h.append(str(self.type))
- h.append("Location")
- h.append(self.location)
- h.append("Friendly")
- h.append(self.friendly)
- h.append("SHA1D")
- h.append(self.sha1d)
- sha1c = b64enc(sha.sha("".join(h)).digest())
- self.text = '<msnobj Creator="%s" Size="%s" Type="%s" Location="%s" Friendly="%s" SHA1D="%s" SHA1C="%s"/>' % (self.creator, str(self.size), str(self.type), self.location, self.friendly, self.sha1d, sha1c)
-
- def parse(self, s):
- e = xmlw.parseText(s, True)
- self.creator = e.getAttribute("Creator")
- self.size = int(e.getAttribute("Size"))
- self.type = int(e.getAttribute("Type"))
- self.location = e.getAttribute("Location")
- self.friendly = e.getAttribute("Friendly")
- self.sha1d = e.getAttribute("SHA1D")
- self.text = s
-
-
-
-class BinaryFields:
- ACK = 0x02
- WAIT = 0x04
- ERR = 0x08
- DATA = 0x20
- BYEGOT = 0x40
- BYESENT = 0x80
- DATAFT = 0x1000030
-
- def __init__(self, fields=None, packet=None):
- if fields:
- self.fields = fields
- else:
- self.fields = [0] * 10
- if packet:
- self.unpackFields(packet)
-
- def __getitem__(self, key):
- return self.fields[key]
-
- def __setitem__(self, key, value):
- self.fields[key] = value
-
- def unpackFields(self, packet):
- self.fields = struct.unpack("<LLQQLLLLQ", packet[0:48])
- self.fields += struct.unpack(">L", packet[len(packet)-4:])
- if MSNP2P_DEBUG:
- print "Unpacked fields:",
- for i in self.fields:
- print hex(i),
- print
-
- def packHeaders(self):
- f = tuple(self.fields)
- if MSNP2P_DEBUG:
- print "Packed fields:",
- for i in self.fields:
- print hex(i),
- print
- return struct.pack("<LLQQLLLLQ", f[0], f[1], f[2], f[3], f[4], f[5], f[6], f[7], f[8])
-
- def packFooter(self):
- return struct.pack(">L", self.fields[9])
-
-
-class MSNSLPMessage:
- def __init__(self, packet=None):
- self.method = ""
- self.status = ""
- self.to = ""
- self.fro = ""
- self.cseq = 0
- self.sessionGuid = ""
- self.sessionID = None
- self.euf_guid = ""
- self.data = "\r\n" + chr(0)
- if packet:
- self.parse(packet)
-
- def create(self, method=None, status=None, to=None, fro=None, cseq=0, sessionGuid=None, data=None):
- self.method = method
- self.status = status
- self.to = to
- self.fro = fro
- self.cseq = cseq
- self.sessionGuid = sessionGuid
- if data: self.data = data
-
- def setData(self, sessionID=None, appID=None, guid=None, context=None):
- s = []
- if guid: s.append("EUF-GUID: %s\r\n" % guid)
- if sessionID: s.append("SessionID: %s\r\n" % sessionID)
- if appID: s.append("AppID: %s\r\n" % appID)
- if context: s.append("Context: %s\r\n\r\n" % context)
- s.append(chr(0))
-
- self.data = "".join(s)
-
- def parse(self, s):
- s = s[48:len(s)-4:]
- if s.find("MSNSLP/1.0") < 0: return
-
- lines = s.split("\r\n")
-
- # Get the MSNSLP method or status
- msnslp = lines[0].split(" ")
- if MSNP2P_DEBUG: print "Parsing MSNSLPMessage", s, len(s)
- if(msnslp[0] in ("INVITE", "BYE")):
- self.method = msnslp[0].strip()
- else:
- self.status = msnslp[1].strip()
-
- lines.remove(lines[0])
-
- for line in lines:
- line = line.split(":")
- if(len(line) > 1):
- if(len(line) > 2 and line[0] == "To"):
- self.to = line[2][:line[2].find('>')]
- elif(len(line) > 2 and line[0] == "From"):
- self.fro = line[2][:line[2].find('>')]
- elif(line[0] == "Call-ID"):
- self.sessionGuid = line[1].strip()
- elif(line[0] == "CSeq"):
- self.cseq = int(line[1].strip())
- elif(line[0] == "SessionID"):
- self.sessionID = int(line[1].strip())
- elif(line[0] == "EUF-GUID"):
- self.euf_guid = line[1].strip()
-
- def __str__(self):
- s = []
- if(self.method):
- s.append("%s MSNMSGR:%s MSNSLP/1.0\r\n" % (self.method, self.to))
- else:
- s.append("MSNSLP/1.0 %s\r\n" % self.status)
- s.append("To: <msnmsgr:%s>\r\n" % self.to)
- s.append("From: <msnmsgr:%s>\r\n" % self.fro)
- s.append("Via: MSNSLP/1.0/TLP ;branch=%s\r\n" % random_guid())
- s.append("CSeq: %s \r\n" % str(self.cseq))
- s.append("Call-ID: %s\r\n" % self.sessionGuid)
- s.append("Max-Forwards: 0\r\n")
- if(self.method == "BYE"):
- s.append("Content-Type: application/x-msnmsgr-sessionclosebody\r\n")
- else:
- s.append("Content-Type: application/x-msnmsgr-sessionreqbody\r\n")
- s.append("Content-Length: %s\r\n\r\n" % len(self.data))
- s.append(self.data)
- return "".join(s)
-
-
-class BaseID:
- def __init__(self, baseID=None, sender=False):
- if(baseID):
- self.baseID = baseID
- else:
- self.baseID = random.randint(4, 2**30)
- self.sender = sender
- if(self.sender):
- self.pos = -1
- else:
- self.pos = 0
-
- def get(self):
- if self.pos == -1:
- return self.baseID
- else:
- return self.baseID + self.pos - 3
-
- def next(self):
- self.pos += 1
- if self.pos == 3 and self.sender:
- self.pos += 1
- return self.get()
-
-class MSNP2P_Avatar:
- TRANSFER_COUNT = 0
- ERROR_COUNT = 0
-
- EUF_GUID = "{A4268EEC-FEC5-49E5-95C3-F126696BDBF6}"
- ERROR = -1
-
- def __init__(self):
- raise "NotImplemented"
-
- def getImage(self):
- return False
-
- def isFinished(self):
- if self.state >= self.FINISHED:
- MSNP2P_Avatar.TRANSFER_COUNT += 1
- return True
- elif self.state < 0:
- MSNP2P_Avatar.ERROR_COUNT += 1
- return True
- else:
- return False
-
- def setError(self, text):
- if MSNP2P_DEBUG:
- print "ERROR in avatar transfer: ", self, text, "in state:", self.state
- self.state = self.ERROR
-
- def warn(self, text):
- if MSNP2P_DEBUG:
- print "Warning in avatar transfer: ", self, text, "in state:", self.state
-
-
-class MSNP2P_Avatar_Send(MSNP2P_Avatar):
- # Avatar_Send states
- WAIT_REQUEST = 0
- SEND_REQACK = 1
- SEND_200OK = 2
- WAIT_200OK_ACK = 3
- SEND_DATAPREP = 4
- WAIT_DATAPREP_ACK = 5
- SEND_DATA = 6
- WAIT_BYE = 7
- SEND_BYE_ACK = 8
- FINISHED = 9
-
- def __init__(self, to, fro, msnobj):
- self.to = to
- self.fro = fro
- self.msnobj = msnobj
- self.fileOffset = 0 # The amount already sent
- self.sessionID = 0
- self.baseID = BaseID(sender=True)
- self.state = self.WAIT_REQUEST
- self.lastFields = BinaryFields()
- self.lastSentFields = BinaryFields()
-
- def processPacket(self, packet):
- if MSNP2P_DEBUG:
- print "processPacket", self.to, self.fro, self.state
- if(self.state == self.WAIT_REQUEST):
- message = MSNSLPMessage()
- message.parse(packet)
- if(message.method != "INVITE"):
- self.setError("method" + message.method)
- return
- if(message.cseq != 0):
- self.setError("cseq" + str(message.cseq))
- return
- if(message.euf_guid != self.EUF_GUID):
- self.setError("guid" + message.euf_guid)
- return
-
- binaryFields = BinaryFields()
- binaryFields.unpackFields(packet)
-
- self.sguid = message.sessionGuid
- self.sessionID = message.sessionID
-
- self.lastFields = binaryFields
- self.state = self.SEND_REQACK
- return
-
- if(self.state == self.WAIT_200OK_ACK):
- binaryFields = BinaryFields()
- binaryFields.unpackFields(packet)
-
- if(binaryFields[6] != self.lastSentFields[1]):
- self.warn("field6," + str(binaryFields[6]) + "," + str(self.lastSentFields[1]))
- return
- if(binaryFields[3] != self.lastSentFields[3]):
- self.setError("field3," + str(binaryFields[3]) + "," + str(self.lastSentFields[3]))
- return
- if(binaryFields[8] != self.lastSentFields[3]):
- self.setError("field8," + str(binaryFields[8]) + "," + str(self.lastSentFields[3]))
- return
- if(binaryFields[5] != BinaryFields.ACK):
- self.setError("field5," + str(binaryFields[5]))
- return
-
- self.lastFields = binaryFields
- self.state = self.SEND_DATAPREP
- return
-
- if(self.state == self.WAIT_DATAPREP_ACK):
- binaryFields = BinaryFields()
- binaryFields.unpackFields(packet)
-
- if(binaryFields[0] != self.sessionID):
- self.warn("field0," + str(binaryFields[0]) + "," + str(self.sessionID))
- return
- if(binaryFields[3] != self.lastSentFields[3]):
- self.setError("field3," + str(binaryFields[3]) + "," + str(self.lastSentFields[3]))
- return
- if(binaryFields[8] != self.lastSentFields[3]):
- self.setError("field8," + str(binaryFields[8]) + "," + str(self.lastSentFields[3]))
- return
- if(binaryFields[5] != BinaryFields.ACK):
- self.setError("field5," + str(binaryFields[5]))
- return
- if(binaryFields[6] != self.lastSentFields[1]):
- self.setError("field6," + str(binaryFields[6]) + "," + str(self.lastSentFields[1]))
- return
- if(binaryFields[7] != self.lastSentFields[6]):
- self.setError("field7," + str(binaryFields[7]) + "," + str(self.lastSentFields[6]))
- return
-
- self.lastFields = binaryFields
- self.baseID.next()
- self.state = self.SEND_DATA
- return
-
- if(self.state == self.WAIT_BYE):
- binaryFields = BinaryFields()
- binaryFields.unpackFields(packet)
-
- # BYE message
- message = MSNSLPMessage()
- message.parse(packet)
- if(message.sessionGuid != self.sguid):
- self.warn("sessionGuid" + message.sessionGuid)
- return
- if(message.method != "BYE"):
- self.setError("method " + message.method)
- return
- if(message.cseq != 0):
- self.setError("cseq" + str(message.cseq))
- return
-
- self.lastFields = binaryFields
- self.state = self.SEND_BYE_ACK # I don't really care about receiving the data ack
- return
-
-
- def getNextPacket(self):
- if MSNP2P_DEBUG:
- print "getNextPacket (Avatar_Send)", self.to, self.fro, self.state
- if(self.state == self.SEND_REQACK):
- binaryFields = BinaryFields()
- binaryFields[1] = self.baseID.get()
- binaryFields[3] = self.lastFields[3]
- binaryFields[5] = BinaryFields.ACK
- binaryFields[6] = self.lastFields[1]
- binaryFields[7] = self.lastFields[6]
- binaryFields[8] = self.lastFields[3]
-
- packet = binaryFields.packHeaders() + binaryFields.packFooter()
-
- self.state = self.SEND_200OK
- self.lastSentFields = binaryFields
- return packet
-
- if(self.state == self.SEND_200OK):
- msg = MSNSLPMessage()
- msg.create(status="200 OK", to=self.to, fro=self.fro, cseq=1, sessionGuid=self.sguid)
- msg.setData(sessionID=self.sessionID)
- msgStr = str(msg)
-
- binaryFields = BinaryFields()
- binaryFields[1] = self.baseID.next()
- binaryFields[3] = len(msgStr)
- binaryFields[4] = len(msgStr)
- binaryFields[6] = random.randint(0, 2**30)
-
- packet = binaryFields.packHeaders() + msgStr + binaryFields.packFooter()
-
- self.state = self.WAIT_200OK_ACK
- self.lastSentFields = binaryFields
- return packet
-
- if(self.state == self.SEND_DATAPREP):
- binaryFields = BinaryFields()
- binaryFields[0] = self.sessionID
- binaryFields[1] = self.baseID.next()
- binaryFields[3] = 4
- binaryFields[4] = 4
- binaryFields[6] = random.randint(0, 2**30)
- binaryFields[9] = 1
-
- packet = binaryFields.packHeaders() + chr(0) * 4 + binaryFields.packFooter()
-
- self.state = self.WAIT_DATAPREP_ACK
- self.lastSentFields = binaryFields
- return packet
-
- if(self.state == self.SEND_DATA):
- binaryFields = BinaryFields()
- binaryFields[0] = self.sessionID
- binaryFields[1] = self.baseID.get()
- binaryFields[2] = self.fileOffset
- binaryFields[3] = len(self.msnobj.imageData)
- binaryFields[5] = BinaryFields.DATA
- binaryFields[6] = random.randint(0, 2**30)
- binaryFields[9] = 1
-
- # Work out what part of the file we're sending
- length = len(self.msnobj.imageData) - self.fileOffset
- if(length > 1202):
- # Max amount per message is 1202
- length = 1202
- else:
- # Last packet!
- self.state = self.WAIT_BYE
- self.lastSentFields = binaryFields
- binaryFields[4] = length
- chunk = self.msnobj.imageData[self.fileOffset : self.fileOffset + length]
- self.fileOffset += length
-
- packet = binaryFields.packHeaders() + chunk + binaryFields.packFooter()
- return packet
-
- if(self.state == self.SEND_BYE_ACK):
- binaryFields = BinaryFields()
- binaryFields[1] = self.baseID.next()
- binaryFields[3] = self.lastFields[3]
- binaryFields[5] = BinaryFields.BYEGOT
- binaryFields[6] = self.lastFields[1]
- binaryFields[7] = self.lastFields[6]
- binaryFields[8] = self.lastFields[3]
-
- packet = binaryFields.packHeaders() + binaryFields.packFooter()
-
- self.state = self.FINISHED
- self.lastSentFields = binaryFields
- return packet
-
-
-
-
-class MSNP2P_Avatar_Receive(MSNP2P_Avatar):
- # Avatar_Receive states
- SEND_REQUEST = 0 # Send the request
- WAIT_REQACK_200OK = 1 # Wait for REQACK and 200OK message
- # Skip one value so we know both of the above have been done
- SEND_200OK_ACK = 3 # Received both of the above
- WAIT_DATAPREP = 4 # Wait for DATAPREP
- SEND_DATAPREP_ACK = 5 # Send ACK to above
- WAIT_DATA = 6 # Wait for all data messages and send DATA_ACK
- SEND_DATA_ACK = 7 # Then send BYE
- SEND_BYE = 8
- FINISHED = 9
-
- def __init__(self, to, fro, msnobj):
- self.to = to
- self.fro = fro
- self.msnobj = msnobj
- self.sessionID = random.randint(0, 2**30)
- self.sguid = random_guid()
- self.baseID = BaseID()
- self.state = self.SEND_REQUEST
- self.lastFields = BinaryFields()
- self.lastSentFields = BinaryFields()
- self.fileData = None
-
- def getImage(self):
- if(self.state >= self.SEND_BYE):
- return self.fileData.data
-
- def processPacket(self, packet):
- if MSNP2P_DEBUG:
- print "processPacket", self.to, self.fro, self.state
- if(self.state == self.WAIT_REQACK_200OK or self.state == self.WAIT_REQACK_200OK + 1):
- binaryFields = BinaryFields()
- binaryFields.unpackFields(packet)
-
- if(binaryFields[5] == BinaryFields.ACK):
- # REQUESTACK!
- if(binaryFields[6] != self.lastSentFields[1]):
- self.warn("field6," + str(binaryFields[6]) + "," + str(self.lastSentFields[1]))
- return
- if(binaryFields[3] != self.lastSentFields[3]):
- self.setError("field3," + str(binaryFields[3]) + "," + str(self.lastSentFields[3]))
- return
- if(binaryFields[7] != self.lastSentFields[6]):
- self.setError("field7," + str(binaryFields[7]) + "," + str(self.lastSentFields[6]))
- return
- if(binaryFields[8] != self.lastSentFields[3]):
- self.setError("field8," + str(binaryFields[8]) + "," + str(self.lastSentFields[3]))
- return
-
- self.state += 1
- return
-
- elif(binaryFields[5] == 0):
- # 200OK
- message = MSNSLPMessage()
- message.parse(packet)
- if(message.sessionID != self.sessionID):
- self.warn("sessionID" + str(message.sessionID) + "," + str(self.sessionID))
- return
- if(message.status != "200"):
- self.setError("status" + message.status)
- return
- if(message.cseq != 1):
- self.setError("cseq" + str(message.cseq))
- return
- if(message.sessionGuid != self.sguid):
- self.setError("sessionGuid" + message.sessionGuid + "," + self.sguid)
- return
-
- self.lastFields = binaryFields
- self.state += 1
- return
-
- else:
- self.warn("Packet discarded," + str(binaryFields[5]))
-
- if(self.state == self.WAIT_DATAPREP):
- binaryFields = BinaryFields()
- binaryFields.unpackFields(packet)
-
- if(binaryFields[0] != self.sessionID):
- self.warn("field0," + str(binaryFields[0]) + "," + str(self.sessionID))
- return
- if(binaryFields[3] != 4):
- self.setError("field3," + str(binaryFields[3]))
- return
- if(binaryFields[4] != 4):
- self.setError("field4," + str(binaryFields[4]))
- return
- if(binaryFields[9] != 1):
- self.warn("field9," + str(binaryFields[9]))
- # return
-
- self.lastFields = binaryFields
- self.state = self.SEND_DATAPREP_ACK
- return
-
- if(self.state == self.WAIT_DATA):
- binaryFields = BinaryFields()
- binaryFields.unpackFields(packet)
- if(binaryFields[0] != self.sessionID):
- self.warn("field0," + str(binaryFields[0]) + "," + str(self.sessionID))
- return
- if(binaryFields[5] != BinaryFields.DATA):
- self.setError("field5," + str(binaryFields[5]))
- return
- if(binaryFields[9] != 1):
- self.warn("field9," + str(binaryFields[9]))
- # return
- offset = binaryFields[2]
- total = binaryFields[3]
- length = binaryFields[4]
- if(not self.fileData):
- self.fileData = FileData(binaryFields[3])
-
- data = packet[48:len(packet)-4]
- self.fileData.put(offset, packet[48:len(packet)-4])
-
- if self.fileData.finished():
- self.state = self.SEND_DATA_ACK
-
- self.lastFields = binaryFields
-
- return
-
- def getNextPacket(self):
- if MSNP2P_DEBUG:
- print "getNextPacket (Avatar_Receive)", self.to, self.fro, self.state
- if(self.state == self.SEND_REQUEST):
- msg = MSNSLPMessage()
- msg.create(method="INVITE", to=self.to, fro=self.fro, cseq=0, sessionGuid=self.sguid)
- msg.setData(sessionID=self.sessionID, appID="1", guid=self.EUF_GUID, context=b64enc(self.msnobj.text + chr(0)))
- msgStr = str(msg)
-
- binaryFields = BinaryFields()
- binaryFields[1] = self.baseID.get()
- binaryFields[6] = random.randint(0, 2**30)
- binaryFields[3] = len(msgStr)
- binaryFields[4] = len(msgStr)
-
- packet = binaryFields.packHeaders() + msgStr + binaryFields.packFooter()
-
- self.state = self.WAIT_REQACK_200OK
- self.lastSentFields = binaryFields
- return packet
-
- if(self.state == self.SEND_200OK_ACK):
- binaryFields = BinaryFields()
- binaryFields[1] = self.baseID.next()
- binaryFields[3] = self.lastFields[3]
- binaryFields[8] = self.lastFields[3]
- binaryFields[5] = BinaryFields.ACK
- binaryFields[6] = self.lastFields[1]
- binaryFields[7] = self.lastFields[6]
-
- packet = binaryFields.packHeaders() + binaryFields.packFooter()
-
- self.state = self.WAIT_DATAPREP
- self.lastSentFields = binaryFields
- return packet
-
- if(self.state == self.SEND_DATAPREP_ACK):
- binaryFields = BinaryFields()
- binaryFields[0] = self.sessionID
- binaryFields[1] = self.baseID.next()
- binaryFields[3] = 4
- binaryFields[8] = 4
- binaryFields[5] = BinaryFields.ACK
- binaryFields[6] = self.lastFields[1]
- binaryFields[7] = self.lastFields[6]
-
- packet = binaryFields.packHeaders() + binaryFields.packFooter()
-
- self.state = self.WAIT_DATA
- self.lastSentFields = binaryFields
- return packet
-
- if(self.state == self.SEND_DATA_ACK):
- # FIXME Check hash!
- binaryFields = BinaryFields()
- binaryFields[0] = self.sessionID
- binaryFields[1] = self.baseID.next()
- binaryFields[3] = self.lastFields[3]
- binaryFields[8] = self.lastFields[3]
- binaryFields[5] = BinaryFields.ACK
- binaryFields[6] = self.lastFields[1]
- binaryFields[7] = self.lastFields[6]
-
- packet = binaryFields.packHeaders() + binaryFields.packFooter()
-
- self.state = self.SEND_BYE
- self.lastSentFields = binaryFields
- return packet
-
- if(self.state == self.SEND_BYE):
- msg = MSNSLPMessage()
- msg.create(method="BYE", to=self.to, fro=self.fro, cseq=0, sessionGuid=self.sguid)
- msgStr = str(msg)
-
- binaryFields = BinaryFields()
- binaryFields[1] = self.baseID.next()
- binaryFields[3] = len(msgStr)
- binaryFields[4] = len(msgStr)
- binaryFields[5] = BinaryFields.BYESENT
- binaryFields[6] = random.randint(0, 2**30)
-
- packet = binaryFields.packHeaders() + msgStr + binaryFields.packFooter()
-
- self.state = self.FINISHED
- self.lastSentFields = binaryFields
- return packet
-
-
-
-class SLPLink:
- def __init__(self, remoteUser, switchboard, sessionID, sessionGuid):
- if not sessionID:
- sessionID = random.randint(1000, sys.maxint)
- if not sessionGuid:
- sessionGuid = random_guid()
- self.remoteUser = remoteUser
- self.switchboard = switchboard
- self.sessionID = sessionID
- self.sessionGuid = sessionGuid
-
- def setError(self, text):
- if MSNP2P_DEBUG:
- print "ERROR in avatar transfer: ", self, text, "in state:", self.state
- self.state = self.ERROR
-
- def warn(self, text):
- if MSNP2P_DEBUG:
- print "Warning in avatar transfer: ", self, text, "in state:", self.state
-
-
-class SLPLink_Send(SLPLink):
- def __init__(self, remoteUser, switchboard, length, sessionID=None, sessionGuid=None):
- SLPLink.__init__(self, remoteUser, switchboard, sessionID, sessionGuid)
- self.handlePacket = None
- self.offset = 0
- self.length = length
- self.data = ""
- # Send dataprep
- self.send_dataprep()
-
- def send_dataprep(self):
- binaryFields = BinaryFields()
- binaryFields[0] = self.sessionID
- binaryFields[1] = self.baseID.next()
- binaryFields[3] = 4
- binaryFields[4] = 4
- binaryFields[6] = random.randint(0, sys.maxint)
- binaryFields[9] = 1
-
- self.switchboard._sendP2PMessage(binaryFields, chr(0) * 4)
-
- def write(self, data):
- i = 0
- length = len(data)
- while i < length:
- if i + 1202 < length:
- self._writeChunk(data[i:i+1202])
- i += 1202
- else:
- self.data += data
- if len(self.data) >= 1202:
- data = self.data
- self.data = ""
- self.write(data)
- return
-
- def _writeChunk(self, chunk):
- binaryFields = BinaryFields()
- binaryFields[0] = self.sessionID
- binaryFields[1] = self.baseID.get()
- binaryFields[2] = self.fileOffset
- binaryFields[3] = len(chunk)
- binaryFields[4] = self.length
- binaryFields[5] = BinaryFields.DATA
- binaryFields[6] = random.randint(0, 2**30)
- binaryFields[9] = 1
-
- self.offset += len(chunk)
- self.switchboard._sendP2PMessage(binaryFields, chunk)
-
- def finish(self):
- self._writeChunk(self.data)
- # FIXME Now tell the switchboard
-
- def error(self):
- pass
- # Same as above?
-
-
-class SLPLink_Receive(SLPLink):
- def __init__(self, remoteUser, switchboard, consumer, sessionID=None, sessionGuid=None):
- SLPLink.__init__(self, remoteUser, switchboard, sessionID, sessionGuid)
- self.consumer = consumer
- self.pos = 0
-
- self.handlePacket = wait_dataprep
-
- def wait_dataprep(self, packet):
- binaryFields = BinaryFields()
- binaryFields.unpackFields(packet)
-
- if binaryFields[0] != self.sessionID:
- self.warn("field0," + str(binaryFields[0]) + "," + str(self.sessionID))
- return
- if binaryFields[3] != 4:
- self.setError("field3," + str(binaryFields[3]))
- return
- if binaryFields[4] != 4:
- self.setError("field4," + str(binaryFields[4]))
- return
- if binaryFields[9] != 1:
- self.warn("field9," + str(binaryFields[9]))
- # return
-
- self.switchboard._sendP2PACK(self, binaryFields)
- self.handlePacket = self.wait_data
-
- def wait_data(self, packet):
- binaryFields = BinaryFields()
- binaryFields.unpackFields(packet)
- if binaryFields[0] != self.sessionID:
- self.warn("field0," + str(binaryFields[0]) + "," + str(self.sessionID))
- return
- if binaryFields[5] != BinaryFields.DATA:
- self.setError("field5," + str(binaryFields[5]))
- return
- if binaryFields[9] != 1):
- self.warn("field9," + str(binaryFields[9]))
- # return
- offset = binaryFields[2]
- total = binaryFields[3]
- length = binaryFields[4]
-
- data = packet[48:-4]
- if offset != self.pos:
- self.setError("Received packet out of order")
- self.consumer.error()
- return
- if len(data) != length:
- self.setError("Received bad length of slp")
- self.consumer.error()
- return
-
- self.pos += length
-
- self.consumer.write(data)
-
- if self.pos == total:
- self.switchboard._sendP2PACK(self, binaryFields)
- self.consumer.finish()
- self.switchboard.gotAvatarImage(self.remoteUser, self.fileData.data)
- self.handlePacket = None
- del self.switchboard.slpLinks[self.sessionID]
-
-
-
-
-class SwitchboardP2PMixin:
- def handleP2PMessage(self, message, cTypes):
- """ helper method for msnslp messages (file transfer & avatars) """
- packet = message.message
- binaryFields = msnp2p.BinaryFields(packet=packet)
- if binaryFields[0] != 0:
- slpLink = self.slpLinks[binaryFields[0]]
- if slpLink.remoteUser == message.userHandle:
- slpLink.handlePacket(packet)
- elif binaryFields[5] == BinaryFields.ACK or binaryFields[5] == BinaryFields.BYEGOT:
- pass # Ignore the ACKs
- else:
- slpMessage = msnp2p.MSNSLPMessage(packet)
- slpLink = None
- if slpMessage.method == "INVITE":
- if slpMessage.euf_guid == MSN_MSNFTP_GUID:
- slpLink = msnp2p.SLPLink_Receive(slpMessage.fro, slpMessage.sessionID, slpMessage.sessionGuid)
- context = msnp2p.FileContext(slpMessage.context)
- fileReceive = msnft.MSNP2P_Receive(context.filename, context.filesize, slpMessage.fro)
- elif slpMessage.euf_guid == MSN_AVATAR_GUID:
- slpLink = msnp2p.SLPLink_Send(slpMessage.fro, slpMessage.sessionID, slpMessage.sessionGuid)
- self._sendMSNSLPResponse(slpLink, "200 OK")
- if slpLink:
- self.slpLinks[slpMessage.sessionID] = slpLink
- else:
- if slpMessage.status != "200":
- for slpLink in self.slpLinks:
- if slpLink.sessionGuid == slpMessage.sessionGuid:
- del self.slpLinks[slpLink.sessionID]
- if slpMessage.method != "BYE":
- # Must be an error. If its a file transfer we need to signal that it failed
- slpLink.transferError()
- else:
- slpLink = self.slpLinks[slpMessage.sessionID]
- slpLink.transferReady()
- if slpLink:
- # Always need to ACK these packets if we can
- self._sendP2PACK(self, slpLink, binaryHeaders)
-
-
- def _sendP2PACK(self, slpLink, ackHeaders):
- binaryFields = msnp2p.BinaryFields()
- binaryFields[1] = slpLink.nextBaseID()
- binaryFields[3] = ackHeaders[3]
- binaryFields[5] = BinaryFields.ACK
- binaryFields[6] = ackHeaders[1]
- binaryFields[7] = ackHeaders[6]
- binaryFields[8] = ackHeaders[3]
- self._sendP2PMessage(binaryFields, "")
-
- def _sendMSNSLPCommand(self, command, slpLink, guid, context):
- msg = msnp2p.MSNSLP_Message()
- msg.create(method=command, to=slpLink.remoteUser, fro=self.userHandle, cseq=0, sessionGuid=slpLink.sessionGuid)
- msg.setData(sessionID=slpLink.sessionID, appID="1", guid=guid, context=msnp2p.b64enc(context + chr(0)))
- self._sendMSNSLPMessage(slpLink, msg)
-
- def _sendMSNSLPResponse(self, slpLink, response):
- msg = msnp2p.MSNSLPMessage()
- msg.create(status=response, to=slpLink.remoteUser, fro=self.userHandle, cseq=1, sessionGuid=slpLink.sessionGuid)
- msg.setData(sessionID=slpLink.sessionID)
- self._sendMSNSLPMessage(slpLink, msg)
-
- def _sendMSNSLPMessage(self, slpLink, msnSlpMessage):
- msgStr = str(msg)
- binaryFields = msnp2p.BinaryFields()
- binaryFields[1] = slpLink.nextBaseID()
- binaryFields[3] = len(msgStr)
- binaryFields[4] = binaryFields[3]
- binaryFields[6] = random.randint(0, sys.maxint)
- self._sendP2PMessage(binaryFields, msgStr)
-
- def _sendP2PMessage(self, binaryFields, msgStr):
- packet = binaryFields.packHeaders() + msgStr + binaryFields.packFooter()
-
- message = MSNMessage(message=packet)
- message.setHeader("Content-Type", "application/x-msnmsgrp2p")
- message.setHeader("P2P-Dest", handler.to)
- message.ack = MSNMessage.MESSAGE_ACK_FAT
- self.sendMessage(message)
-
-