slidge 0.1.0rc1__py3-none-any.whl → 0.1.1__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (164) hide show
  1. slidge/__init__.py +54 -31
  2. slidge/__main__.py +51 -5
  3. slidge/command/__init__.py +28 -0
  4. slidge/command/adhoc.py +258 -0
  5. slidge/command/admin.py +193 -0
  6. slidge/command/base.py +441 -0
  7. slidge/command/categories.py +3 -0
  8. slidge/command/chat_command.py +288 -0
  9. slidge/command/register.py +179 -0
  10. slidge/command/user.py +250 -0
  11. slidge/contact/__init__.py +8 -0
  12. slidge/contact/contact.py +452 -0
  13. slidge/contact/roster.py +192 -0
  14. slidge/core/__init__.py +2 -0
  15. slidge/core/cache.py +121 -39
  16. slidge/core/config.py +116 -11
  17. slidge/core/gateway/__init__.py +3 -0
  18. slidge/core/gateway/base.py +895 -0
  19. slidge/core/gateway/caps.py +63 -0
  20. slidge/core/gateway/delivery_receipt.py +52 -0
  21. slidge/core/gateway/disco.py +80 -0
  22. slidge/core/gateway/mam.py +75 -0
  23. slidge/core/gateway/muc_admin.py +35 -0
  24. slidge/core/gateway/ping.py +66 -0
  25. slidge/core/gateway/presence.py +95 -0
  26. slidge/core/gateway/registration.py +53 -0
  27. slidge/core/gateway/search.py +102 -0
  28. slidge/core/gateway/session_dispatcher.py +789 -0
  29. slidge/core/gateway/vcard_temp.py +130 -0
  30. slidge/core/mixins/__init__.py +9 -1
  31. slidge/core/mixins/attachment.py +506 -0
  32. slidge/core/mixins/avatar.py +167 -0
  33. slidge/core/mixins/base.py +6 -19
  34. slidge/core/mixins/disco.py +66 -15
  35. slidge/core/mixins/lock.py +31 -0
  36. slidge/core/mixins/message.py +254 -252
  37. slidge/core/mixins/message_maker.py +154 -0
  38. slidge/core/mixins/presence.py +128 -31
  39. slidge/core/mixins/recipient.py +43 -0
  40. slidge/core/pubsub.py +275 -116
  41. slidge/core/session.py +586 -518
  42. slidge/group/__init__.py +10 -0
  43. slidge/group/archive.py +125 -0
  44. slidge/group/bookmarks.py +163 -0
  45. slidge/group/participant.py +458 -0
  46. slidge/group/room.py +1103 -0
  47. slidge/migration.py +18 -0
  48. slidge/slixfix/__init__.py +68 -0
  49. slidge/{util/xep_0050 → slixfix/link_preview}/__init__.py +4 -5
  50. slidge/slixfix/link_preview/link_preview.py +17 -0
  51. slidge/slixfix/link_preview/stanza.py +99 -0
  52. slidge/slixfix/roster.py +60 -0
  53. slidge/{util → slixfix}/xep_0077/register.py +1 -2
  54. slidge/slixfix/xep_0077/stanza.py +104 -0
  55. slidge/{util → slixfix}/xep_0100/gateway.py +17 -12
  56. slidge/slixfix/xep_0153/__init__.py +10 -0
  57. slidge/slixfix/xep_0153/stanza.py +25 -0
  58. slidge/slixfix/xep_0153/vcard_avatar.py +23 -0
  59. slidge/slixfix/xep_0264/__init__.py +5 -0
  60. slidge/slixfix/xep_0264/stanza.py +36 -0
  61. slidge/slixfix/xep_0264/thumbnail.py +23 -0
  62. slidge/slixfix/xep_0292/__init__.py +5 -0
  63. slidge/slixfix/xep_0292/vcard4.py +100 -0
  64. slidge/slixfix/xep_0313/__init__.py +12 -0
  65. slidge/slixfix/xep_0313/mam.py +262 -0
  66. slidge/slixfix/xep_0313/stanza.py +359 -0
  67. slidge/slixfix/xep_0317/__init__.py +5 -0
  68. slidge/slixfix/xep_0317/hats.py +17 -0
  69. slidge/slixfix/xep_0317/stanza.py +28 -0
  70. slidge/{util → slixfix}/xep_0356_old/privilege.py +9 -7
  71. slidge/slixfix/xep_0424/__init__.py +9 -0
  72. slidge/slixfix/xep_0424/retraction.py +77 -0
  73. slidge/slixfix/xep_0424/stanza.py +28 -0
  74. slidge/slixfix/xep_0490/__init__.py +8 -0
  75. slidge/slixfix/xep_0490/mds.py +47 -0
  76. slidge/slixfix/xep_0490/stanza.py +17 -0
  77. slidge/util/__init__.py +4 -6
  78. slidge/util/archive_msg.py +61 -0
  79. slidge/util/conf.py +25 -4
  80. slidge/util/db.py +23 -69
  81. slidge/util/schema.sql +126 -0
  82. slidge/util/sql.py +508 -0
  83. slidge/util/test.py +136 -86
  84. slidge/util/types.py +155 -14
  85. slidge/util/util.py +225 -51
  86. slidge-0.1.1.dist-info/METADATA +110 -0
  87. slidge-0.1.1.dist-info/RECORD +96 -0
  88. {slidge-0.1.0rc1.dist-info → slidge-0.1.1.dist-info}/WHEEL +1 -1
  89. slidge/core/adhoc.py +0 -492
  90. slidge/core/chat_command.py +0 -197
  91. slidge/core/contact.py +0 -441
  92. slidge/core/disco.py +0 -59
  93. slidge/core/gateway.py +0 -899
  94. slidge/core/muc/__init__.py +0 -3
  95. slidge/core/muc/bookmarks.py +0 -74
  96. slidge/core/muc/participant.py +0 -152
  97. slidge/core/muc/room.py +0 -348
  98. slidge/plugins/discord/__init__.py +0 -121
  99. slidge/plugins/discord/client.py +0 -121
  100. slidge/plugins/discord/session.py +0 -172
  101. slidge/plugins/dummy.py +0 -334
  102. slidge/plugins/facebook.py +0 -591
  103. slidge/plugins/hackernews.py +0 -209
  104. slidge/plugins/mattermost/__init__.py +0 -1
  105. slidge/plugins/mattermost/api.py +0 -288
  106. slidge/plugins/mattermost/gateway.py +0 -417
  107. slidge/plugins/mattermost/websocket.py +0 -248
  108. slidge/plugins/signal/__init__.py +0 -4
  109. slidge/plugins/signal/config.py +0 -4
  110. slidge/plugins/signal/contact.py +0 -104
  111. slidge/plugins/signal/gateway.py +0 -379
  112. slidge/plugins/signal/group.py +0 -76
  113. slidge/plugins/signal/session.py +0 -515
  114. slidge/plugins/signal/txt.py +0 -13
  115. slidge/plugins/signal/util.py +0 -32
  116. slidge/plugins/skype.py +0 -310
  117. slidge/plugins/steam.py +0 -400
  118. slidge/plugins/telegram/__init__.py +0 -6
  119. slidge/plugins/telegram/client.py +0 -325
  120. slidge/plugins/telegram/config.py +0 -21
  121. slidge/plugins/telegram/contact.py +0 -154
  122. slidge/plugins/telegram/gateway.py +0 -182
  123. slidge/plugins/telegram/group.py +0 -184
  124. slidge/plugins/telegram/session.py +0 -275
  125. slidge/plugins/telegram/util.py +0 -153
  126. slidge/plugins/whatsapp/__init__.py +0 -6
  127. slidge/plugins/whatsapp/config.py +0 -17
  128. slidge/plugins/whatsapp/contact.py +0 -33
  129. slidge/plugins/whatsapp/event.go +0 -455
  130. slidge/plugins/whatsapp/gateway.go +0 -156
  131. slidge/plugins/whatsapp/gateway.py +0 -69
  132. slidge/plugins/whatsapp/go.mod +0 -17
  133. slidge/plugins/whatsapp/go.sum +0 -22
  134. slidge/plugins/whatsapp/session.go +0 -371
  135. slidge/plugins/whatsapp/session.py +0 -370
  136. slidge/util/xep_0030/__init__.py +0 -13
  137. slidge/util/xep_0030/disco.py +0 -811
  138. slidge/util/xep_0030/stanza/__init__.py +0 -7
  139. slidge/util/xep_0030/stanza/info.py +0 -270
  140. slidge/util/xep_0030/stanza/items.py +0 -147
  141. slidge/util/xep_0030/static.py +0 -467
  142. slidge/util/xep_0050/adhoc.py +0 -631
  143. slidge/util/xep_0050/stanza.py +0 -180
  144. slidge/util/xep_0077/stanza.py +0 -71
  145. slidge/util/xep_0292/__init__.py +0 -1
  146. slidge/util/xep_0292/stanza.py +0 -167
  147. slidge/util/xep_0292/vcard4.py +0 -74
  148. slidge/util/xep_0356/__init__.py +0 -7
  149. slidge/util/xep_0356/permissions.py +0 -35
  150. slidge/util/xep_0356/privilege.py +0 -160
  151. slidge/util/xep_0356/stanza.py +0 -44
  152. slidge/util/xep_0461/__init__.py +0 -6
  153. slidge/util/xep_0461/reply.py +0 -48
  154. slidge/util/xep_0461/stanza.py +0 -80
  155. slidge-0.1.0rc1.dist-info/METADATA +0 -171
  156. slidge-0.1.0rc1.dist-info/RECORD +0 -99
  157. /slidge/{plugins/__init__.py → py.typed} +0 -0
  158. /slidge/{util → slixfix}/xep_0077/__init__.py +0 -0
  159. /slidge/{util → slixfix}/xep_0100/__init__.py +0 -0
  160. /slidge/{util → slixfix}/xep_0100/stanza.py +0 -0
  161. /slidge/{util → slixfix}/xep_0356_old/__init__.py +0 -0
  162. /slidge/{util → slixfix}/xep_0356_old/stanza.py +0 -0
  163. {slidge-0.1.0rc1.dist-info → slidge-0.1.1.dist-info}/LICENSE +0 -0
  164. {slidge-0.1.0rc1.dist-info → slidge-0.1.1.dist-info}/entry_points.txt +0 -0
slidge/core/contact.py DELETED
@@ -1,441 +0,0 @@
1
- import logging
2
- from datetime import date, datetime
3
- from typing import Any, Generic, Optional, Type, Union
4
-
5
- from slixmpp import JID, Message, Presence
6
- from slixmpp.jid import JID_UNESCAPE_TRANSFORMATIONS, _unescape_node
7
-
8
- from ..util import SubclassableOnce
9
- from ..util.types import (
10
- AvatarType,
11
- LegacyContactType,
12
- LegacyMessageType,
13
- LegacyUserIdType,
14
- SessionType,
15
- )
16
- from ..util.xep_0292.stanza import VCard4
17
- from . import config
18
- from .mixins import FullCarbonMixin
19
- from .mixins.base import ReactionRecipientMixin
20
-
21
-
22
- class LegacyContact(
23
- Generic[SessionType, LegacyUserIdType],
24
- FullCarbonMixin,
25
- ReactionRecipientMixin,
26
- metaclass=SubclassableOnce,
27
- ):
28
- """
29
- This class centralizes actions in relation to a specific legacy contact.
30
-
31
- You shouldn't create instances of contacts manually, but rather rely on
32
- :meth:`.LegacyRoster.by_legacy_id` to ensure that contact instances are
33
- singletons. The :class:`.LegacyRoster` instance of a session is accessible
34
- through the :attr:`.BaseSession.contacts` attribute.
35
-
36
- Typically, your plugin should have methods hook to the legacy events and
37
- call appropriate methods here to transmit the "legacy action" to the xmpp
38
- user. This should look like this:
39
-
40
- .. code-block:python
41
-
42
- class Session(BaseSession):
43
- ...
44
-
45
- async def on_cool_chat_network_new_text_message(self, legacy_msg_event):
46
- contact = self.contacts.by_legacy_id(legacy_msg_event.from)
47
- contact.send_text(legacy_msg_event.text)
48
-
49
- async def on_cool_chat_network_new_typing_event(self, legacy_typing_event):
50
- contact = self.contacts.by_legacy_id(legacy_msg_event.from)
51
- contact.composing()
52
- ...
53
-
54
- Use ``carbon=True`` as a keyword arg for methods to represent an action FROM
55
- the user TO the contact, typically when the user uses an official client to
56
- do an action such as sending a message or marking as message as read.
57
- This will use :xep:`0363` to impersonate the XMPP user in order.
58
- """
59
-
60
- session: "SessionType"
61
-
62
- RESOURCE: str = "slidge"
63
- """
64
- A full JID, including a resource part is required for chat states (and maybe other stuff)
65
- to work properly. This is the name of the resource the contacts will use.
66
- """
67
-
68
- mtype = "chat"
69
- is_group = False
70
-
71
- def __init__(
72
- self,
73
- session: "SessionType",
74
- legacy_id: LegacyUserIdType,
75
- jid_username: str,
76
- ):
77
- """
78
- :param session: The session this contact is part of
79
- :param legacy_id: The contact's legacy ID
80
- :param jid_username: User part of this contact's 'puppet' JID.
81
- NB: case-insensitive, and some special characters are not allowed
82
- """
83
- self.session = session
84
- self.user = session.user
85
- self.legacy_id = legacy_id
86
- self.jid_username = jid_username
87
-
88
- self.added_to_roster = False
89
-
90
- self._name: Optional[str] = None
91
- self._avatar: Optional[AvatarType] = None
92
-
93
- self._subscribe_from = True
94
- self._subscribe_to = True
95
-
96
- if self.xmpp.MARK_ALL_MESSAGES:
97
- self._sent_order = list[str]()
98
-
99
- self.xmpp = session.xmpp
100
- self.jid = JID(self.jid_username + "@" + self.xmpp.boundjid.bare)
101
- self.jid.resource = self.RESOURCE
102
-
103
- def __repr__(self):
104
- return f"<LegacyContact <{self.jid}> ('{self.legacy_id}') of <{self.user}>"
105
-
106
- def __get_subscription_string(self):
107
- if self._subscribe_from and self._subscribe_to:
108
- return "both"
109
- if self._subscribe_from:
110
- return "from"
111
- if self._subscribe_to:
112
- return "to"
113
- return "none"
114
-
115
- def _send(self, stanza: Union[Message, Presence], carbon=False, **send_kwargs):
116
- if carbon and isinstance(stanza, Message):
117
- stanza["to"] = self.jid.bare
118
- stanza["from"] = self.user.jid
119
- self._privileged_send(stanza)
120
- else:
121
- if self.xmpp.MARK_ALL_MESSAGES and is_markable(stanza):
122
- self._sent_order.append(stanza["id"])
123
- stanza["to"] = self.user.jid
124
- stanza.send()
125
-
126
- def get_msg_xmpp_id_up_to(self, horizon_xmpp_id: str):
127
- """
128
- Return XMPP msg ids sent by this contact up to a given XMPP msg id.
129
-
130
- Plugins have no reason to use this, but it is used by slidge core
131
- for legacy networks that need to mark all messages as read (most XMPP
132
- clients only send a read marker for the latest message.
133
-
134
- This has side effects, if the horizon XMPP id is found, messages up to
135
- this horizon are not cleared, to avoid sending the same read mark twice.
136
-
137
- :param horizon_xmpp_id: The latest message
138
- :return: A list of XMPP ids or None if horizon_xmpp_id was not found
139
- """
140
- for i, xmpp_id in enumerate(self._sent_order):
141
- if xmpp_id == horizon_xmpp_id:
142
- break
143
- else:
144
- return
145
- i += 1
146
- res = self._sent_order[:i]
147
- self._sent_order = self._sent_order[i:]
148
- return res
149
-
150
- def send_text(
151
- self,
152
- body: str,
153
- legacy_msg_id: Optional[LegacyMessageType] = None,
154
- *,
155
- when: Optional[datetime] = None,
156
- reply_to_msg_id: Optional[LegacyMessageType] = None,
157
- reply_to_fallback_text: Optional[str] = None,
158
- reply_self=False,
159
- **kwargs,
160
- ):
161
- """
162
- The contact sends a message to the user.
163
-
164
- :param body:
165
- :param legacy_msg_id:
166
- :param when:
167
- :param reply_to_msg_id: Quote another message (:xep:`0461`)
168
- :param reply_to_fallback_text: Fallback text for clients not supporting :xep:`0461`
169
- :param reply_self: Set to true is this is a self quote. If False, it means the
170
- quoted author is the gateway user.
171
- """
172
- super().send_text(
173
- body=body,
174
- legacy_msg_id=legacy_msg_id,
175
- when=when,
176
- reply_to_msg_id=reply_to_msg_id,
177
- reply_to_fallback_text=reply_to_fallback_text,
178
- reply_to_jid=self.jid if reply_self else self.user.jid,
179
- **kwargs,
180
- )
181
-
182
- @property
183
- def name(self):
184
- """
185
- Friendly name of the contact, as it should appear in the user's roster
186
- """
187
- return self._name
188
-
189
- @name.setter
190
- def name(self, n: Optional[str]):
191
- if self._name == n:
192
- return
193
- self._name = n
194
- self.xmpp.pubsub.set_nick(
195
- jid=self.jid.bare, nick=n, restrict_to=self.user.jid.bare
196
- )
197
-
198
- @property
199
- def avatar(self):
200
- """
201
- An image that represents this contact
202
- """
203
- return self._avatar
204
-
205
- @avatar.setter
206
- def avatar(self, a: Optional[AvatarType]):
207
- if a == self._avatar:
208
- return
209
- self.xmpp.loop.create_task(
210
- self.xmpp.pubsub.set_avatar(
211
- jid=self.jid.bare, avatar=a, restrict_to=self.user.jid.bare
212
- )
213
- )
214
- self._avatar = a
215
-
216
- def set_vcard(
217
- self,
218
- /,
219
- full_name: Optional[str] = None,
220
- given: Optional[str] = None,
221
- surname: Optional[str] = None,
222
- birthday: Optional[date] = None,
223
- phone: Optional[str] = None,
224
- note: Optional[str] = None,
225
- url: Optional[str] = None,
226
- email: Optional[str] = None,
227
- country: Optional[str] = None,
228
- locality: Optional[str] = None,
229
- ):
230
- vcard = VCard4()
231
- vcard.add_impp(f"xmpp:{self.jid.bare}")
232
-
233
- if n := self.name:
234
- vcard.add_nickname(n)
235
- if full_name:
236
- vcard["full_name"] = full_name
237
- elif n:
238
- vcard["full_name"] = n
239
-
240
- if given:
241
- vcard["given"] = given
242
- if surname:
243
- vcard["surname"] = surname
244
- if birthday:
245
- vcard["birthday"] = birthday
246
-
247
- if note:
248
- vcard.add_note(note)
249
- if url:
250
- vcard.add_url(url)
251
- if email:
252
- vcard.add_email(email)
253
- if phone:
254
- vcard.add_tel(phone)
255
- if country and locality:
256
- vcard.add_address(country, locality)
257
- elif country:
258
- vcard.add_address(country, locality)
259
-
260
- self.xmpp.vcard.set_vcard(self.jid.bare, vcard, {self.user.jid.bare})
261
-
262
- async def add_to_roster(self):
263
- """
264
- Add this contact to the user roster using :xep:`0356`
265
- """
266
- if config.NO_ROSTER_PUSH:
267
- log.debug("Roster push request by plugin ignored (--no-roster-push)")
268
- return
269
- item = {
270
- "subscription": self.__get_subscription_string(),
271
- "groups": [self.xmpp.ROSTER_GROUP],
272
- }
273
- if (n := self.name) is not None:
274
- item["name"] = n
275
- kw = dict(
276
- jid=self.user.jid,
277
- roster_items={self.jid.bare: item},
278
- )
279
- try:
280
- await self.xmpp["xep_0356"].set_roster(**kw)
281
- except PermissionError:
282
- try:
283
- await self.xmpp["xep_0356_old"].set_roster(**kw)
284
- except PermissionError:
285
- log.warning(
286
- "Slidge does not have privileges to add contacts to the roster."
287
- "Refer to https://slidge.readthedocs.io/en/latest/admin/xmpp_server.html "
288
- "for more info."
289
- )
290
- if config.ROSTER_PUSH_PRESENCE_SUBSCRIPTION_REQUEST_FALLBACK:
291
- self._send(self._make_presence(ptype="subscribe"))
292
- return
293
-
294
- self.added_to_roster = True
295
- self._send_last_presence()
296
-
297
- def unsubscribe(self):
298
- """
299
- Send an "unsubscribe", "unsubscribed", "unavailable" presence sequence
300
- from this contact to the user, ie, "this contact has removed you from
301
- their 'friends'".
302
- """
303
- for ptype in "unsubscribe", "unsubscribed", "unavailable":
304
- self.xmpp.send_presence(pfrom=self.jid, pto=self.user.jid.bare, ptype=ptype) # type: ignore
305
-
306
-
307
- class LegacyRoster(
308
- Generic[SessionType, LegacyContactType, LegacyUserIdType],
309
- metaclass=SubclassableOnce,
310
- ):
311
- """
312
- Virtual roster of a gateway user, that allows to represent all
313
- of their contacts as singleton instances (if used properly and not too bugged).
314
-
315
- Every :class:`.BaseSession` instance will have its own :class:`.LegacyRoster` instance
316
- accessible via the :attr:`.BaseSession.contacts` attribute.
317
-
318
- Typically, you will mostly use the :meth:`.LegacyRoster.by_legacy_id` function to
319
- retrieve a contact instance.
320
-
321
- You might need to override :meth:`.LegacyRoster.legacy_id_to_jid_username` and/or
322
- :meth:`.LegacyRoster.jid_username_to_legacy_id` to incorporate some custom logic
323
- if you need some characters when translation JID user parts and legacy IDs.
324
- """
325
-
326
- def __init__(self, session: "SessionType"):
327
- self._contact_cls: Type[
328
- LegacyContactType
329
- ] = LegacyContact.get_self_or_unique_subclass()
330
- self._contact_cls.xmpp = session.xmpp
331
-
332
- self.session = session
333
- self._contacts_by_bare_jid: dict[str, LegacyContactType] = {}
334
- self._contacts_by_legacy_id: dict[LegacyUserIdType, LegacyContactType] = {}
335
-
336
- def __iter__(self):
337
- return iter(self._contacts_by_legacy_id.values())
338
-
339
- def known_contacts(self):
340
- return self._contacts_by_bare_jid.copy()
341
-
342
- async def by_jid(self, contact_jid: JID) -> LegacyContactType:
343
- """
344
- Retrieve a contact by their JID
345
-
346
- If the contact was not instantiated before, it will be created
347
- using :meth:`slidge.LegacyRoster.jid_username_to_legacy_id` to infer their
348
- legacy user ID.
349
-
350
- :param contact_jid:
351
- :return:
352
- """
353
- bare = contact_jid.bare
354
- c = self._contacts_by_bare_jid.get(bare)
355
- if c is None:
356
- jid_username = str(contact_jid.username)
357
- log.debug("Contact %s not found", contact_jid)
358
- c = self._contact_cls(
359
- self.session,
360
- await self.jid_username_to_legacy_id(jid_username),
361
- jid_username,
362
- )
363
- await c.update_caps()
364
- self._contacts_by_legacy_id[c.legacy_id] = self._contacts_by_bare_jid[
365
- bare
366
- ] = c
367
- return c
368
-
369
- async def by_legacy_id(self, legacy_id: Any) -> LegacyContactType:
370
- """
371
- Retrieve a contact by their legacy_id
372
-
373
- If the contact was not instantiated before, it will be created
374
- using :meth:`slidge.LegacyRoster.legacy_id_to_jid_username` to infer their
375
- legacy user ID.
376
-
377
- :param legacy_id:
378
- :return:
379
- """
380
- c = self._contacts_by_legacy_id.get(legacy_id)
381
- if c is None:
382
- log.debug("Contact %s not found in roster", legacy_id)
383
- c = self._contact_cls(
384
- self.session, legacy_id, await self.legacy_id_to_jid_username(legacy_id)
385
- )
386
- await c.update_caps()
387
- self._contacts_by_bare_jid[c.jid.bare] = self._contacts_by_legacy_id[
388
- legacy_id
389
- ] = c
390
- return c
391
-
392
- async def by_stanza(self, s) -> LegacyContactType:
393
- """
394
- Retrieve a contact by the destination of a stanza
395
-
396
- See :meth:`slidge.Roster.by_legacy_id` for more info.
397
-
398
- :param s:
399
- :return:
400
- """
401
- return await self.by_jid(s.get_to())
402
-
403
- async def legacy_id_to_jid_username(self, legacy_id: Any) -> str:
404
- """
405
- Convert a legacy ID to a valid 'user' part of a JID
406
-
407
- Should be overridden for cases where the str conversion of
408
- the legacy_id is not enough, e.g., if it is case-sensitive or contains
409
- forbidden characters not covered by :xep:`0106`.
410
-
411
- :param legacy_id:
412
- """
413
- return str(legacy_id).translate(ESCAPE_TABLE)
414
-
415
- async def jid_username_to_legacy_id(self, jid_username: str) -> LegacyUserIdType:
416
- """
417
- Convert a JID user part to a legacy ID.
418
-
419
- Should be overridden in case legacy IDs are not strings, or more generally
420
- for any case where the username part of a JID (unescaped with to the mapping
421
- defined by :xep:`0106`) is not enough to identify a contact on the legacy network.
422
-
423
- Default implementation is an identity operation
424
-
425
- :param jid_username: User part of a JID, ie "user" in "user@example.com"
426
- :return: An identifier for the user on the legacy network.
427
- """
428
- return _unescape_node(jid_username)
429
-
430
-
431
- def is_markable(stanza: Union[Message, Presence]):
432
- if isinstance(stanza, Presence):
433
- return False
434
- return bool(stanza["body"])
435
-
436
-
437
- ESCAPE_TABLE = "".maketrans(
438
- {v: k for k, v in JID_UNESCAPE_TRANSFORMATIONS.items()} # type:ignore
439
- )
440
-
441
- log = logging.getLogger(__name__)
slidge/core/disco.py DELETED
@@ -1,59 +0,0 @@
1
- import logging
2
- from typing import TYPE_CHECKING, Any, Optional
3
-
4
- from slixmpp import JID
5
- from slixmpp.exceptions import XMPPError
6
- from slixmpp.types import OptJid
7
-
8
- from ..util.db import user_store
9
- from ..util.xep_0030.stanza.info import DiscoInfo
10
-
11
- if TYPE_CHECKING:
12
- from ..core.gateway import BaseGateway
13
-
14
-
15
- class Disco:
16
- def __init__(self, xmpp: "BaseGateway"):
17
- self.xmpp = xmpp
18
-
19
- xmpp.plugin["xep_0030"].set_node_handler(
20
- "get_info",
21
- jid=None,
22
- node=None,
23
- handler=self.get_info,
24
- )
25
-
26
- async def get_info(
27
- self, jid: OptJid, node: Optional[str], ifrom: OptJid, data: Any
28
- ):
29
- base = self.xmpp.plugin["xep_0030"].static.get_info(jid, node, ifrom, data)
30
-
31
- if ifrom == self.xmpp.boundjid.bare:
32
- return base
33
-
34
- if jid == self.xmpp.boundjid.bare:
35
- return base
36
-
37
- if ifrom is None:
38
- raise XMPPError("subscription-required")
39
-
40
- user = user_store.get_by_jid(ifrom)
41
- if user is None:
42
- raise XMPPError("registration-required")
43
- session = self.xmpp.get_session_from_user(user) # type:ignore
44
- log.debug("Looking for entity: %s", jid)
45
- try:
46
- entity = await session.contacts.by_jid(jid)
47
- except XMPPError:
48
- entity = await session.bookmarks.by_jid(jid)
49
- if nick := JID(jid).resource:
50
- log.debug("Returning empty disco for participant")
51
- d = DiscoInfo()
52
- d.set_identities([("client", "pc", None, nick)])
53
- return d
54
-
55
- log.debug("entity: %s", entity)
56
- return entity.get_disco_info()
57
-
58
-
59
- log = logging.getLogger(__name__)