From 77251452c106618ab1cfdad546eb224bc9693dea Mon Sep 17 00:00:00 2001 From: Lance Stout Date: Thu, 24 Feb 2011 12:10:29 -0500 Subject: [PATCH] Updated the XEP-0085 plugin. Can now be used as so: >>> msg['chat_state'] '' >>> msg >>> msg['chat_state'] = 'paused' >>> msg >>> msg['chat_state'] 'paused' >>> del msg['chat_state'] >>> msg --- setup.py | 1 + sleekxmpp/plugins/xep_0085.py | 104 ---------------------- sleekxmpp/plugins/xep_0085/__init__.py | 10 +++ sleekxmpp/plugins/xep_0085/chat_states.py | 48 ++++++++++ sleekxmpp/plugins/xep_0085/stanza.py | 73 +++++++++++++++ tests/test_stanza_xep_0085.py | 37 ++++---- 6 files changed, 149 insertions(+), 124 deletions(-) delete mode 100644 sleekxmpp/plugins/xep_0085.py create mode 100644 sleekxmpp/plugins/xep_0085/__init__.py create mode 100644 sleekxmpp/plugins/xep_0085/chat_states.py create mode 100644 sleekxmpp/plugins/xep_0085/stanza.py diff --git a/setup.py b/setup.py index ae8cf68..4575a07 100644 --- a/setup.py +++ b/setup.py @@ -50,6 +50,7 @@ packages = [ 'sleekxmpp', 'sleekxmpp/plugins/xep_0030', 'sleekxmpp/plugins/xep_0030/stanza', 'sleekxmpp/plugins/xep_0059', + 'sleekxmpp/plugins/xep_0085', 'sleekxmpp/plugins/xep_0092', 'sleekxmpp/plugins/xep_0199', ] diff --git a/sleekxmpp/plugins/xep_0085.py b/sleekxmpp/plugins/xep_0085.py deleted file mode 100644 index 3627e71..0000000 --- a/sleekxmpp/plugins/xep_0085.py +++ /dev/null @@ -1,104 +0,0 @@ -""" - 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 for copying permissio -""" - -import logging -from . import base -from .. xmlstream.handler.callback import Callback -from .. xmlstream.matcher.xpath import MatchXPath -from .. xmlstream.stanzabase import registerStanzaPlugin, ElementBase, ET, JID -from .. stanza.message import Message - - -log = logging.getLogger(__name__) - - -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 = '{%s}%s' % (self.namespace, state) - else: - raise ValueError('Invalid chat state') - - 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)) - - registerStanzaPlugin(Message, Active) - registerStanzaPlugin(Message, Composing) - registerStanzaPlugin(Message, Gone) - registerStanzaPlugin(Message, Inactive) - registerStanzaPlugin(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 - log.debug("Chat State: %s, %s" % (state, msg['from'].jid)) - self.xmpp.event('chatstate_%s' % state, msg) diff --git a/sleekxmpp/plugins/xep_0085/__init__.py b/sleekxmpp/plugins/xep_0085/__init__.py new file mode 100644 index 0000000..ff882f0 --- /dev/null +++ b/sleekxmpp/plugins/xep_0085/__init__.py @@ -0,0 +1,10 @@ +""" + SleekXMPP: The Sleek XMPP Library + Copyright (C) 2011 Nathanael C. Fritz, Lance J.T. Stout + This file is part of SleekXMPP. + + See the file LICENSE for copying permissio +""" + +from sleekxmpp.plugins.xep_0085.stanza import ChatState +from sleekxmpp.plugins.xep_0085.chat_states import xep_0085 diff --git a/sleekxmpp/plugins/xep_0085/chat_states.py b/sleekxmpp/plugins/xep_0085/chat_states.py new file mode 100644 index 0000000..a2feb53 --- /dev/null +++ b/sleekxmpp/plugins/xep_0085/chat_states.py @@ -0,0 +1,48 @@ +""" + SleekXMPP: The Sleek XMPP Library + Copyright (C) 2011 Nathanael C. Fritz, Lance J.T. Stout + This file is part of SleekXMPP. + + See the file LICENSE for copying permissio +""" + +import logging + +import sleekxmpp +from sleekxmpp.stanza import Message +from sleekxmpp.xmlstream.handler import Callback +from sleekxmpp.xmlstream.matcher import StanzaPath +from sleekxmpp.xmlstream import register_stanza_plugin, ElementBase, ET +from sleekxmpp.plugins.base import base_plugin +from sleekxmpp.plugins.xep_0085 import stanza + + +log = logging.getLogger(__name__) + + +class xep_0085(base_plugin): + + """ + XEP-0085 Chat State Notifications + """ + + def plugin_init(self): + self.xep = '0085' + self.description = 'Chat State Notifications' + self.stanza = stanza + + self.xmpp.registerHandler( + Callback('Chat States', + StanzaPath('message/chat_state'), + self._handle_chat_state)) + + register_stanza_plugin(Message, stanza.ChatState) + + def post_init(self): + base_plugin.post_init(self) + self.xmpp.plugin['xep_0030'].add_feature(stanza.ChatState.namepsace) + + def _handle_chat_state(self, msg): + state = msg['chat_state'] + log.debug("Chat State: %s, %s" % (state, msg['from'].jid)) + self.xmpp.event('chatstate_%s' % state, msg) diff --git a/sleekxmpp/plugins/xep_0085/stanza.py b/sleekxmpp/plugins/xep_0085/stanza.py new file mode 100644 index 0000000..8c46758 --- /dev/null +++ b/sleekxmpp/plugins/xep_0085/stanza.py @@ -0,0 +1,73 @@ +""" + SleekXMPP: The Sleek XMPP Library + Copyright (C) 2011 Nathanael C. Fritz, Lance J.T. Stout + This file is part of SleekXMPP. + + See the file LICENSE for copying permissio +""" + +import sleekxmpp +from sleekxmpp.xmlstream import ElementBase, ET + + +class ChatState(ElementBase): + + """ + Example chat state stanzas: + + + + + + + + + Stanza Interfaces: + chat_state + + Attributes: + states + + Methods: + get_chat_state + set_chat_state + del_chat_state + """ + + name = '' + namespace = 'http://jabber.org/protocol/chatstates' + plugin_attrib = 'chat_state' + interfaces = set(('chat_state',)) + is_extension = True + + states = set(('active', 'composing', 'gone', 'inactive', 'paused')) + + def setup(self, xml=None): + self.xml = ET.Element('') + return True + + def get_chat_state(self): + parent = self.parent() + for state in self.states: + state_xml = parent.find('{%s}%s' % (self.namespace, state)) + if state_xml is not None: + self.xml = state_xml + return state + return '' + + def set_chat_state(self, state): + self.del_chat_state() + parent = self.parent() + if state in self.states: + self.xml = ET.Element('{%s}%s' % (self.namespace, state)) + parent.append(self.xml) + elif state not in [None, '']: + raise ValueError('Invalid chat state') + + def del_chat_state(self): + parent = self.parent() + for state in self.states: + state_xml = parent.find('{%s}%s' % (self.namespace, state)) + if state_xml is not None: + self.xml = ET.Element('') + parent.xml.remove(state_xml) diff --git a/tests/test_stanza_xep_0085.py b/tests/test_stanza_xep_0085.py index 5db7139..b08404e 100644 --- a/tests/test_stanza_xep_0085.py +++ b/tests/test_stanza_xep_0085.py @@ -4,11 +4,7 @@ import sleekxmpp.plugins.xep_0085 as xep_0085 class TestChatStates(SleekTest): def setUp(self): - register_stanza_plugin(Message, xep_0085.Active) - register_stanza_plugin(Message, xep_0085.Composing) - register_stanza_plugin(Message, xep_0085.Gone) - register_stanza_plugin(Message, xep_0085.Inactive) - register_stanza_plugin(Message, xep_0085.Paused) + register_stanza_plugin(Message, xep_0085.ChatState) def testCreateChatState(self): """Testing creating chat states.""" @@ -20,25 +16,26 @@ class TestChatStates(SleekTest): """ msg = self.Message() - msg['chat_state'].active() - self.check(msg, xmlstring % 'active', - use_values=False) - msg['chat_state'].composing() - self.check(msg, xmlstring % 'composing', - use_values=False) + self.assertEqual(msg['chat_state'], '') + self.check(msg, "", use_values=False) + msg['chat_state'] = 'active' + self.check(msg, xmlstring % 'active', use_values=False) - msg['chat_state'].gone() - self.check(msg, xmlstring % 'gone', - use_values=False) + msg['chat_state'] = 'composing' + self.check(msg, xmlstring % 'composing', use_values=False) - msg['chat_state'].inactive() - self.check(msg, xmlstring % 'inactive', - use_values=False) + msg['chat_state'] = 'gone' + self.check(msg, xmlstring % 'gone', use_values=False) - msg['chat_state'].paused() - self.check(msg, xmlstring % 'paused', - use_values=False) + msg['chat_state'] = 'inactive' + self.check(msg, xmlstring % 'inactive', use_values=False) + + msg['chat_state'] = 'paused' + self.check(msg, xmlstring % 'paused', use_values=False) + + del msg['chat_state'] + self.check(msg, "") suite = unittest.TestLoader().loadTestsFromTestCase(TestChatStates)