changeset 659:b6c22d9f593a

plugin xep-0085: bug fix + improvement
author souliane <souliane@mailoo.org>
date Mon, 07 Oct 2013 13:09:57 +0200
parents e26134122ed7
children 69a8bfd266a5
files src/plugins/plugin_xep_0085.py
diffstat 1 files changed, 45 insertions(+), 36 deletions(-) [+]
line wrap: on
line diff
--- a/src/plugins/plugin_xep_0085.py	Mon Oct 07 14:58:41 2013 +0200
+++ b/src/plugins/plugin_xep_0085.py	Mon Oct 07 13:09:57 2013 +0200
@@ -18,7 +18,7 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 from sat.core import exceptions
-from logging import debug, info, error
+from logging import info
 from wokkel import disco, iwokkel
 from zope.interface import implements
 from twisted.words.protocols.jabber.jid import JID
@@ -89,7 +89,7 @@
     }
 
     def __init__(self, host):
-        info(_("CSN plugin initialization"))
+        info(_("Chat State Notifications plugin initialization"))
         self.host = host
 
         # parameter value is retrieved before each use
@@ -99,7 +99,7 @@
         host.trigger.add("MessageReceived", self.messageReceivedTrigger)
         host.trigger.add("sendMessageXml", self.sendMessageXmlTrigger)
         host.trigger.add("paramUpdateTrigger", self.paramUpdateTrigger)
-        # TODO: handle profile disconnexion (free memory in entity data)
+        # TODO: handle profile disconnection (free memory in entity data)
 
         # args: to_s (jid as string), profile
         host.bridge.addMethod("chatStateComposing", ".plugin", in_sign='ss',
@@ -113,9 +113,11 @@
 
     def updateEntityData(self, entity_jid, value, profile):
         """
-        Update the entity data and reset the chat state display
-        if the notification has been disabled. Parameter "entity_jid"
-        could be @ALL@ to update all entities.
+        Update the entity data of the given profile for one or all contacts.
+        Reset the chat state(s) display if the notification has been disabled.
+        @param entity_jid: contact's JID, or '@ALL@' to update all contacts.
+        @param value: True, False or '@NONE@' to delete the entity data
+        @param profile: current profile
         """
         self.host.memory.updateEntityData(entity_jid, ENTITY_KEY, value, profile)
         if not value or value == "@NONE@":
@@ -124,9 +126,10 @@
 
     def paramUpdateTrigger(self, name, value, category, type, profile):
         """
-        Reset all the existing chat state entity data associated
-        with this profile after a parameter modification (value
-        different then "true" would delete the entity data).
+        Reset all the existing chat state entity data associated with this profile after a parameter modification.
+        @param name: parameter name
+        @param value: "true" to activate the notifications, or any other value to delete it
+        @param category: parameter category
         """
         if (category, name) == (PARAM_KEY, PARAM_NAME):
             self.updateEntityData("@ALL@", True if value == "true" else "@NONE@", profile)
@@ -151,6 +154,7 @@
             except StopIteration:
                 # contact didn't enable Chat State Notifications
                 self.updateEntityData(from_jid, False, profile)
+                return True
         except StopIteration:
             pass
 
@@ -160,8 +164,7 @@
                       and child.defaultUri == NS_CHAT_STATES]
         for state in state_list:
             # there must be only one state according to the XEP
-            self.host.bridge.chatStateReceived(message.getAttribute("from"),
-                                               state, profile)
+            self.host.bridge.chatStateReceived(message.getAttribute("from"), state, profile)
             break
         return True
 
@@ -170,19 +173,8 @@
         Eventually add the chat state to the message and initiate
         the state machine when sending an "active" state.
         """
-        if not self.host.memory.getParamA(PARAM_NAME, PARAM_KEY, profile_key=profile):
-            return True
-
-        # check if notifications should be sent to this contact
-        contact_enabled = True
         to_jid = JID(message.getAttribute("to"))
-        try:
-            contact_enabled = self.host.memory.getEntityData(
-                to_jid, [ENTITY_KEY], profile)[ENTITY_KEY]
-        except (exceptions.UnknownEntityError, KeyError):
-            # enable it for the first time
-            self.updateEntityData(to_jid, True, profile)
-        if not contact_enabled:
+        if not self.__checkActivation(to_jid, forceEntityData=True, profile=profile):
             return True
         try:
             # message with a body always mean active state
@@ -197,6 +189,28 @@
                 message.addElement(state, NS_CHAT_STATES)
         return True
 
+    def __checkActivation(self, to_jid, forceEntityData, profile):
+        """
+        @param to_joid: the contact's JID
+        @param forceEntityData: if set to True, a non-existing
+        entity data will be considered to be True (and initialized)
+        @param: current profile
+        @return: True if the notifications should be sent to this JID.
+        """
+        # check if the parameter is active
+        if not self.host.memory.getParamA(PARAM_NAME, PARAM_KEY, profile_key=profile):
+            return False
+        # check if notifications should be sent to this contact
+        try:
+            return self.host.memory.getEntityData(to_jid, [ENTITY_KEY], profile)[ENTITY_KEY]
+        except (exceptions.UnknownEntityError, KeyError):
+            if forceEntityData:
+                # enable it for the first time
+                self.updateEntityData(to_jid, True, profile)
+                return True
+        # wait for the first message before sending states
+        return False
+
     def __chatStateInit(self, to_jid, mess_type, profile):
         """
         Data initialization for the chat state machine.
@@ -222,6 +236,7 @@
         profile = self.host.memory.getProfileName(profile_key)
         if profile is None:
             raise exceptions.ProfileUnknownError
+            return
         self.__chatStateInit(to_jid, mess_type, profile)
         self.map[profile][to_jid]._onEvent("active")
 
@@ -233,26 +248,20 @@
         data associated to the target JID.
         TODO: try to optimize this method which is called often
         """
-        # check if the parameter is active
-        if not self.host.memory.getParamA(PARAM_NAME, PARAM_KEY, profile_key=profile_key):
-            return
         # TODO: use also the JID resource in the map key
         to_jid = JID(to_jid_s).userhostJID()
         profile = self.host.memory.getProfileName(profile_key)
         if profile is None:
             raise exceptions.ProfileUnknownError
-        # check if notifications should be sent to this contact
-        contact_enabled = True
+            return
+        if not self.__checkActivation(to_jid, forceEntityData=False, profile=profile):
+            return
         try:
-            contact_enabled = self.host.memory.getEntityData(
-                to_jid, [ENTITY_KEY], profile)[ENTITY_KEY]
-        except (exceptions.UnknownEntityError, KeyError):
-            # wait for the first message before sending states
+            self.map[profile][to_jid]._onEvent("composing")
+        except AttributeError:
+            # no message has been sent/received since the notifications
+            # have been enabled, it's better to wait for a first one
             pass
-        if not contact_enabled:
-            return True
-        # now we are sure that the state should be sent
-        self.map[profile][to_jid]._onEvent("composing")
 
 
 class ChatStateMachine: