XEP-0482: add initial support
This commit is contained in:
parent
3de8ee97b5
commit
a30f76892b
8
doap.xml
8
doap.xml
@ -941,6 +941,14 @@
|
|||||||
<xmpp:since>1.8.6</xmpp:since>
|
<xmpp:since>1.8.6</xmpp:since>
|
||||||
</xmpp:SupportedXep>
|
</xmpp:SupportedXep>
|
||||||
</implements>
|
</implements>
|
||||||
|
<implements>
|
||||||
|
<xmpp:SupportedXep>
|
||||||
|
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0482.html"/>
|
||||||
|
<xmpp:status>complete</xmpp:status>
|
||||||
|
<xmpp:version>0.1.0</xmpp:version>
|
||||||
|
<xmpp:since>1.8.7</xmpp:since>
|
||||||
|
</xmpp:SupportedXep>
|
||||||
|
</implements>
|
||||||
<implements>
|
<implements>
|
||||||
<xmpp:SupportedXep>
|
<xmpp:SupportedXep>
|
||||||
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0490.html"/>
|
<xmpp:xep rdf:resource="https://xmpp.org/extensions/xep-0490.html"/>
|
||||||
|
@ -122,6 +122,7 @@ PLUGINS = [
|
|||||||
'xep_0447', # Stateless file sharing
|
'xep_0447', # Stateless file sharing
|
||||||
'xep_0461', # Message Replies
|
'xep_0461', # Message Replies
|
||||||
'xep_0469', # Bookmarks Pinning
|
'xep_0469', # Bookmarks Pinning
|
||||||
|
'xep_0482', # Call Invites
|
||||||
'xep_0490', # Message Displayed Synchronization
|
'xep_0490', # Message Displayed Synchronization
|
||||||
'xep_0492', # Chat Notification Settings
|
'xep_0492', # Chat Notification Settings
|
||||||
# Meant to be imported by plugins
|
# Meant to be imported by plugins
|
||||||
|
11
slixmpp/plugins/xep_0482/__init__.py
Normal file
11
slixmpp/plugins/xep_0482/__init__.py
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# Slixmpp: The Slick XMPP Library
|
||||||
|
# Copyright (C) 2025 Mathieu Pasquet
|
||||||
|
# This file is part of Slixmpp.
|
||||||
|
# See the file LICENSE for copying permissio
|
||||||
|
from slixmpp.plugins.base import register_plugin
|
||||||
|
|
||||||
|
from slixmpp.plugins.xep_0482 import stanza
|
||||||
|
from slixmpp.plugins.xep_0482.call_invites import XEP_0482
|
||||||
|
|
||||||
|
|
||||||
|
register_plugin(XEP_0482)
|
55
slixmpp/plugins/xep_0482/call_invites.py
Normal file
55
slixmpp/plugins/xep_0482/call_invites.py
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
# Slixmpp: The Slick XMPP Library
|
||||||
|
# Copyright (C) 2025 Mathieu Pasquet
|
||||||
|
# This file is part of Slixmpp.
|
||||||
|
# See the file LICENSE for copying permissio
|
||||||
|
import logging
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from slixmpp.stanza import Message
|
||||||
|
from slixmpp.jid import JID
|
||||||
|
from slixmpp.xmlstream.handler import Callback
|
||||||
|
from slixmpp.xmlstream.matcher import StanzaPath
|
||||||
|
from slixmpp.xmlstream import register_stanza_plugin
|
||||||
|
from slixmpp.plugins import BasePlugin
|
||||||
|
from slixmpp.plugins.xep_0482 import stanza
|
||||||
|
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class XEP_0482(BasePlugin):
|
||||||
|
|
||||||
|
"""
|
||||||
|
XEP-0482: Call Invites
|
||||||
|
|
||||||
|
This plugin defines the stanza elements for Call Invites, as well as new
|
||||||
|
events:
|
||||||
|
|
||||||
|
- `call-invite`
|
||||||
|
- `call-reject`
|
||||||
|
- `call-retract`
|
||||||
|
- `call-leave`
|
||||||
|
- `call-left`
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = 'xep_0482'
|
||||||
|
description = 'XEP-0482: Call Invites'
|
||||||
|
dependencies = set()
|
||||||
|
stanza = stanza
|
||||||
|
|
||||||
|
def plugin_init(self):
|
||||||
|
stanza.register_plugins()
|
||||||
|
|
||||||
|
for event in ('invite', 'reject', 'retract', 'leave', 'left'):
|
||||||
|
self.xmpp.register_handler(
|
||||||
|
Callback(f'Call {event}',
|
||||||
|
StanzaPath(f'message/call-{event}'),
|
||||||
|
self._handle_event))
|
||||||
|
def _handle_event(self, message):
|
||||||
|
for event in ('invite', 'reject', 'retract', 'leave', 'left'):
|
||||||
|
if message.get_plugin(f'call-{event}', check=True):
|
||||||
|
self.xmpp.event(f'call-{event}')
|
||||||
|
|
||||||
|
def plugin_end(self):
|
||||||
|
for event in ('invite', 'reject', 'retract', 'leave', 'left'):
|
||||||
|
self.xmpp.remove_handler(f'Call {event}')
|
102
slixmpp/plugins/xep_0482/stanza.py
Normal file
102
slixmpp/plugins/xep_0482/stanza.py
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
# Slixmpp: The Slick XMPP Library
|
||||||
|
# Copyright (C) 2025 Mathieu Pasquet
|
||||||
|
# This file is part of Slixmpp.
|
||||||
|
# See the file LICENSE for copying permission
|
||||||
|
|
||||||
|
from typing import Tuple, List, Optional
|
||||||
|
from slixmpp import Message
|
||||||
|
from slixmpp.jid import JID
|
||||||
|
from slixmpp.xmlstream import ElementBase, register_stanza_plugin
|
||||||
|
|
||||||
|
NS = 'urn:xmpp:call-invites:0'
|
||||||
|
|
||||||
|
|
||||||
|
class Jingle(ElementBase):
|
||||||
|
name = 'jingle'
|
||||||
|
namespace = NS
|
||||||
|
plugin_attrib = 'jingle'
|
||||||
|
plugin_multi_attrib = 'jingles'
|
||||||
|
interfaces = {'sid', 'jid'}
|
||||||
|
|
||||||
|
def set_jid(self, value: JID) -> None:
|
||||||
|
if not isinstance(value, JID):
|
||||||
|
try:
|
||||||
|
value = JID(value)
|
||||||
|
except ValueError:
|
||||||
|
raise ValueError(f'"jid" must be a valid JID object')
|
||||||
|
self.xml.attrib['jid'] = value.full
|
||||||
|
|
||||||
|
def get_jid(self) -> Optional[JID]:
|
||||||
|
try:
|
||||||
|
return JID(self.xml.attrib.get('jid', ''))
|
||||||
|
except ValueError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
class External(ElementBase):
|
||||||
|
name = 'external'
|
||||||
|
namespace = NS
|
||||||
|
plugin_attrib = 'external'
|
||||||
|
plugin_multi_attrib = 'externals'
|
||||||
|
interfaces = {'uri'}
|
||||||
|
|
||||||
|
|
||||||
|
class Invite(ElementBase):
|
||||||
|
name = 'invite'
|
||||||
|
namespace = NS
|
||||||
|
plugin_attrib = 'call-invite'
|
||||||
|
interfaces = {'video'}
|
||||||
|
|
||||||
|
def get_methods(self) -> Tuple[List[Jingle], List[External]]:
|
||||||
|
return (self['jingles'], self['externals'])
|
||||||
|
|
||||||
|
def set_video(self, value: bool) -> None:
|
||||||
|
if not isinstance(value, bool):
|
||||||
|
raise ValueError(f'Invalid value for the video attribute: {value}')
|
||||||
|
self.xml.attrib['video'] = str(value).lower()
|
||||||
|
|
||||||
|
def get_video(self) -> bool:
|
||||||
|
vid = self.xml.attrib.get('video', 'false').lower()
|
||||||
|
return vid == 'true'
|
||||||
|
|
||||||
|
|
||||||
|
class Retract(ElementBase):
|
||||||
|
name = 'retract'
|
||||||
|
namespace = NS
|
||||||
|
plugin_attrib = 'call-retract'
|
||||||
|
interfaces = {'id'}
|
||||||
|
|
||||||
|
|
||||||
|
class Accept(ElementBase):
|
||||||
|
name = 'accept'
|
||||||
|
namespace = NS
|
||||||
|
plugin_attrib = 'call-accept'
|
||||||
|
interfaces = {'id'}
|
||||||
|
|
||||||
|
|
||||||
|
class Reject(ElementBase):
|
||||||
|
name = 'reject'
|
||||||
|
namespace = NS
|
||||||
|
plugin_attrib = 'call-reject'
|
||||||
|
interfaces = {'id'}
|
||||||
|
|
||||||
|
|
||||||
|
class Left(ElementBase):
|
||||||
|
name = 'left'
|
||||||
|
namespace = NS
|
||||||
|
plugin_attrib = 'call-left'
|
||||||
|
interfaces = {'id'}
|
||||||
|
|
||||||
|
|
||||||
|
def register_plugins() -> None:
|
||||||
|
register_stanza_plugin(Message, Invite)
|
||||||
|
register_stanza_plugin(Message, Retract)
|
||||||
|
register_stanza_plugin(Message, Accept)
|
||||||
|
register_stanza_plugin(Message, Reject)
|
||||||
|
register_stanza_plugin(Message, Left)
|
||||||
|
|
||||||
|
register_stanza_plugin(Invite, Jingle, iterable=True)
|
||||||
|
register_stanza_plugin(Invite, External, iterable=True)
|
||||||
|
|
||||||
|
register_stanza_plugin(Accept, Jingle)
|
||||||
|
register_stanza_plugin(Accept, External)
|
42
tests/test_stanza_xep_0482.py
Normal file
42
tests/test_stanza_xep_0482.py
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import unittest
|
||||||
|
from slixmpp import Message
|
||||||
|
from slixmpp.jid import JID
|
||||||
|
from slixmpp.test import SlixTest
|
||||||
|
from slixmpp.plugins.xep_0482 import stanza
|
||||||
|
from slixmpp.plugins.xep_0482.stanza import External, Jingle
|
||||||
|
from slixmpp.xmlstream import register_stanza_plugin
|
||||||
|
|
||||||
|
|
||||||
|
class TestCallInviteStanza(SlixTest):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
stanza.register_plugins()
|
||||||
|
|
||||||
|
def test_invite(self):
|
||||||
|
"""Test that the element is created correctly."""
|
||||||
|
msg = Message()
|
||||||
|
msg['call-invite']['video'] = True
|
||||||
|
jingle = Jingle()
|
||||||
|
jingle['sid'] = 'toto'
|
||||||
|
jingle['jid'] = JID('toto@example.com/m')
|
||||||
|
external = External()
|
||||||
|
external['uri'] = "https://example.com/call"
|
||||||
|
msg['call-invite'].append(jingle)
|
||||||
|
msg['call-invite'].append(external)
|
||||||
|
|
||||||
|
self.check(msg, """
|
||||||
|
<message>
|
||||||
|
<invite xmlns="urn:xmpp:call-invites:0" video="true">
|
||||||
|
<jingle sid="toto" jid="toto@example.com/m" />
|
||||||
|
<external uri="https://example.com/call" />
|
||||||
|
</invite>
|
||||||
|
</message>
|
||||||
|
""")
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
msg['call-invite'].get_methods(),
|
||||||
|
([jingle], [external]),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
suite = unittest.TestLoader().loadTestsFromTestCase(TestCallInviteStanza)
|
Loading…
Reference in New Issue
Block a user