Fix recursive BrokenPipeException on disconnect
[mudpy.git] / lib / mudpy / misc.py
index 8e747dd..41d3ab6 100644 (file)
@@ -1,7 +1,6 @@
-# -*- coding: utf-8 -*-
 """Miscellaneous functions for the mudpy engine."""
 
-# Copyright (c) 2004-2014 Jeremy Stanley <fungi@yuggoth.org>. Permission
+# Copyright (c) 2004-2015 Jeremy Stanley <fungi@yuggoth.org>. Permission
 # to use, copy, modify, and distribute this software is granted under
 # terms provided in the LICENSE file distributed with this software.
 
@@ -414,9 +413,13 @@ class Universe:
         # make a list of inactive avatars
         inactive_avatars = []
         for account in self.categories["account"].values():
-            inactive_avatars += [
-                (self.contents[x]) for x in account.getlist("avatars")
-            ]
+            for avatar in account.get("avatars"):
+                try:
+                    inactive_avatars.append(self.contents[avatar])
+                except KeyError:
+                    pending_loglines.append((
+                        "Missing avatar \"%s\", possible data corruption" %
+                        avatar, 6))
         for user in self.userlist:
             if user.avatar in inactive_avatars:
                 inactive_avatars.remove(user.avatar)
@@ -837,14 +840,14 @@ class User:
         if self.output_queue:
             try:
                 self.connection.send(self.output_queue[0])
-                del self.output_queue[0]
             except BrokenPipeError:
                 if self.account and self.account.get("name"):
                     account = self.account.get("name")
                 else:
                     account = "an unknown user"
-                log("Broken pipe sending to %s." % account, 7)
                 self.state = "disconnecting"
+                log("Broken pipe sending to %s." % account, 7)
+            del self.output_queue[0]
 
     def enqueue_input(self):
         """Process and enqueue any new input."""
@@ -973,11 +976,14 @@ class User:
 
     def list_avatar_names(self):
         """List names of assigned avatars."""
-        return [
-            universe.contents[avatar].get(
-                "name"
-            ) for avatar in self.account.getlist("avatars")
-        ]
+        avatars = []
+        for avatar in self.account.get("avatars"):
+            try:
+                avatars.append(universe.contents[avatar].get("name"))
+            except KeyError:
+                log("Missing avatar \"%s\", possible data corruption." %
+                    avatar, 6)
+        return avatars
 
 
 def broadcast(message, add_prompt=True):
@@ -2037,7 +2043,9 @@ def command_say(actor, parameters):
             universe.categories["internal"]["language"].get(
                 "default_punctuation"))
         action = ""
-        for mark in actions.keys():
+
+        # reverse sort punctuation options so the longest match wins
+        for mark in sorted(actions.keys(), reverse=True):
             if not literal and message.endswith(mark):
                 action = actions[mark]
                 break