summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--slixmpp/plugins/xep_0045/__init__.py14
-rw-r--r--slixmpp/plugins/xep_0045/muc.py (renamed from slixmpp/plugins/xep_0045.py)109
-rw-r--r--slixmpp/plugins/xep_0045/stanza.py149
3 files changed, 175 insertions, 97 deletions
diff --git a/slixmpp/plugins/xep_0045/__init__.py b/slixmpp/plugins/xep_0045/__init__.py
new file mode 100644
index 00000000..eb13b018
--- /dev/null
+++ b/slixmpp/plugins/xep_0045/__init__.py
@@ -0,0 +1,14 @@
+"""
+ Slixmpp: The Slick XMPP Library
+ Copyright (C) 2020 "Maxime “pep” Buquet <pep@bouah.net>"
+ This file is part of Slixmpp.
+
+ See the file LICENSE for copying permission.
+"""
+
+from slixmpp.plugins import register_plugin
+from slixmpp.plugins.xep_0045 import stanza
+from slixmpp.plugins.xep_0045.muc import XEP_0045
+from slixmpp.plugins.xep_0045.stanza import MUCPresence, MUCMessage
+
+register_plugin(XEP_0045)
diff --git a/slixmpp/plugins/xep_0045.py b/slixmpp/plugins/xep_0045/muc.py
index dfbb3b58..364c47fd 100644
--- a/slixmpp/plugins/xep_0045.py
+++ b/slixmpp/plugins/xep_0045/muc.py
@@ -1,6 +1,7 @@
"""
Slixmpp: The Slick XMPP Library
Copyright (C) 2010 Nathanael C. Fritz
+ Copyright (C) 2020 "Maxime “pep” Buquet <pep@bouah.net>"
This file is part of Slixmpp.
See the file LICENSE for copying permission.
@@ -10,103 +11,18 @@ from __future__ import with_statement
import logging
from slixmpp import Presence, Message
-from slixmpp.plugins import BasePlugin, register_plugin
-from slixmpp.xmlstream import register_stanza_plugin, ElementBase, JID, ET
+from slixmpp.plugins import BasePlugin
+from slixmpp.xmlstream import register_stanza_plugin, ET
from slixmpp.xmlstream.handler.callback import Callback
from slixmpp.xmlstream.matcher.xpath import MatchXPath
from slixmpp.xmlstream.matcher.xmlmask import MatchXMLMask
from slixmpp.exceptions import IqError, IqTimeout
+from slixmpp.plugins.xep_0045 import stanza
+from slixmpp.plugins.xep_0045.stanza import MUCPresence, MUCMessage
-log = logging.getLogger(__name__)
-
-
-class MUCPresence(ElementBase):
- name = 'x'
- namespace = 'http://jabber.org/protocol/muc#user'
- plugin_attrib = 'muc'
- interfaces = {'affiliation', 'role', 'jid', 'nick', 'room'}
- affiliations = {'', }
- roles = {'', }
-
- def get_item_attr(self, attr, default):
- item = self.xml.find('{http://jabber.org/protocol/muc#user}item')
- if item is None:
- return default
- return item.get(attr)
-
- def set_item_attr(self, attr, value):
- item = self.xml.find('{http://jabber.org/protocol/muc#user}item')
- if item is None:
- item = ET.Element('{http://jabber.org/protocol/muc#user}item')
- self.xml.append(item)
- item.attrib[attr] = value
- return item
-
- def del_item_attr(self, attr):
- item = self.xml.find('{http://jabber.org/protocol/muc#user}item')
- if item is not None and attr in item.attrib:
- del item.attrib[attr]
-
- def get_affiliation(self):
- return self.get_item_attr('affiliation', '')
-
- def set_affiliation(self, value):
- self.set_item_attr('affiliation', value)
- return self
-
- def del_affiliation(self):
- # TODO: set default affiliation
- self.del_item_attr('affiliation')
- return self
-
- def get_jid(self):
- return JID(self.get_item_attr('jid', ''))
-
- def set_jid(self, value):
- if not isinstance(value, str):
- value = str(value)
- self.set_item_attr('jid', value)
- return self
-
- def del_jid(self):
- self.del_item_attr('jid')
- return self
- def get_role(self):
- return self.get_item_attr('role', '')
-
- def set_role(self, value):
- # TODO: check for valid role
- self.set_item_attr('role', value)
- return self
-
- def del_role(self):
- # TODO: set default role
- self.del_item_attr('role')
- return self
-
- def get_nick(self):
- return self.parent()['from'].resource
-
- def get_room(self):
- return self.parent()['from'].bare
-
- def set_nick(self, value):
- log.warning("Cannot set nick through mucpresence plugin.")
- return self
-
- def set_room(self, value):
- log.warning("Cannot set room through mucpresence plugin.")
- return self
-
- def del_nick(self):
- log.warning("Cannot delete nick through mucpresence plugin.")
- return self
-
- def del_room(self):
- log.warning("Cannot delete room through mucpresence plugin.")
- return self
+log = logging.getLogger(__name__)
class XEP_0045(BasePlugin):
@@ -118,6 +34,7 @@ class XEP_0045(BasePlugin):
name = 'xep_0045'
description = 'XEP-0045: Multi-User Chat'
dependencies = {'xep_0030', 'xep_0004'}
+ stanza = stanza
def plugin_init(self):
self.rooms = {}
@@ -125,6 +42,7 @@ class XEP_0045(BasePlugin):
self.xep = '0045'
# load MUC support in presence stanzas
register_stanza_plugin(Presence, MUCPresence)
+ register_stanza_plugin(Message, MUCMessage)
self.xmpp.register_handler(Callback('MUCPresence', MatchXMLMask("<presence xmlns='%s' />" % self.xmpp.default_ns), self.handle_groupchat_presence))
self.xmpp.register_handler(Callback('MUCError', MatchXMLMask("<message xmlns='%s' type='error'><error/></message>" % self.xmpp.default_ns), self.handle_groupchat_error_message))
self.xmpp.register_handler(Callback('MUCMessage', MatchXMLMask("<message xmlns='%s' type='groupchat'><body/></message>" % self.xmpp.default_ns), self.handle_groupchat_message))
@@ -132,14 +50,14 @@ class XEP_0045(BasePlugin):
self.xmpp.register_handler(Callback('MUCConfig', MatchXMLMask("<message xmlns='%s' type='groupchat'><x xmlns='http://jabber.org/protocol/muc#user'><status/></x></message>" % self.xmpp.default_ns), self.handle_config_change))
self.xmpp.register_handler(Callback('MUCInvite', MatchXPath("{%s}message/{%s}x/{%s}invite" % (
self.xmpp.default_ns,
- 'http://jabber.org/protocol/muc#user',
- 'http://jabber.org/protocol/muc#user')), self.handle_groupchat_invite))
+ stanza.NS_USER,
+ stanza.NS_USER)), self.handle_groupchat_invite))
def plugin_end(self):
- self.xmpp.plugin['xep_0030'].del_feature(feature='http://jabber.org/protocol/muc')
+ self.xmpp.plugin['xep_0030'].del_feature(feature=stanza.NS)
def session_bind(self, jid):
- self.xmpp.plugin['xep_0030'].add_feature('http://jabber.org/protocol/muc')
+ self.xmpp.plugin['xep_0030'].add_feature(stanza.NS)
def handle_groupchat_invite(self, inv):
""" Handle an invite into a muc.
@@ -417,6 +335,3 @@ class XEP_0045(BasePlugin):
iq = cls.xmpp.Iq(sto=room, sfrom=ifrom, stype='get')
iq.append(query)
return iq.send()
-
-
-register_plugin(XEP_0045)
diff --git a/slixmpp/plugins/xep_0045/stanza.py b/slixmpp/plugins/xep_0045/stanza.py
new file mode 100644
index 00000000..1550853f
--- /dev/null
+++ b/slixmpp/plugins/xep_0045/stanza.py
@@ -0,0 +1,149 @@
+"""
+ Slixmpp: The Slick XMPP Library
+ Copyright (C) 2010 Nathanael C. Fritz
+ Copyright (C) 2020 "Maxime “pep” Buquet <pep@bouah.net>"
+ This file is part of Slixmpp.
+
+ See the file LICENSE for copying permission.
+"""
+
+import logging
+from slixmpp.xmlstream import ElementBase, ET, JID
+
+
+log = logging.getLogger(__name__)
+
+NS = 'http://jabber.org/protocol/muc'
+NS_USER = 'http://jabber.org/protocol/muc#user'
+NS_ADMIN = 'http://jabber.org/protocol/muc#admin'
+NS_OWNER = 'http://jabber.org/protocol/muc#owner'
+
+
+class MUCBase(ElementBase):
+ name = 'x'
+ namespace = NS_USER
+ plugin_attrib = 'muc'
+ interfaces = {'affiliation', 'role', 'jid', 'nick', 'room'}
+
+ def get_item_attr(self, attr, default: str):
+ item = self.xml.find('{{{NS_USER}}}item')
+ if item is None:
+ return default
+ return item.get(attr)
+
+ def set_item_attr(self, attr, value: str):
+ item = self.xml.find(f'{{{NS_USER}}}item')
+ if item is None:
+ item = ET.Element(f'{{{NS_USER}}}item')
+ self.xml.append(item)
+ item.attrib[attr] = value
+ return item
+
+ def del_item_attr(self, attr):
+ item = self.xml.find('{{{NS_USER}}}item')
+ if item is not None and attr in item.attrib:
+ del item.attrib[attr]
+
+ def get_affiliation(self):
+ return self.get_item_attr('affiliation', '')
+
+ def set_affiliation(self, value):
+ self.set_item_attr('affiliation', value)
+ return self
+
+ def del_affiliation(self):
+ # TODO: set default affiliation
+ self.del_item_attr('affiliation')
+ return self
+
+ def get_jid(self):
+ return JID(self.get_item_attr('jid', ''))
+
+ def set_jid(self, value):
+ if not isinstance(value, str):
+ value = str(value)
+ self.set_item_attr('jid', value)
+ return self
+
+ def del_jid(self):
+ self.del_item_attr('jid')
+ return self
+
+ def get_role(self):
+ return self.get_item_attr('role', '')
+
+ def set_role(self, value):
+ # TODO: check for valid role
+ self.set_item_attr('role', value)
+ return self
+
+ def del_role(self):
+ # TODO: set default role
+ self.del_item_attr('role')
+ return self
+
+ def get_nick(self):
+ return self.parent()['from'].resource
+
+ def get_room(self):
+ return self.parent()['from'].bare
+
+ def set_nick(self, value):
+ log.warning(
+ "Cannot set nick through the %s plugin.",
+ self.__class__.__name__,
+ )
+ return self
+
+ def set_room(self, value):
+ log.warning(
+ "Cannot set room through the %s plugin.",
+ self.__class__.__name__,
+ )
+ return self
+
+ def del_nick(self):
+ log.warning(
+ "Cannot delete nick through the %s plugin.",
+ self.__class__.__name__,
+ )
+ return self
+
+ def del_room(self):
+ log.warning(
+ "Cannot delete room through the %s plugin.",
+ self.__class__.__name__,
+ )
+ return self
+
+
+class MUCPresence(MUCBase):
+ '''
+ A MUC Presence
+
+ <presence from='foo@muc/user1' type='unavailable'>
+ <x xmlns='http://jabber.org/protocol/muc#user'>
+ <item affiliation='none'
+ role='none'
+ nick='newnick2'
+ jid='some@jid'/>
+ <status code='303'/>
+ </x>
+ </presence>
+ '''
+
+
+class MUCMessage(MUCBase):
+ '''
+ A MUC Message
+
+ <message from='foo@muc/user1' type='groupchat' id='someid'>
+ <body>Foo</body>
+ <x xmlns='http://jabber.org/protocol/muc#user'>
+ <item affiliation='none'
+ role='none'
+ nick='newnick2'
+ jid='some@jid'/>
+ </x>
+ </message>
+ '''