changeset 1253:c13a46207410

plugin XEP-0085: send 'gone' state before disconnection
author souliane <souliane@mailoo.org>
date Mon, 20 Oct 2014 20:26:46 +0200
parents 5ff9f9af9d1f
children 87fbe4640448
files src/plugins/plugin_xep_0085.py
diffstat 1 files changed, 31 insertions(+), 18 deletions(-) [+]
line wrap: on
line diff
--- a/src/plugins/plugin_xep_0085.py	Mon Oct 20 12:57:55 2014 +0200
+++ b/src/plugins/plugin_xep_0085.py	Mon Oct 20 20:26:46 2014 +0200
@@ -94,6 +94,7 @@
     def __init__(self, host):
         log.info(_("Chat State Notifications plugin initialization"))
         self.host = host
+        self.map = {}
 
         # parameter value is retrieved before each use
         host.memory.updateParams(self.params)
@@ -102,7 +103,6 @@
         host.trigger.add("MessageReceived", self.messageReceivedTrigger)
         host.trigger.add("sendMessage", self.sendMessageTrigger)
         host.trigger.add("paramUpdateTrigger", self.paramUpdateTrigger)
-        # TODO: handle profile disconnection (free memory in entity data)
 
         # args: to_s (jid as string), profile
         host.bridge.addMethod("chatStateComposing", ".plugin", in_sign='ss',
@@ -114,6 +114,17 @@
     def getHandler(self, profile):
         return XEP_0085_handler(self, profile)
 
+    def profileDisconnected(self, profile):
+        """Eventually send a 'gone' state to all one2one contacts."""
+        if profile not in self.map:
+            return
+        for to_jid in self.map[profile]:
+            # FIXME: the "unavailable" presence stanza is received by to_jid
+            # before the chat state, so it will be ignored... find a way to
+            # actually defer the disconnection
+            self.map[profile][to_jid]._onEvent('gone')
+        del self.map[profile]
+
     def updateEntityData(self, entity_jid, value, profile):
         """
         Update the entity data of the given profile for one or all contacts.
@@ -259,8 +270,6 @@
         """
         if mess_type is None:
             return
-        if not hasattr(self, "map"):
-            self.map = {}
         profile_map = self.map.setdefault(profile, {})
         if to_jid not in profile_map:
             machine = ChatStateMachine(self.host, to_jid,
@@ -338,28 +347,32 @@
         notification to the contact (the "active" state is
         automatically sent with each message) and set the timer.
         """
+        assert(state in TRANSITIONS)
+        transition = TRANSITIONS[state]
+        assert("next_state" in transition and "delay" in transition)
+
         if state != self.state and state != "active":
             if state != 'gone' or self.mess_type != 'groupchat':
                 # send a new message without body
-                self.host.sendMessage(self.to_jid, '', '', self.mess_type,
-                                      extra={"chat_state": state},
-                                      profile_key=self.profile)
+                log.debug(u"sending state '{state}' to {jid}".format(state=state, jid=self.to_jid.full()))
+                client = self.host.getClient(self.profile)
+                mess_data = {'message': None,
+                             'type': self.mess_type,
+                             'from': client.jid,
+                             'to': self.to_jid,
+                             'subject': None
+                             }
+                self.host.generateMessageXML(mess_data)
+                mess_data['xml'].addElement(state, NS_CHAT_STATES)
+                client.xmlstream.send(mess_data['xml'])
+
         self.state = state
         if self.timer is not None:
             self.timer.cancel()
 
-        if state not in TRANSITIONS:
-            return
-        if "next_state" not in TRANSITIONS[state]:
-            return
-        if "delay" not in TRANSITIONS[state]:
-            return
-        next_state = TRANSITIONS[state]["next_state"]
-        delay = TRANSITIONS[state]["delay"]
-        if next_state == "" or delay < 0:
-            return
-        self.timer = Timer(delay, self._onEvent, [next_state])
-        self.timer.start()
+        if transition["next_state"] and transition["delay"] > 0:
+            self.timer = Timer(transition["delay"], self._onEvent, [transition["next_state"]])
+            self.timer.start()
 
 
 class XEP_0085_handler(XMPPHandler):