From 745df8356fa9dd0f8be5c2078625ec73930dd7d0 Mon Sep 17 00:00:00 2001 From: Griatch Date: Sun, 3 Oct 2010 19:11:43 +0000 Subject: [PATCH] Added comprehensive encoding handling to support both player-level encoding choices as well as global multiple encodings through the settings file. --- src/objects/models.py | 12 ++------ src/players/models.py | 18 +++++------- src/server/session.py | 62 +++++++++++++++++++++++++++++++-------- src/settings_default.py | 6 ++++ src/typeclasses/models.py | 5 ++-- 5 files changed, 69 insertions(+), 34 deletions(-) diff --git a/src/objects/models.py b/src/objects/models.py index 162a64a27b..1a21514d5e 100644 --- a/src/objects/models.py +++ b/src/objects/models.py @@ -505,15 +505,9 @@ class ObjectDB(TypedObject): """ # This is an important function that must always work. # we use a different __getattribute__ to avoid recursive loops. - - if from_obj: - try: - from_obj.at_msg_send(message, self) - except Exception: - pass - if self.at_msg_receive(message, from_obj): - for session in object.__getattribute__(self, 'sessions'): - session.msg(message, markup) + + if object.__getattribute__(self, 'player'): + object.__getattribute__(self, 'player').msg(message, markup) def emit_to(self, message, from_obj=None): "Deprecated. Alias for msg" diff --git a/src/players/models.py b/src/players/models.py index b758d164ba..d034faa171 100644 --- a/src/players/models.py +++ b/src/players/models.py @@ -253,19 +253,15 @@ class PlayerDB(TypedObject): def msg(self, message, from_obj=None, markup=True): """ - This duplicates the same-named method on the Character. - It forwards messages to the character or uses - the session messaging directly. + This is the main route for sending data to the user. """ + if from_obj: + try: + from_obj.at_msg_send(message, self) + except Exception: + pass if self.character: - self.character.msg(message, from_obj) - else: - if from_obj: - try: - from_obj.at_msg_send(message, self) - except Exception: - pass - if self.at_msg_receive(message, from_obj): + if self.character.at_msg_receive(message, from_obj): for session in object.__getattribute__(self, 'sessions'): session.msg(message, markup) diff --git a/src/server/session.py b/src/server/session.py index 20ddbcaf2b..9d02e3cc38 100644 --- a/src/server/session.py +++ b/src/server/session.py @@ -16,6 +16,8 @@ from src.utils import reloads from src.utils import logger from src.utils import utils +ENCODINGS = settings.ENCODINGS + class SessionProtocol(StatefulTelnetProtocol): """ This class represents a player's session. Each player @@ -71,6 +73,7 @@ class SessionProtocol(StatefulTelnetProtocol): self.name = None self.uid = None self.logged_in = False + self.encoding = "utf-8" # The time the user last issued a command. self.cmd_last = time.time() @@ -103,13 +106,31 @@ class SessionProtocol(StatefulTelnetProtocol): So we take the user input and pass it to the Player and their currently connected character. """ - try: - raw_string = utils.to_unicode(raw_string) - except Exception, e: - self.sendLine(str(e)) - return - self.execute_cmd(raw_string) + if self.encoding: + try: + raw_string = utils.to_unicode(raw_string, encoding=self.encoding) + self.execute_cmd(raw_string) + return + except Exception, e: + err = str(e) + print err + pass + + # malformed/wrong encoding defined on player-try some defaults + for encoding in ENCODINGS: + try: + raw_string = utils.to_unicode(raw_string, encoding=encoding) + err = None + break + except Exception, e: + err = str(e) + continue + if err: + self.sendLine(err) + else: + self.execute_cmd(raw_string) + def msg(self, message, markup=True): """ Communication Evennia -> Player @@ -120,12 +141,27 @@ class SessionProtocol(StatefulTelnetProtocol): colors, but could also be html tags for web connections etc. """ - try: - message = utils.to_str(message) - except Exception, e: - self.sendLine(str(e)) - return - self.sendLine(ansi.parse_ansi(message, strip_ansi=not markup)) + if self.encoding: + try: + message = utils.to_str(message, encoding=self.encoding) + self.sendLine(ansi.parse_ansi(message, strip_ansi=not markup)) + return + except Exception: + pass + + # malformed/wrong encoding defined on player - try some defaults + for encoding in ENCODINGS: + try: + message = utils.to_str(message, encoding=encoding) + err = None + break + except Exception, e: + err = str(e) + continue + if err: + self.sendLine(err) + else: + self.sendLine(ansi.parse_ansi(message, strip_ansi=not markup)) def get_character(self): """ @@ -228,6 +264,8 @@ class SessionProtocol(StatefulTelnetProtocol): self.name = user.username self.logged_in = True self.conn_time = time.time() + if player.db.encoding: + self.encoding = player.db.encoding if not settings.ALLOW_MULTISESSION: # disconnect previous sessions. diff --git a/src/settings_default.py b/src/settings_default.py index e23402b337..d5f44dc59d 100644 --- a/src/settings_default.py +++ b/src/settings_default.py @@ -70,6 +70,12 @@ IMPORT_MUX_HELP = False # thrown off by sending the empty system command 'idle' to the server # at regular intervals. IDLE_TIMEOUT = 3600 +# The set of encodings tried. A Player object may set an attribute "encoding" on +# itself to match the client used. If not set, or wrong encoding is +# given, this list is tried, in order, aborting on the first match. +# Add sets for languages/regions your players are likely to use. +# (see http://en.wikipedia.org/wiki/Character_encoding) +ENCODINGS = ["utf-8", "latin-1", "ISO-8859-1"] ################################################### # Evennia Database config diff --git a/src/typeclasses/models.py b/src/typeclasses/models.py index 1e2cb5153c..365ab3d81d 100644 --- a/src/typeclasses/models.py +++ b/src/typeclasses/models.py @@ -273,7 +273,7 @@ class Attribute(SharedMemoryModel): such as dhango model instances, cannot be directly stored/pickled in an attribute, so we have to be clever about it. Types of objects and how they are handled: - * str - stored directly in field + * str - s5Atored directly in field * django model object - store its dbref in field * any other python structure - pickle in field @@ -813,7 +813,8 @@ class TypedObject(SharedMemoryModel): """ Returns all attributes defined on the object. """ - return [attr for attr in self.objattribute_set.all()] + attr_set_all = eval("self.%s_set.all()" % (self.attribute_model_name.lower())) + return [attr for attr in attr_set_all] def attr(self, attribute_name=None, value=None, delete=False): """