# HG changeset patch # User souliane # Date 1413829606 -7200 # Node ID c13a46207410742979f975f163596de8df19e228 # Parent 5ff9f9af9d1ffa85460cb0197f6ac1d1e22cbfc4 plugin XEP-0085: send 'gone' state before disconnection diff -r 5ff9f9af9d1f -r c13a46207410 src/plugins/plugin_xep_0085.py --- 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):