]>
code.delx.au - pymsnt/blob - src/tlib/msnp2p.py
1 # Copyright 2005 James Bunton <james@delx.cjb.net>
2 # Licensed for distribution under the GPL version 2, check COPYING for details
23 def setData(self
, creator
, imageData
):
24 self
.creator
= creator
25 self
.imageData
= imageData
26 self
.size
= len(imageData
)
28 self
.location
= "TMP" + str(random
.randint(1000,9999))
29 self
.friendly
= "AAA="
30 self
.sha1d
= utils
.b64enc(sha
.sha(imageData
).digest())
46 h
.append(self
.creator
)
48 h
.append(str(self
.size
))
50 h
.append(str(self
.type))
52 h
.append(self
.location
)
54 h
.append(self
.friendly
)
57 sha1c
= utils
.b64enc(sha
.sha("".join(h
)).digest())
58 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
)
61 e
= utils
.parseText(s
)
62 self
.creator
= e
.getAttribute("Creator")
63 self
.size
= int(e
.getAttribute("Size"))
64 self
.type = int(e
.getAttribute("Type"))
65 self
.location
= e
.getAttribute("Location")
66 self
.friendly
= e
.getAttribute("Friendly")
67 self
.sha1d
= e
.getAttribute("SHA1D")
81 def __init__(self
, fields
=None):
86 def __getitem__(self
, key
):
87 return self
.fields
[key
]
89 def __setitem__(self
, key
, value
):
90 self
.fields
[key
] = value
92 def unpackFields(self
, packet
):
93 self
.fields
= struct
.unpack("<LLQQLLLLQ", packet
[0:48])
94 self
.fields
+= struct
.unpack(">L", packet
[len(packet
)-4:])
96 print "Unpacked fields:",
101 def packHeaders(self
):
102 f
= tuple(self
.fields
)
104 print "Packed fields:",
105 for i
in self
.fields
:
108 return struct
.pack("<LLQQLLLLQ", f
[0], f
[1], f
[2], f
[3], f
[4], f
[5], f
[6], f
[7], f
[8])
110 def packFooter(self
):
111 return struct
.pack(">L", self
.fields
[9])
121 self
.sessionGuid
= ""
122 self
.sessionID
= None
124 self
.data
= "\r\n" + chr(0)
126 def create(self
, method
=None, status
=None, to
=None, fro
=None, cseq
=0, sessionGuid
=None, data
=None):
132 self
.sessionGuid
= sessionGuid
133 if(data
): self
.data
= data
135 def setData(self
, sessionID
=None, appID
=None, guid
=None, context
=None):
137 if(guid
): s
.append("EUF-GUID: %s\r\n" % guid
)
138 if(sessionID
): s
.append("SessionID: %s\r\n" % sessionID
)
139 if(appID
): s
.append("AppID: %s\r\n" % appID
)
140 if(context
): s
.append("Context: %s\r\n\r\n" % context
)
143 self
.data
= "".join(s
)
147 if s
.find("MSNSLP/1.0") < 0: return
149 lines
= s
.split("\r\n")
151 # Get the MSNSLP method or status
152 msnslp
= lines
[0].split(" ")
153 if MSNP2P_DEBUG
: print "Parsing MSNSLPMessage", s
, len(s
)
154 if(msnslp
[0] in ("INVITE", "BYE")):
155 self
.method
= msnslp
[0].strip()
157 self
.status
= msnslp
[1].strip()
159 lines
.remove(lines
[0])
162 line
= line
.split(":")
164 if(len(line
) > 2 and line
[0] == "To"):
165 self
.to
= line
[2][:line
[2].find('>')]
166 elif(len(line
) > 2 and line
[0] == "From"):
167 self
.fro
= line
[2][:line
[2].find('>')]
168 elif(line
[0] == "Call-ID"):
169 self
.sessionGuid
= line
[1].strip()
170 elif(line
[0] == "CSeq"):
171 self
.cseq
= int(line
[1].strip())
172 elif(line
[0] == "SessionID"):
173 self
.sessionID
= int(line
[1].strip())
174 elif(line
[0] == "EUF-GUID"):
175 self
.euf_guid
= line
[1].strip()
180 s
.append("%s MSNMSGR:%s MSNSLP/1.0\r\n" % (self
.method
, self
.to
))
182 s
.append("MSNSLP/1.0 %s\r\n" % self
.status
)
183 s
.append("To: <msnmsgr:%s>\r\n" % self
.to
)
184 s
.append("From: <msnmsgr:%s>\r\n" % self
.fro
)
185 s
.append("Via: MSNSLP/1.0/TLP ;branch=%s\r\n" % utils
.random_guid())
186 s
.append("CSeq: %s \r\n" % str(self
.cseq
))
187 s
.append("Call-ID: %s\r\n" % self
.sessionGuid
)
188 s
.append("Max-Forwards: 0\r\n")
189 if(self
.method
== "BYE"):
190 s
.append("Content-Type: application/x-msnmsgr-sessionclosebody\r\n")
192 s
.append("Content-Type: application/x-msnmsgr-sessionreqbody\r\n")
193 s
.append("Content-Length: %s\r\n\r\n" % len(self
.data
))
199 def __init__(self
, baseID
=None, sender
=False):
203 self
.baseID
= random
.randint(4, 2**30)
214 return self
.baseID
+ self
.pos
- 3
218 if self
.pos
== 3 and self
.sender
:
223 def __init__(self
, size
):
224 self
.data
= chr(0) * size
225 self
.totalSize
= size
228 def put(self
, offset
, data
):
229 self
.data
= self
.data
[0:offset
] + data
+ self
.data
[offset
+len(data
):]
230 self
.gotSize
+= len(data
)
233 return self
.gotSize
>= self
.totalSize
240 EUF_GUID
= "{A4268EEC-FEC5-49E5-95C3-F126696BDBF6}"
244 raise "NotImplemented"
249 def isFinished(self
):
250 if self
.state
>= self
.FINISHED
:
251 MSNP2P_Avatar
.TRANSFER_COUNT
+= 1
254 MSNP2P_Avatar
.ERROR_COUNT
+= 1
259 def setError(self
, text
):
261 print "ERROR in avatar transfer: ", self
, text
, "in state:", self
.state
262 self
.state
= self
.ERROR
264 def warn(self
, text
):
266 print "Warning in avatar transfer: ", self
, text
, "in state:", self
.state
269 class MSNP2P_Avatar_Send(MSNP2P_Avatar
):
276 WAIT_DATAPREP_ACK
= 5
282 def __init__(self
, to
, fro
, msnobj
):
286 self
.fileOffset
= 0 # The amount already sent
288 self
.baseID
= BaseID(sender
=True)
289 self
.state
= self
.WAIT_REQUEST
290 self
.lastFields
= BinaryFields()
291 self
.lastSentFields
= BinaryFields()
293 def processPacket(self
, packet
):
295 print "processPacket", self
.to
, self
.fro
, self
.state
296 if(self
.state
== self
.WAIT_REQUEST
):
297 message
= MSNSLPMessage()
298 message
.parse(packet
)
299 if(message
.method
!= "INVITE"):
300 self
.setError("method" + message
.method
)
302 if(message
.cseq
!= 0):
303 self
.setError("cseq" + str(message
.cseq
))
305 if(message
.euf_guid
!= self
.EUF_GUID
):
306 self
.setError("guid" + message
.euf_guid
)
309 binaryFields
= BinaryFields()
310 binaryFields
.unpackFields(packet
)
312 self
.sguid
= message
.sessionGuid
313 self
.sessionID
= message
.sessionID
315 self
.lastFields
= binaryFields
316 self
.state
= self
.SEND_REQACK
319 if(self
.state
== self
.WAIT_200OK_ACK
):
320 binaryFields
= BinaryFields()
321 binaryFields
.unpackFields(packet
)
323 if(binaryFields
[6] != self
.lastSentFields
[1]):
324 self
.warn("field6," + str(binaryFields
[6]) + "," + str(self
.lastSentFields
[1]))
326 if(binaryFields
[3] != self
.lastSentFields
[3]):
327 self
.setError("field3," + str(binaryFields
[3]) + "," + str(self
.lastSentFields
[3]))
329 if(binaryFields
[8] != self
.lastSentFields
[3]):
330 self
.setError("field8," + str(binaryFields
[8]) + "," + str(self
.lastSentFields
[3]))
332 if(binaryFields
[5] != BinaryFields
.ACK
):
333 self
.setError("field5," + str(binaryFields
[5]))
336 self
.lastFields
= binaryFields
337 self
.state
= self
.SEND_DATAPREP
340 if(self
.state
== self
.WAIT_DATAPREP_ACK
):
341 binaryFields
= BinaryFields()
342 binaryFields
.unpackFields(packet
)
344 if(binaryFields
[0] != self
.sessionID
):
345 self
.warn("field0," + str(binaryFields
[0]) + "," + str(self
.sessionID
))
347 if(binaryFields
[3] != self
.lastSentFields
[3]):
348 self
.setError("field3," + str(binaryFields
[3]) + "," + str(self
.lastSentFields
[3]))
350 if(binaryFields
[8] != self
.lastSentFields
[3]):
351 self
.setError("field8," + str(binaryFields
[8]) + "," + str(self
.lastSentFields
[3]))
353 if(binaryFields
[5] != BinaryFields
.ACK
):
354 self
.setError("field5," + str(binaryFields
[5]))
356 if(binaryFields
[6] != self
.lastSentFields
[1]):
357 self
.setError("field6," + str(binaryFields
[6]) + "," + str(self
.lastSentFields
[1]))
359 if(binaryFields
[7] != self
.lastSentFields
[6]):
360 self
.setError("field7," + str(binaryFields
[7]) + "," + str(self
.lastSentFields
[6]))
363 self
.lastFields
= binaryFields
365 self
.state
= self
.SEND_DATA
368 if(self
.state
== self
.WAIT_BYE
):
369 binaryFields
= BinaryFields()
370 binaryFields
.unpackFields(packet
)
373 message
= MSNSLPMessage()
374 message
.parse(packet
)
375 if(message
.sessionGuid
!= self
.sguid
):
376 self
.warn("sessionGuid" + message
.sessionGuid
)
378 if(message
.method
!= "BYE"):
379 self
.setError("method " + message
.method
)
381 if(message
.cseq
!= 0):
382 self
.setError("cseq" + str(message
.cseq
))
385 self
.lastFields
= binaryFields
386 self
.state
= self
.SEND_BYE_ACK
# I don't really care about receiving the data ack
390 def getNextPacket(self
):
392 print "getNextPacket (Avatar_Send)", self
.to
, self
.fro
, self
.state
393 if(self
.state
== self
.SEND_REQACK
):
394 binaryFields
= BinaryFields()
395 binaryFields
[1] = self
.baseID
.get()
396 binaryFields
[3] = self
.lastFields
[3]
397 binaryFields
[5] = BinaryFields
.ACK
398 binaryFields
[6] = self
.lastFields
[1]
399 binaryFields
[7] = self
.lastFields
[6]
400 binaryFields
[8] = self
.lastFields
[3]
402 packet
= binaryFields
.packHeaders() + binaryFields
.packFooter()
404 self
.state
= self
.SEND_200OK
405 self
.lastSentFields
= binaryFields
408 if(self
.state
== self
.SEND_200OK
):
409 msg
= MSNSLPMessage()
410 msg
.create(status
="200 OK", to
=self
.to
, fro
=self
.fro
, cseq
=1, sessionGuid
=self
.sguid
)
411 msg
.setData(sessionID
=self
.sessionID
)
414 binaryFields
= BinaryFields()
415 binaryFields
[1] = self
.baseID
.next()
416 binaryFields
[3] = len(msgStr
)
417 binaryFields
[4] = len(msgStr
)
418 binaryFields
[6] = random
.randint(0, 2**30)
420 packet
= binaryFields
.packHeaders() + msgStr
+ binaryFields
.packFooter()
422 self
.state
= self
.WAIT_200OK_ACK
423 self
.lastSentFields
= binaryFields
426 if(self
.state
== self
.SEND_DATAPREP
):
427 binaryFields
= BinaryFields()
428 binaryFields
[0] = self
.sessionID
429 binaryFields
[1] = self
.baseID
.next()
432 binaryFields
[6] = random
.randint(0, 2**30)
435 packet
= binaryFields
.packHeaders() + chr(0) * 4 + binaryFields
.packFooter()
437 self
.state
= self
.WAIT_DATAPREP_ACK
438 self
.lastSentFields
= binaryFields
441 if(self
.state
== self
.SEND_DATA
):
442 binaryFields
= BinaryFields()
443 binaryFields
[0] = self
.sessionID
444 binaryFields
[1] = self
.baseID
.get()
445 binaryFields
[2] = self
.fileOffset
446 binaryFields
[3] = len(self
.msnobj
.imageData
)
447 binaryFields
[5] = BinaryFields
.DATA
448 binaryFields
[6] = random
.randint(0, 2**30)
451 # Work out what part of the file we're sending
452 length
= len(self
.msnobj
.imageData
) - self
.fileOffset
454 # Max amount per message is 1202
458 self
.state
= self
.WAIT_BYE
459 self
.lastSentFields
= binaryFields
460 binaryFields
[4] = length
461 chunk
= self
.msnobj
.imageData
[self
.fileOffset
: self
.fileOffset
+ length
]
462 self
.fileOffset
+= length
464 packet
= binaryFields
.packHeaders() + chunk
+ binaryFields
.packFooter()
467 if(self
.state
== self
.SEND_BYE_ACK
):
468 binaryFields
= BinaryFields()
469 binaryFields
[1] = self
.baseID
.next()
470 binaryFields
[3] = self
.lastFields
[3]
471 binaryFields
[5] = BinaryFields
.BYEGOT
472 binaryFields
[6] = self
.lastFields
[1]
473 binaryFields
[7] = self
.lastFields
[6]
474 binaryFields
[8] = self
.lastFields
[3]
476 packet
= binaryFields
.packHeaders() + binaryFields
.packFooter()
478 self
.state
= self
.FINISHED
479 self
.lastSentFields
= binaryFields
485 class MSNP2P_Avatar_Receive(MSNP2P_Avatar
):
486 # Avatar_Receive states
487 SEND_REQUEST
= 0 # Send the request
488 WAIT_REQACK_200OK
= 1 # Wait for REQACK and 200OK message
489 # Skip one value so we know both of the above have been done
490 SEND_200OK_ACK
= 3 # Received both of the above
491 WAIT_DATAPREP
= 4 # Wait for DATAPREP
492 SEND_DATAPREP_ACK
= 5 # Send ACK to above
493 WAIT_DATA
= 6 # Wait for all data messages and send DATA_ACK
494 SEND_DATA_ACK
= 7 # Then send BYE
498 def __init__(self
, to
, fro
, msnobj
):
502 self
.sessionID
= random
.randint(0, 2**30)
503 self
.sguid
= utils
.random_guid()
504 self
.baseID
= BaseID()
505 self
.state
= self
.SEND_REQUEST
506 self
.lastFields
= BinaryFields()
507 self
.lastSentFields
= BinaryFields()
511 if(self
.state
>= self
.SEND_BYE
):
512 return self
.fileData
.data
514 def processPacket(self
, packet
):
516 print "processPacket", self
.to
, self
.fro
, self
.state
517 if(self
.state
== self
.WAIT_REQACK_200OK
or self
.state
== self
.WAIT_REQACK_200OK
+ 1):
518 binaryFields
= BinaryFields()
519 binaryFields
.unpackFields(packet
)
521 if(binaryFields
[5] == BinaryFields
.ACK
):
523 if(binaryFields
[6] != self
.lastSentFields
[1]):
524 self
.warn("field6," + str(binaryFields
[6]) + "," + str(self
.lastSentFields
[1]))
526 if(binaryFields
[3] != self
.lastSentFields
[3]):
527 self
.setError("field3," + str(binaryFields
[3]) + "," + str(self
.lastSentFields
[3]))
529 if(binaryFields
[7] != self
.lastSentFields
[6]):
530 self
.setError("field7," + str(binaryFields
[7]) + "," + str(self
.lastSentFields
[6]))
532 if(binaryFields
[8] != self
.lastSentFields
[3]):
533 self
.setError("field8," + str(binaryFields
[8]) + "," + str(self
.lastSentFields
[3]))
539 elif(binaryFields
[5] == 0):
541 message
= MSNSLPMessage()
542 message
.parse(packet
)
543 if(message
.sessionID
!= self
.sessionID
):
544 self
.warn("sessionID" + str(message
.sessionID
) + "," + str(self
.sessionID
))
546 if(message
.status
!= "200"):
547 self
.setError("status" + message
.status
)
549 if(message
.cseq
!= 1):
550 self
.setError("cseq" + str(message
.cseq
))
552 if(message
.sessionGuid
!= self
.sguid
):
553 self
.setError("sessionGuid" + message
.sessionGuid
+ "," + self
.sguid
)
556 self
.lastFields
= binaryFields
561 self
.warn("Packet discarded," + str(binaryFields
[5]))
563 if(self
.state
== self
.WAIT_DATAPREP
):
564 binaryFields
= BinaryFields()
565 binaryFields
.unpackFields(packet
)
567 if(binaryFields
[0] != self
.sessionID
):
568 self
.warn("field0," + str(binaryFields
[0]) + "," + str(self
.sessionID
))
570 if(binaryFields
[3] != 4):
571 self
.setError("field3," + str(binaryFields
[3]))
573 if(binaryFields
[4] != 4):
574 self
.setError("field4," + str(binaryFields
[4]))
576 if(binaryFields
[9] != 1):
577 self
.warn("field9," + str(binaryFields
[9]))
580 self
.lastFields
= binaryFields
581 self
.state
= self
.SEND_DATAPREP_ACK
584 if(self
.state
== self
.WAIT_DATA
):
585 binaryFields
= BinaryFields()
586 binaryFields
.unpackFields(packet
)
587 if(binaryFields
[0] != self
.sessionID
):
588 self
.warn("field0," + str(binaryFields
[0]) + "," + str(self
.sessionID
))
590 if(binaryFields
[5] != BinaryFields
.DATA
):
591 self
.setError("field5," + str(binaryFields
[5]))
593 if(binaryFields
[9] != 1):
594 self
.warn("field9," + str(binaryFields
[9]))
596 offset
= binaryFields
[2]
597 total
= binaryFields
[3]
598 length
= binaryFields
[4]
599 if(not self
.fileData
):
600 self
.fileData
= FileData(binaryFields
[3])
602 data
= packet
[48:len(packet
)-4]
603 self
.fileData
.put(offset
, packet
[48:len(packet
)-4])
605 if self
.fileData
.finished():
606 self
.state
= self
.SEND_DATA_ACK
608 self
.lastFields
= binaryFields
612 def getNextPacket(self
):
614 print "getNextPacket (Avatar_Receive)", self
.to
, self
.fro
, self
.state
615 if(self
.state
== self
.SEND_REQUEST
):
616 msg
= MSNSLPMessage()
617 msg
.create(method
="INVITE", to
=self
.to
, fro
=self
.fro
, cseq
=0, sessionGuid
=self
.sguid
)
618 msg
.setData(sessionID
=self
.sessionID
, appID
="1", guid
=self
.EUF_GUID
, context
=utils
.b64enc(self
.msnobj
.text
+ chr(0)))
621 binaryFields
= BinaryFields()
622 binaryFields
[1] = self
.baseID
.get()
623 binaryFields
[6] = random
.randint(0, 2**30)
624 binaryFields
[3] = len(msgStr
)
625 binaryFields
[4] = len(msgStr
)
627 packet
= binaryFields
.packHeaders() + msgStr
+ binaryFields
.packFooter()
629 self
.state
= self
.WAIT_REQACK_200OK
630 self
.lastSentFields
= binaryFields
633 if(self
.state
== self
.SEND_200OK_ACK
):
634 binaryFields
= BinaryFields()
635 binaryFields
[1] = self
.baseID
.next()
636 binaryFields
[3] = self
.lastFields
[3]
637 binaryFields
[8] = self
.lastFields
[3]
638 binaryFields
[5] = BinaryFields
.ACK
639 binaryFields
[6] = self
.lastFields
[1]
640 binaryFields
[7] = self
.lastFields
[6]
642 packet
= binaryFields
.packHeaders() + binaryFields
.packFooter()
644 self
.state
= self
.WAIT_DATAPREP
645 self
.lastSentFields
= binaryFields
648 if(self
.state
== self
.SEND_DATAPREP_ACK
):
649 binaryFields
= BinaryFields()
650 binaryFields
[0] = self
.sessionID
651 binaryFields
[1] = self
.baseID
.next()
654 binaryFields
[5] = BinaryFields
.ACK
655 binaryFields
[6] = self
.lastFields
[1]
656 binaryFields
[7] = self
.lastFields
[6]
658 packet
= binaryFields
.packHeaders() + binaryFields
.packFooter()
660 self
.state
= self
.WAIT_DATA
661 self
.lastSentFields
= binaryFields
664 if(self
.state
== self
.SEND_DATA_ACK
):
666 binaryFields
= BinaryFields()
667 binaryFields
[0] = self
.sessionID
668 binaryFields
[1] = self
.baseID
.next()
669 binaryFields
[3] = self
.lastFields
[3]
670 binaryFields
[8] = self
.lastFields
[3]
671 binaryFields
[5] = BinaryFields
.ACK
672 binaryFields
[6] = self
.lastFields
[1]
673 binaryFields
[7] = self
.lastFields
[6]
675 packet
= binaryFields
.packHeaders() + binaryFields
.packFooter()
677 self
.state
= self
.SEND_BYE
678 self
.lastSentFields
= binaryFields
681 if(self
.state
== self
.SEND_BYE
):
682 msg
= MSNSLPMessage()
683 msg
.create(method
="BYE", to
=self
.to
, fro
=self
.fro
, cseq
=0, sessionGuid
=self
.sguid
)
686 binaryFields
= BinaryFields()
687 binaryFields
[1] = self
.baseID
.next()
688 binaryFields
[3] = len(msgStr
)
689 binaryFields
[4] = len(msgStr
)
690 binaryFields
[5] = BinaryFields
.BYESENT
691 binaryFields
[6] = random
.randint(0, 2**30)
693 packet
= binaryFields
.packHeaders() + msgStr
+ binaryFields
.packFooter()
695 self
.state
= self
.FINISHED
696 self
.lastSentFields
= binaryFields