Coverage for slidge / core / mixins / disco.py: 97%
86 statements
« prev ^ index » next coverage.py v7.13.0, created at 2026-02-15 09:02 +0000
« prev ^ index » next coverage.py v7.13.0, created at 2026-02-15 09:02 +0000
1from slixmpp.plugins.xep_0004 import Form
2from slixmpp.plugins.xep_0030.stanza.info import DiscoInfo
3from slixmpp.types import OptJid
5from .base import Base
8class BaseDiscoMixin(Base):
9 DISCO_TYPE: str = NotImplemented
10 DISCO_CATEGORY: str = NotImplemented
11 DISCO_NAME: str = NotImplemented
12 DISCO_LANG = None
14 def _get_disco_name(self) -> str | None:
15 if self.DISCO_NAME is NotImplemented:
16 return self.xmpp.COMPONENT_NAME
17 return self.DISCO_NAME or self.xmpp.COMPONENT_NAME
19 def features(self):
20 return []
22 async def extended_features(self) -> list[Form] | None:
23 return None
25 async def get_disco_info(self, jid: OptJid = None, node: str | None = None):
26 info = DiscoInfo()
27 for feature in self.features():
28 info.add_feature(feature)
29 info.add_identity(
30 category=self.DISCO_CATEGORY,
31 itype=self.DISCO_TYPE,
32 name=self._get_disco_name(),
33 lang=self.DISCO_LANG,
34 )
35 if forms := await self.extended_features():
36 for form in forms:
37 info.append(form)
38 return info
40 async def get_caps_ver(self, jid: OptJid = None, node: str | None = None):
41 info = await self.get_disco_info(jid, node)
42 caps = self.xmpp.plugin["xep_0115"]
43 ver = caps.generate_verstring(info, caps.hash)
44 return ver
47class ChatterDiscoMixin(BaseDiscoMixin):
48 AVATAR = True
49 RECEIPTS = True
50 MARKS = True
51 CHAT_STATES = True
52 UPLOAD = True
53 CORRECTION = True
54 REACTION = True
55 RETRACTION = True
56 REPLIES = True
57 INVITATION_RECIPIENT = False
59 DISCO_TYPE = "pc"
60 DISCO_CATEGORY = "client"
61 DISCO_NAME = ""
63 def features(self):
64 features = []
65 if self.CHAT_STATES:
66 features.append("http://jabber.org/protocol/chatstates")
67 if self.RECEIPTS:
68 features.append("urn:xmpp:receipts")
69 if self.CORRECTION:
70 features.append("urn:xmpp:message-correct:0")
71 if self.MARKS:
72 features.append("urn:xmpp:chat-markers:0")
73 if self.UPLOAD:
74 features.append("jabber:x:oob")
75 if self.REACTION:
76 features.append("urn:xmpp:reactions:0")
77 if self.RETRACTION:
78 features.append("urn:xmpp:message-retract:0")
79 if self.REPLIES:
80 features.append("urn:xmpp:reply:0")
81 if self.INVITATION_RECIPIENT:
82 features.append("jabber:x:conference")
83 features.append("urn:ietf:params:xml:ns:vcard-4.0")
84 return features
86 async def extended_features(self):
87 f = getattr(self, "restricted_emoji_extended_feature", None)
88 if f is None:
89 return
91 e = await f()
92 if not e:
93 return
95 return [e]
98class ContactAccountDiscoMixin(BaseDiscoMixin):
99 async def get_disco_info(self, jid: OptJid = None, node: str | None = None):
100 if jid and jid.resource:
101 return await super().get_disco_info()
102 info = DiscoInfo()
103 info.add_feature("http://jabber.org/protocol/pubsub")
104 info.add_feature("http://jabber.org/protocol/pubsub#retrieve-items")
105 info.add_feature("http://jabber.org/protocol/pubsub#subscribe")
106 info.add_identity(
107 category="account",
108 itype="registered",
109 name=self._get_disco_name(),
110 lang=self.DISCO_LANG,
111 )
112 info.add_identity(
113 category="pubsub",
114 itype="pep",
115 name=self._get_disco_name(),
116 lang=self.DISCO_LANG,
117 )
118 return info