# HG changeset patch # User souliane # Date 1413802675 -7200 # Node ID 5ff9f9af9d1ffa85460cb0197f6ac1d1e22cbfc4 # Parent 51a85e8f599addcfd03f6fb5b1dab9c4d63bc362 plugin XEP-0085: use the full JID + fixes bad entity data "type" value diff -r 51a85e8f599a -r 5ff9f9af9d1f src/plugins/plugin_xep_0085.py --- a/src/plugins/plugin_xep_0085.py Mon Oct 20 16:38:49 2014 +0200 +++ b/src/plugins/plugin_xep_0085.py Mon Oct 20 12:57:55 2014 +0200 @@ -127,12 +127,13 @@ # disable chat state for this or these contact(s) self.host.bridge.chatStateReceived(unicode(entity_jid), "", profile) - def paramUpdateTrigger(self, name, value, category, type, profile): + def paramUpdateTrigger(self, name, value, category, type_, profile): """ 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 + @param type_: parameter type """ if (category, name) == (PARAM_KEY, PARAM_NAME): self.updateEntityData("@ALL@", True if value == "true" else C.PROF_KEY_NONE, profile) @@ -148,19 +149,23 @@ return True from_jid = JID(message.getAttribute("from")) - try: - domish.generateElementsNamed(message.elements(), name="body").next() + if self.__isMUC(from_jid, profile): + from_jid = from_jid.userhostJID() + else: # update entity data for one2one chat + assert(from_jid.resource) try: - domish.generateElementsNamed(message.elements(), name="active").next() - # contact enabled Chat State Notifications - self.updateEntityData(from_jid, True, profile) + domish.generateElementsNamed(message.elements(), name="body").next() + try: + domish.generateElementsNamed(message.elements(), name="active").next() + # contact enabled Chat State Notifications + self.updateEntityData(from_jid, True, profile) + except StopIteration: + if message.getAttribute('type') == 'chat': + # contact didn't enable Chat State Notifications + self.updateEntityData(from_jid, False, profile) + return True except StopIteration: - if message.getAttribute('type') == 'chat': - # contact didn't enable Chat State Notifications - self.updateEntityData(from_jid, False, profile) - return True - except StopIteration: - pass + pass # send our next "composing" states to any MUC and to the contacts who enabled the feature self.__chatStateInit(from_jid, message.getAttribute("type"), profile) @@ -191,6 +196,8 @@ domish.generateElementsNamed(message.elements(), name="body").next() message.addElement('active', NS_CHAT_STATES) # launch the chat state machine (init the timer) + if self.__isMUC(to_jid, profile): + to_jid = to_jid.userhostJID() self.__chatStateActive(to_jid, mess_data["type"], profile) except StopIteration: if "chat_state" in mess_data["extra"]: @@ -202,9 +209,24 @@ post_xml_treatments.addCallback(treatment) return True + def __isMUC(self, to_jid, profile): + """Tell if that JID is a MUC or not + + @param to_jid (JID): full or bare JID to check + @param profile (str): %(doc_profile)s + @return: bool + """ + try: + type_ = self.host.memory.getEntityDatum(to_jid.userhostJID(), 'type', profile) + if type_ == 'chatroom': + return True + except (exceptions.UnknownEntityError, KeyError): + pass + return False + def __checkActivation(self, to_jid, forceEntityData, profile): """ - @param to_joid: the contact's JID + @param to_jid: the contact's full JID (or bare if you know it's a MUC) @param forceEntityData: if set to True, a non-existing entity data will be considered to be True (and initialized) @param: current profile @@ -214,14 +236,11 @@ if not self.host.memory.getParamA(PARAM_NAME, PARAM_KEY, profile_key=profile): return False # check if notifications should be sent to this contact + if self.__isMUC(to_jid, profile): + return True + assert(to_jid.resource or not self.host.memory.isContactConnected(to_jid, profile)) try: - type_ = self.host.memory.getEntityData(to_jid, ['type'], profile)['type'] - if type_ == 'groupchat': # always send to groupchat - return True - except (exceptions.UnknownEntityError, KeyError): - pass # private chat - try: - return self.host.memory.getEntityData(to_jid, [ENTITY_KEY], profile)[ENTITY_KEY] + return self.host.memory.getEntityDatum(to_jid, ENTITY_KEY, profile) except (exceptions.UnknownEntityError, KeyError): if forceEntityData: # enable it for the first time @@ -233,15 +252,17 @@ def __chatStateInit(self, to_jid, mess_type, profile): """ Data initialization for the chat state machine. + + @param to_jid (JID): full JID for one2one, bare JID for MUC + @param mess_type (str): "one2one" or "groupchat" + @param profile (str): %(doc_profile)s """ - # TODO: use also the resource in map key (not for groupchat) - to_jid = to_jid.userhostJID() if mess_type is None: return if not hasattr(self, "map"): self.map = {} profile_map = self.map.setdefault(profile, {}) - if not to_jid in profile_map: + if to_jid not in profile_map: machine = ChatStateMachine(self.host, to_jid, mess_type, profile) self.map[profile][to_jid] = machine @@ -249,30 +270,36 @@ def __chatStateActive(self, to_jid, mess_type, profile_key): """ Launch the chat state machine on "active" state. + + @param to_jid (JID): full JID for one2one, bare JID for MUC + @param mess_type (str): "one2one" or "groupchat" + @param profile (str): %(doc_profile)s """ - # TODO: use also the JID resource in the map key (not for groupchat) - to_jid = to_jid.userhostJID() 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") def chatStateComposing(self, to_jid_s, profile_key): - """ - Move to the "composing" state. Since this method is called - from the front-end, it needs to check the values of the - parameter "Send chat state notifications" and the entity + """Move to the "composing" state when required. + + Since this method is called from the front-end, it needs to check the + values of the parameter "Send chat state notifications" and the entity data associated to the target JID. - TODO: try to optimize this method which is called often + + @param to_jid_s (str): contact full JID as a string + @param profile_key (str): %(doc_profile_key)s """ - # TODO: use also the JID resource in the map key (not for groupchat) - to_jid = JID(to_jid_s).userhostJID() + # TODO: try to optimize this method which is called often profile = self.host.memory.getProfileName(profile_key) if profile is None: raise exceptions.ProfileUnknownError - return + to_jid = JID(to_jid_s) + if self.__isMUC(to_jid, profile): + to_jid = to_jid.userhostJID() + elif not to_jid.resource: + to_jid.resource = self.host.memory.getLastResource(to_jid, profile) if not self.__checkActivation(to_jid, forceEntityData=False, profile=profile): return try: @@ -318,14 +345,14 @@ extra={"chat_state": state}, profile_key=self.profile) self.state = state - if not self.timer is None: + if self.timer is not None: self.timer.cancel() - if not state in TRANSITIONS: + if state not in TRANSITIONS: return - if not "next_state" in TRANSITIONS[state]: + if "next_state" not in TRANSITIONS[state]: return - if not "delay" in TRANSITIONS[state]: + if "delay" not in TRANSITIONS[state]: return next_state = TRANSITIONS[state]["next_state"] delay = TRANSITIONS[state]["delay"]