plugin xep-0085: bug fix + improvement

This commit is contained in:
souliane 2013-10-07 13:09:57 +02:00
commit 58561b8732

View file

@ -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 @@ class XEP_0085(object):
}
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 @@ class XEP_0085(object):
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 @@ class XEP_0085(object):
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 @@ class XEP_0085(object):
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 @@ class XEP_0085(object):
except StopIteration:
# contact didn't enable Chat State Notifications
self.updateEntityData(from_jid, False, profile)
return True
except StopIteration:
pass
@ -160,8 +164,7 @@ class XEP_0085(object):
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 @@ class XEP_0085(object):
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 @@ class XEP_0085(object):
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 @@ class XEP_0085(object):
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 @@ class XEP_0085(object):
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: