X-Git-Url: https://code.delx.au/pymsnt/blobdiff_plain/5cf86b62f7bd37c5d68535c9ea3812f54844a684..cc447943af3bbac238973eda368ba9c22174d1f9:/src/tlib/msn/msn.py diff --git a/src/tlib/msn/msn.py b/src/tlib/msn/msn.py index 6b70a08..96aa587 100644 --- a/src/tlib/msn/msn.py +++ b/src/tlib/msn/msn.py @@ -100,9 +100,12 @@ import msnp11chl from twisted.internet import reactor, task from twisted.internet.defer import Deferred from twisted.internet.protocol import ClientFactory -from twisted.internet.ssl import ClientContextFactory +try: + from twisted.internet.ssl import ClientContextFactory +except ImportError: + print "You must install pycrypto and pyopenssl." + raise from twisted.python import failure, log -from twisted.xish.domish import unescapeFromXml # Compat stuff from tlib import xmlw @@ -430,7 +433,7 @@ class MSNMessage: self.screenName = screenName self.specialMessage = specialMessage self.message = message - self.headers = {'MIME-Version' : '1.0', 'Content-Type' : 'text/plain'} + self.headers = {'MIME-Version' : '1.0', 'Content-Type' : 'text/plain; charset=UTF-8'} self.length = length self.readPos = 0 @@ -441,6 +444,11 @@ class MSNMessage: """ return reduce(operator.add, [len(x[0]) + len(x[1]) + 4 for x in self.headers.items()]) + len(self.message) + 2 + def delHeader(self, header): + """ delete the desired header """ + if self.headers.has_key(header): + del self.headers[header] + def setHeader(self, header, value): """ set the desired header """ self.headers[header] = value @@ -834,9 +842,13 @@ class MSNEventBase(LineReceiver): m = self.currentMessage self.currentMessage = None if MESSAGEDEBUG: log.msg(m.message) - if not self.checkMessage(m): + try: + if not self.checkMessage(m): + self.setLineMode(extra) + return + except Exception, e: self.setLineMode(extra) - return + raise self.gotMessage(m) self.setLineMode(extra) @@ -1040,16 +1052,17 @@ class NotificationClient(MSNEventBase): self.gotMSNAlert(bodytext, actionurl, subscrurl) def _gotUBX(self, message): + msnContact = self.factory.contacts.getContact(message.userHandle) + if not msnContact: return lm = message.message.lower() p1 = lm.find("") + 5 p2 = lm.find("") if p1 >= 0 and p2 >= 0: - personal = unescapeFromXml(message.message[p1:p2]) - msnContact = self.factory.contacts.getContact(message.userHandle) - if not msnContact: return + personal = xmlw.unescapeFromXml(message.message[p1:p2]) msnContact.personal = personal self.contactPersonalChanged(message.userHandle, personal) else: + msnContact.personal = '' self.contactPersonalChanged(message.userHandle, '') def checkMessage(self, message): @@ -1363,7 +1376,7 @@ class NotificationClient(MSNEventBase): self.currentMessage = MSNMessage(length=messageLen, userHandle=params[0], screenName="UBX", specialMessage=True) self.setRawMode() else: - self.contactPersonalChanged(params[0], '') + self._gotUBX(MSNMessage(userHandle=params[0])) def handle_UUX(self, params): checkParamLen(len(params), 2, 'UUX') @@ -2090,7 +2103,7 @@ class SwitchboardClient(MSNEventBase): cookie = info['Invitation-Cookie'] filename = info['Application-File'] filesize = int(info['Application-FileSize']) - connectivity = (info.get('Connectivity').lower() == 'y') + connectivity = (info.get('Connectivity', 'n').lower() == 'y') except KeyError: log.msg('Received munged file transfer request ... ignoring.') return 0 @@ -2103,14 +2116,16 @@ class SwitchboardClient(MSNEventBase): if not message.getHeader("P2P-Dest") == self.userHandle: return packet = message.message binaryFields = BinaryFields(packet=packet) - if binaryFields[0] != 0: + if binaryFields[5] == BinaryFields.BYEGOT: + pass # Ignore the ACKs to SLP messages + elif binaryFields[0] != 0: slpLink = self.slpLinks.get(binaryFields[0]) if not slpLink: # Link has been killed. Ignore return if slpLink.remoteUser == message.userHandle: slpLink.handlePacket(packet) - if binaryFields[5] == BinaryFields.ACK or binaryFields[5] == BinaryFields.BYEGOT: + elif binaryFields[5] == BinaryFields.ACK: pass # Ignore the ACKs to SLP messages else: slpMessage = MSNSLPMessage(packet) @@ -2322,11 +2337,13 @@ class SwitchboardClient(MSNEventBase): else: id, d = self._createIDMapping() if message.length == 0: message.length = message._calcMessageLen() self.sendLine("MSG %s %s %s" % (id, message.ack, message.length)) - # apparently order matters with at least MIME-Version and Content-Type - self.sendLine('MIME-Version: %s' % message.getHeader('MIME-Version')) - self.sendLine('Content-Type: %s' % message.getHeader('Content-Type')) + # Apparently order matters with these + orderMatters = ("MIME-Version", "Content-Type", "Message-ID") + for header in orderMatters: + if message.hasHeader(header): + self.sendLine("%s: %s" % (header, message.getHeader(header))) # send the rest of the headers - for header in [h for h in message.headers.items() if h[0].lower() not in ('mime-version','content-type')]: + for header in [h for h in message.headers.items() if h[0] not in orderMatters]: self.sendLine("%s: %s" % (header[0], header[1])) self.transport.write("\r\n") self.transport.write(message.message) @@ -2703,7 +2720,9 @@ class SLPLink: self.seqID = SeqID() def killLink(self): + if MSNP2PDEBUG: log.msg("killLink") def kill(): + if MSNP2PDEBUG: log.msg("killLink - kill()") if not self.switchboard: return del self.switchboard.slpLinks[self.sessionID] self.switchboard = None @@ -2778,21 +2797,19 @@ class SLPLink_Send(SLPLink): def write(self, data): if MSNP2PDEBUG: log.msg("write") i = 0 + data = self.data + data + self.data = "" length = len(data) while i < length: if i + 1202 < length: self._writeChunk(data[i:i+1202]) i += 1202 else: - self.data += data[i:] - if len(self.data) >= 1202: - data = self.data - self.data = "" - self.write(data) + self.data = data[i:] return def _writeChunk(self, chunk): - log.msg("writing chunk") + if MSNP2PDEBUG: log.msg("writing chunk") binaryFields = BinaryFields() binaryFields[0] = self.sessionID if self.offset == 0: @@ -2848,7 +2865,7 @@ class SLPLink_FileSend(SLPLink_Send): else: if slpMessage.status == "603": self.acceptDeferred.callback((False,)) - # SLPLink is over due to decline, error or BYE + if MSNP2PDEBUG: log.msg("SLPLink is over due to decline, error or BYE") self.killLink() def wait_data_ack(self, packet): @@ -2877,7 +2894,8 @@ class SLPLink_AvatarSend(SLPLink_Send): self.handlePacket = lambda packet: None def handleSLPMessage(self, slpMessage): - self.killLink() # BYE or error + if MSNP2PDEBUG: log.msg("BYE or error") + self.killLink() def close(self): SLPLink_Send.close(self) @@ -2958,12 +2976,15 @@ class SLPLink_FileReceive(SLPLink_Receive, FileReceive): def reject(self): # Send a 603 decline + if not self.switchboard: return self.sendSLPMessage("603", "application/x-msnmsgr-sessionreqbody", {"SessionID":self.sessionID}, branch=self.initialBranch) self.killLink() def accept(self, consumer): FileReceive.accept(self, consumer) + if not self.switchboard: return self.sendSLPMessage("200", "application/x-msnmsgr-sessionreqbody", {"SessionID":self.sessionID}, branch=self.initialBranch) + self.handlePacket = self.wait_data # Moved here because sometimes the second INVITE seems to be skipped def handleSLPMessage(self, slpMessage): if slpMessage.method == "INVITE": # The second invite @@ -2971,9 +2992,10 @@ class SLPLink_FileReceive(SLPLink_Receive, FileReceive): "Listening" : "false",\ "Hashed-Nonce": "{00000000-0000-0000-0000-000000000000}"} self.sendSLPMessage("200", "application/x-msnmsgr-transrespbody", data, branch=slpMessage.branch) - self.handlePacket = self.wait_data +# self.handlePacket = self.wait_data # Moved up else: - self.killLink() # It's either a BYE or an error + if MSNP2PDEBUG: log.msg("It's either a BYE or an error") + self.killLink() # FIXME, do some error handling if it was an error def doFinished(self): @@ -2996,7 +3018,7 @@ class SLPLink_AvatarReceive(SLPLink_Receive): if slpMessage.status == "200": self.handlePacket = self.wait_dataprep else: - # SLPLink is over due to error or BYE + if MSNP2PDEBUG: log.msg("SLPLink is over due to error or BYE") self.killLink() def doFinished(self):