]> code.delx.au - pymsnt/blobdiff - src/tlib/msn/msnw.py
Hopeful fix for NotificationClient.connectionLost problem
[pymsnt] / src / tlib / msn / msnw.py
index 55e02ffcf80f5e74ba30afbbdda8ab6ceb68b38b..7b2c22cd7af1eed67ab0211c114255356682e8a0 100644 (file)
@@ -50,8 +50,9 @@ class MSNConnection:
 
        def _getNotificationReferral(self):
                def timeout():
+                       self.timeout = None
                        if not d.called:
-                               d.errback()
+                               d.errback(Exception("Timeout"))
                                self.logOut() # Clean up everything
                self.timeout = reactor.callLater(30, timeout)
                dispatchFactory = msn.DispatchFactory()
@@ -65,6 +66,7 @@ class MSNConnection:
        
        def _gotNotificationReferral(self, (host, port)):
                self.timeout.cancel()
+               self.timeout = None
                # Create the NotificationClient
                self.notificationFactory = msn.NotificationFactory()
                self.notificationFactory.userHandle = self.username
@@ -76,7 +78,6 @@ class MSNConnection:
        
        def _sendSavedEvents(self):
                self.savedEvents.send(self)
-               self.savedEvents = None
        
        def _notificationClientReady(self, notificationClient):
                self.notificationClient = notificationClient
@@ -175,8 +176,8 @@ class MSNConnection:
                if self.notificationClient:
                        LogEvent(INFO, self.ident)
                        self.notificationClient.changeAvatar(imageData, push=True)
-               else:
-                       self.savedEvents.avatarImageData = imageData
+               # Save the avatar for reuse on disconnection
+               self.savedEvents.avatarImageData = imageData
        
        def changeStatus(self, statusCode, screenName, personal):
                """
@@ -189,6 +190,8 @@ class MSNConnection:
                """
 
                if not screenName: screenName = self.username
+               if not statusCode: statusCode = msn.STATUS_ONLINE
+               if not personal: personal = ""
                if self.notificationClient:
                        changeCount = [0] # Hack
                        def cb(ignored=None):
@@ -198,12 +201,11 @@ class MSNConnection:
                        LogEvent(INFO, self.ident)
                        self.notificationClient.changeStatus(statusCode.encode("utf-8")).addCallback(cb)
                        self.notificationClient.changeScreenName(screenName.encode("utf-8")).addCallback(cb)
-                       if not personal: personal = ""
                        self.notificationClient.changePersonalMessage(personal.encode("utf-8")).addCallback(cb)
-               else:
-                       self.savedEvents.statusCode = statusCode
-                       self.savedEvents.screenName = screenName
-                       self.savedEvents.personal = personal
+               # Remember the saved status
+               self.savedEvents.statusCode = statusCode
+               self.savedEvents.screenName = screenName
+               self.savedEvents.personal = personal
                                
        def addContact(self, listType, userHandle):
                """ See msn.NotificationClient.addContact """
@@ -233,6 +235,9 @@ class MSNConnection:
                        if hasattr(sbs, "transport") and sbs.transport:
                                sbs.transport.loseConnection()
                self.switchboardSessions = {}
+               if self.timeout:
+                       self.timeout.cancel()
+                       self.timeout = None
                LogEvent(INFO, self.ident)
                
        
@@ -355,6 +360,10 @@ class DispatchClient(msn.DispatchClient):
 
 
 class NotificationClient(msn.NotificationClient):
+       def doDisconnect(self, *args):
+               if hasattr(self, "transport") and self.transport:
+                       self.transport.loseConnection()
+
        def loginFailure(self, message):
                self.factory.msncon.loginFailed(message)
        
@@ -368,13 +377,19 @@ class NotificationClient(msn.NotificationClient):
        
        def logOut(self):
                msn.NotificationClient.logOut(self)
+               # If we explicitly log out, then all of these events
+               # are now redundant
+               self.loginFailure = self.doDisconnect
+               self.loggedIn = self.doDisconnect
+               self.connectionLost = self.doDisconnect
        
        def connectionLost(self, reason):
-               if not self.factory.msncon: return # If we called logOut
                def wait():
                        LogEvent(INFO, self.factory.msncon.ident)
                        msn.NotificationClient.connectionLost(self, reason)
-                       self.factory.msncon.connectionLost(reason)
+                       if self.factory.maxRetries > self.factory.retries:
+                               self.factory.stopTrying()
+                               self.factory.msncon.connectionLost(reason)
                # Make sure this event is handled after any others
                reactor.callLater(0, wait)
        
@@ -454,10 +469,13 @@ class SwitchboardSessionBase(msn.SwitchboardClient):
                self.funcBuffer = []
                self.ready = False
 
-       def __del__(self):
+       def connectionLost(self, reason):
+               msn.SwitchboardClient.connectionLost(self, reason)
                LogEvent(INFO, self.ident)
-               del self.msncon
-               self.transport.disconnect()
+               self.ready = False
+               self.msncon = None
+               self.msnobj = None
+               self.ident = (self.ident[0], self.ident[1], "Disconnected!")
 
        def loggedIn(self):
                LogEvent(INFO, self.ident)
@@ -527,13 +545,13 @@ class SwitchboardSessionBase(msn.SwitchboardClient):
                        self.messageBuffer.append((text, noerror))
                else:
                        LogEvent(INFO, self.ident)
+                       text = str(text.replace("\n", "\r\n").encode("utf-8"))
                        def failedMessage(ignored):
                                if not noerror:
                                        self.failedMessage(text)
 
                        if len(text) < MSNConnection.MAXMESSAGESIZE:
-                               message = msn.MSNMessage(message=str(text.replace("\n", "\r\n").encode("utf-8")))
-                               message.setHeader("Content-Type", "text/plain; charset=UTF-8")
+                               message = msn.MSNMessage(message=text)
                                message.ack = msn.MSNMessage.MESSAGE_NACK
 
                                d = msn.SwitchboardClient.sendMessage(self, message)
@@ -546,13 +564,14 @@ class SwitchboardSessionBase(msn.SwitchboardClient):
                                guid = msn.random_guid()
                                while chunk < chunks:
                                        offset = chunk * MSNConnection.MAXMESSAGESIZE
-                                       text = text[offset : offset + MSNConnection.MAXMESSAGESIZE]
-                                       message = msn.MSNMessage(message=str(text.replace("\n", "\r\n").encode("utf-8")))
+                                       message = msn.MSNMessage(message=text[offset : offset + MSNConnection.MAXMESSAGESIZE])
                                        message.ack = msn.MSNMessage.MESSAGE_NACK
+                                       message.setHeader("Message-ID", guid)
                                        if chunk == 0:
-                                               message.setHeader("Content-Type", "text/plain; charset=UTF-8")
                                                message.setHeader("Chunks", str(chunks))
                                        else:
+                                               message.delHeader("MIME-Version")
+                                               message.delHeader("Content-Type")
                                                message.setHeader("Chunk", str(chunk))
 
                                        d = msn.SwitchboardClient.sendMessage(self, message)
@@ -568,7 +587,7 @@ class MultiSwitchboardSession(SwitchboardSessionBase):
        def __init__(self, msncon):
                """ Automatically creates a new switchboard connection to the server """
                SwitchboardSessionBase.__init__(self, msncon)
-               self.ident = (self.msncon.ident, self)
+               self.ident = (self.msncon.ident, repr(self))
                self.contactCount = 0
                self.groupchat = None
                self.connect()
@@ -619,13 +638,14 @@ class OneSwitchboardSession(SwitchboardSessionBase):
                self.chattingUsers = []
                self.timeout = None
        
-       def __del__(self):
+       def connectionLost(self, reason):
                if self.timeout:
                        self.timeout.cancel()
                self.timeout = None
                for message, noerror in self.messageBuffer:
                        if not noerror:
                                self.failedMessage(message)
+               SwitchboardSessionBase.connectionLost(self, reason)
 
        def _ready(self):
                LogEvent(INFO, self.ident)
@@ -644,9 +664,7 @@ class OneSwitchboardSession(SwitchboardSessionBase):
                del self.remoteUser
                self.contactCount = 0
                self.msncon.gotGroupchat(self, userHandle)
-               if not self.groupchat:
-                       LogEvent(ERROR, self.ident)
-                       raise Exception("YouNeedAGroupchat-WeHaveAProblemError") # FIXME
+               assert self.groupchat
        
        def failedMessage(self, text):
                self.msncon.failedMessage(self.remoteUser, text)
@@ -661,6 +679,7 @@ class OneSwitchboardSession(SwitchboardSessionBase):
                                LogEvent(INFO, self.ident, "User has not joined after 30 seconds.")
                                del self.msncon.switchboardSessions[self.remoteUser]
                                self.timeout = None
+                               self.transport.loseConnection()
                        d = self.inviteUser(self.remoteUser)
                        d.addErrback(failCB)
                        self.timeout = reactor.callLater(30.0, failCB)