Added implementation and tests for XEP-0085 - Chat State Notifications.
Chat states may be set using: msg['chat_state'].active() msg['chat_state'].composing() msg['chat_state'].gone() msg['chat_state'].inactive() msg['chat_state'].paused() Checking a chat state can be done with either: msg['chat_state'].getState() msg['chat_state'].name When a message with a chat state is receieved, the following events may occur: chatstate_active chatstate_composing chatstate_gone chatstate_inactive chatstate_paused where the event data is the message stanza. Note that currently these events are also triggered for messages sent by SleekXMPP, not just those received.
This commit is contained in:
parent
1e3a6e1b5f
commit
629f6e76a9
3 changed files with 148 additions and 1 deletions
|
@ -17,4 +17,4 @@
|
|||
along with SleekXMPP; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
__all__ = ['xep_0004', 'xep_0030', 'xep_0045', 'xep_0050', 'xep_0078', 'xep_0092', 'xep_0199', 'gmail_notify', 'xep_0060']
|
||||
__all__ = ['xep_0004', 'xep_0030', 'xep_0045', 'xep_0050', 'xep_0078', 'xep_0085', 'xep_0092', 'xep_0199', 'gmail_notify', 'xep_0060']
|
||||
|
|
100
sleekxmpp/plugins/xep_0085.py
Normal file
100
sleekxmpp/plugins/xep_0085.py
Normal file
|
@ -0,0 +1,100 @@
|
|||
"""
|
||||
SleekXMPP: The Sleek XMPP Library
|
||||
Copyright (C) 2010 Nathanael C. Fritz, Lance J.T. Stout
|
||||
This file is part of SleekXMPP.
|
||||
|
||||
See the file license.txt for copying permissio
|
||||
"""
|
||||
|
||||
import logging
|
||||
from . import base
|
||||
from .. xmlstream.handler.callback import Callback
|
||||
from .. xmlstream.matcher.xpath import MatchXPath
|
||||
from .. xmlstream.stanzabase import ElementBase, ET, JID
|
||||
from .. stanza.message import Message
|
||||
|
||||
|
||||
class ChatState(ElementBase):
|
||||
namespace = 'http://jabber.org/protocol/chatstates'
|
||||
plugin_attrib = 'chat_state'
|
||||
interface = set(('state',))
|
||||
states = set(('active', 'composing', 'gone', 'inactive', 'paused'))
|
||||
|
||||
def active(self):
|
||||
self.setState('active')
|
||||
|
||||
def composing(self):
|
||||
self.setState('composing')
|
||||
|
||||
def gone(self):
|
||||
self.setState('gone')
|
||||
|
||||
def inactive(self):
|
||||
self.setState('inactive')
|
||||
|
||||
def paused(self):
|
||||
self.setState('paused')
|
||||
|
||||
def setState(self, state):
|
||||
if state in self.states:
|
||||
self.name = state
|
||||
self.xml.tag = state
|
||||
self.xml.attrib['xmlns'] = self.namespace
|
||||
|
||||
def getState(self):
|
||||
return self.name
|
||||
|
||||
# In order to match the various chat state elements,
|
||||
# we need one stanza object per state, even though
|
||||
# they are all the same except for the initial name
|
||||
# value. Do not depend on the type of the chat state
|
||||
# stanza object for the actual state.
|
||||
|
||||
class Active(ChatState):
|
||||
name = 'active'
|
||||
class Composing(ChatState):
|
||||
name = 'composing'
|
||||
class Gone(ChatState):
|
||||
name = 'gone'
|
||||
class Inactive(ChatState):
|
||||
name = 'inactive'
|
||||
class Paused(ChatState):
|
||||
name = 'paused'
|
||||
|
||||
|
||||
class xep_0085(base.base_plugin):
|
||||
"""
|
||||
XEP-0085 Chat State Notifications
|
||||
"""
|
||||
|
||||
def plugin_init(self):
|
||||
self.xep = '0085'
|
||||
self.description = 'Chat State Notifications'
|
||||
|
||||
handlers = [('Active Chat State', 'active'),
|
||||
('Composing Chat State', 'composing'),
|
||||
('Gone Chat State', 'gone'),
|
||||
('Inactive Chat State', 'inactive'),
|
||||
('Paused Chat State', 'paused')]
|
||||
for handler in handlers:
|
||||
self.xmpp.registerHandler(
|
||||
Callback(handler[0],
|
||||
MatchXPath("{%s}message/{%s}%s" % (self.xmpp.default_ns,
|
||||
ChatState.namespace,
|
||||
handler[1])),
|
||||
self._handleChatState))
|
||||
|
||||
self.xmpp.stanzaPlugin(Message, Active)
|
||||
self.xmpp.stanzaPlugin(Message, Composing)
|
||||
self.xmpp.stanzaPlugin(Message, Gone)
|
||||
self.xmpp.stanzaPlugin(Message, Inactive)
|
||||
self.xmpp.stanzaPlugin(Message, Paused)
|
||||
|
||||
def post_init(self):
|
||||
base.base_plugin.post_init(self)
|
||||
self.xmpp.plugin['xep_0030'].add_feature('http://jabber.org/protocol/chatstates')
|
||||
|
||||
def _handleChatState(self, msg):
|
||||
state = msg['chat_state'].name
|
||||
logging.debug("Chat State: %s, %s" % (state, msg['from'].jid))
|
||||
self.xmpp.event('chatstate_%s' % state, msg)
|
47
tests/test_chatstates.py
Normal file
47
tests/test_chatstates.py
Normal file
|
@ -0,0 +1,47 @@
|
|||
import unittest
|
||||
from xml.etree import cElementTree as ET
|
||||
from sleekxmpp.xmlstream.matcher.stanzapath import StanzaPath
|
||||
from . import xmlcompare
|
||||
|
||||
import sleekxmpp.plugins.xep_0085 as cs
|
||||
|
||||
def stanzaPlugin(stanza, plugin):
|
||||
stanza.plugin_attrib_map[plugin.plugin_attrib] = plugin
|
||||
stanza.plugin_tag_map["{%s}%s" % (plugin.namespace, plugin.name)] = plugin
|
||||
|
||||
class testchatstates(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.cs = cs
|
||||
stanzaPlugin(self.cs.Message, self.cs.Active)
|
||||
stanzaPlugin(self.cs.Message, self.cs.Composing)
|
||||
stanzaPlugin(self.cs.Message, self.cs.Gone)
|
||||
stanzaPlugin(self.cs.Message, self.cs.Inactive)
|
||||
stanzaPlugin(self.cs.Message, self.cs.Paused)
|
||||
|
||||
def try2Methods(self, xmlstring, msg):
|
||||
msg2 = self.cs.Message(None, self.cs.ET.fromstring(xmlstring))
|
||||
self.failUnless(xmlstring == str(msg) == str(msg2),
|
||||
"Two methods for creating stanza don't match")
|
||||
|
||||
def testCreateChatState(self):
|
||||
"""Testing creating chat states."""
|
||||
xmlstring = """<message><%s xmlns="http://jabber.org/protocol/chatstates" /></message>"""
|
||||
|
||||
msg = self.cs.Message()
|
||||
msg['chat_state'].active()
|
||||
self.try2Methods(xmlstring % 'active', msg)
|
||||
|
||||
msg['chat_state'].composing()
|
||||
self.try2Methods(xmlstring % 'composing', msg)
|
||||
|
||||
msg['chat_state'].gone()
|
||||
self.try2Methods(xmlstring % 'gone', msg)
|
||||
|
||||
msg['chat_state'].inactive()
|
||||
self.try2Methods(xmlstring % 'inactive', msg)
|
||||
|
||||
msg['chat_state'].paused()
|
||||
self.try2Methods(xmlstring % 'paused', msg)
|
||||
|
||||
suite = unittest.TestLoader().loadTestsFromTestCase(testchatstates)
|
Loading…
Reference in a new issue