]> code.delx.au - pymsnt/blobdiff - src/tlib/msn/msnw.py
Handle disconnects better.
[pymsnt] / src / tlib / msn / msnw.py
index b0edb3066831e03cb6e99b5afc363fb5b49b7e64..87ed0442623ce420d1881590cf7059ed98383447 100644 (file)
@@ -51,8 +51,9 @@ class MSNConnection:
        def _getNotificationReferral(self):
                def timeout():
                        self.timeout = None
+                       dispatchFactory.d = None
                        if not d.called:
-                               d.errback("Timeout")
+                               d.errback(Exception("Timeout"))
                                self.logOut() # Clean up everything
                self.timeout = reactor.callLater(30, timeout)
                dispatchFactory = msn.DispatchFactory()
@@ -193,15 +194,17 @@ class MSNConnection:
                if not statusCode: statusCode = msn.STATUS_ONLINE
                if not personal: personal = ""
                if self.notificationClient:
-                       changeCount = [0] # Hack
+                       changeCount = [0] # Hack for Python's limited scope :(
                        def cb(ignored=None):
                                changeCount[0] += 1
                                if changeCount[0] == 3:
                                        self.ourStatusChanged(statusCode, screenName, personal)
+                       def errcb(ignored=None):
+                               pass # FIXME, should we do something here?
                        LogEvent(INFO, self.ident)
-                       self.notificationClient.changeStatus(statusCode.encode("utf-8")).addCallback(cb)
-                       self.notificationClient.changeScreenName(screenName.encode("utf-8")).addCallback(cb)
-                       self.notificationClient.changePersonalMessage(personal.encode("utf-8")).addCallback(cb)
+                       self.notificationClient.changeStatus(statusCode.encode("utf-8")).addCallbacks(cb, errcb)
+                       self.notificationClient.changeScreenName(screenName.encode("utf-8")).addCallbacks(cb, errcb)
+                       self.notificationClient.changePersonalMessage(personal.encode("utf-8")).addCallbacks(cb, errcb)
                # Remember the saved status
                self.savedEvents.statusCode = statusCode
                self.savedEvents.screenName = screenName
@@ -228,9 +231,11 @@ class MSNConnection:
                        self.notificationClient.logOut()
                for c in self.connectors:
                        c.disconnect()
+               self.connectors = []
                if self.notificationFactory:
+                       self.notificationFactory.stopTrying()
                        self.notificationFactory.msncon = None
-               self.connectors = []
+                       self.notificationFactory = None
                for sbs in self.switchboardSessions.values():
                        if hasattr(sbs, "transport") and sbs.transport:
                                sbs.transport.loseConnection()
@@ -355,11 +360,18 @@ class SavedEvents:
 
 class DispatchClient(msn.DispatchClient):
        def gotNotificationReferral(self, host, port):
-               if self.factory.d.called: return # Too slow! We've already timed out
-               self.factory.d.callback((host, port))
+               d = self.factory.d
+               self.factory.d = None
+               if not d or d.called:
+                       return # Too slow! We've already timed out
+               d.callback((host, port))
 
 
 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)
        
@@ -373,14 +385,22 @@ 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 = lambda reason: msn.NotificationClient.connectionLost(self, reason)
        
        def connectionLost(self, reason):
-               print "NotificationClient.connectionLost!!!"
-               if not self.factory.msncon: return # If we called logOut
+               if not self.factory.msncon:
+                       # If MSNConnection.logOut is called before _notificationClientReady
+                       return
+
                def wait():
                        LogEvent(INFO, self.factory.msncon.ident)
                        msn.NotificationClient.connectionLost(self, reason)
-                       if self.factory.maxRetries >= self.factory.retries:
+                       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)
@@ -435,9 +455,8 @@ class NotificationClient(msn.NotificationClient):
                sb = self.factory.msncon.switchboardSessions.get(userHandle)
                if sb and sb.transport:
                        sb.transport.loseConnection()
-               else:
-                       sb = OneSwitchboardSession(self.factory.msncon, userHandle)
-                       self.factory.msncon.switchboardSessions[userHandle] = sb
+               sb = OneSwitchboardSession(self.factory.msncon, userHandle)
+               self.factory.msncon.switchboardSessions[userHandle] = sb
                sb.connectReply(host, port, key, sessionID)
        
        def multipleLogin(self):
@@ -461,10 +480,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)
@@ -545,7 +567,7 @@ class SwitchboardSessionBase(msn.SwitchboardClient):
 
                                d = msn.SwitchboardClient.sendMessage(self, message)
                                if not noerror:
-                                       d.addCallback(failedMessage)
+                                       d.addCallbacks(failedMessage, failedMessage)
 
                        else:
                                chunks = int(math.ceil(len(text) / float(MSNConnection.MAXMESSAGESIZE)))
@@ -565,7 +587,7 @@ class SwitchboardSessionBase(msn.SwitchboardClient):
 
                                        d = msn.SwitchboardClient.sendMessage(self, message)
                                        if not noerror:
-                                               d.addCallback(failedMessage)
+                                               d.addCallbacks(failedMessage, failedMessage)
 
                                        chunk += 1
 
@@ -576,7 +598,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()
@@ -627,13 +649,20 @@ 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)
+               self.messageBuffer = []
+
+               if self.msncon and self.msncon.switchboardSessions.has_key(self.remoteUser):
+                       # Unexpected disconnection. Must remove us from msncon
+                       self.msncon.switchboardSessions.pop(self.remoteUser)
+
+               SwitchboardSessionBase.connectionLost(self, reason)
 
        def _ready(self):
                LogEvent(INFO, self.ident)
@@ -662,11 +691,12 @@ class OneSwitchboardSession(SwitchboardSessionBase):
                LogEvent(INFO, self.ident)
                if not self.reply:
                        def failCB(arg=None):
+                               self.timeout = None
+                               self.transport.loseConnection()
                                if not (self.msncon and self.msncon.switchboardSessions.has_key(self.remoteUser)):
                                        return
                                LogEvent(INFO, self.ident, "User has not joined after 30 seconds.")
                                del self.msncon.switchboardSessions[self.remoteUser]
-                               self.timeout = None
                        d = self.inviteUser(self.remoteUser)
                        d.addErrback(failCB)
                        self.timeout = reactor.callLater(30.0, failCB)
@@ -712,7 +742,8 @@ class OneSwitchboardSession(SwitchboardSessionBase):
                                else:
                                        text = message.getMessage()
                                self.msncon.gotMessage(self.remoteUser, text)
-                       except:
+                       except UnicodeDecodeError:
+                               LogEvent(WARN, self.ident, "Message lost!")
                                self.msncon.gotMessage(self.remoteUser, "A message was lost.")
                                raise
                elif "text/x-clientcaps" == cTypes[0]: