slidge 0.2.2__py3-none-any.whl → 0.2.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. slidge/__version__.py +1 -1
  2. slidge/command/register.py +1 -3
  3. slidge/contact/contact.py +1 -1
  4. slidge/core/dispatcher/message/message.py +4 -1
  5. slidge/core/dispatcher/muc/admin.py +3 -4
  6. slidge/core/dispatcher/presence.py +3 -3
  7. slidge/core/gateway.py +2 -0
  8. slidge/core/mixins/attachment.py +1 -1
  9. slidge/core/mixins/avatar.py +6 -0
  10. slidge/core/mixins/message.py +13 -2
  11. slidge/core/mixins/recipient.py +2 -2
  12. slidge/db/store.py +9 -3
  13. slidge/group/archive.py +3 -3
  14. slidge/group/participant.py +11 -5
  15. slidge/group/room.py +21 -1
  16. slidge/main.py +1 -1
  17. slidge/slixfix/__init__.py +69 -13
  18. slidge/slixfix/xep_0153/__init__.py +0 -1
  19. slidge/slixfix/xep_0153/vcard_avatar.py +1 -10
  20. slidge/slixfix/xep_0492/__init__.py +8 -0
  21. slidge/slixfix/xep_0492/notify.py +16 -0
  22. slidge/slixfix/xep_0492/stanza.py +102 -0
  23. slidge/util/test.py +9 -2
  24. slidge-0.2.4.dist-info/METADATA +793 -0
  25. {slidge-0.2.2.dist-info → slidge-0.2.4.dist-info}/RECORD +41 -54
  26. {slidge-0.2.2.dist-info → slidge-0.2.4.dist-info}/WHEEL +2 -1
  27. slidge-0.2.4.dist-info/entry_points.txt +2 -0
  28. slidge-0.2.4.dist-info/top_level.txt +1 -0
  29. slidge/slixfix/xep_0153/stanza.py +0 -25
  30. slidge/slixfix/xep_0264/__init__.py +0 -5
  31. slidge/slixfix/xep_0264/stanza.py +0 -36
  32. slidge/slixfix/xep_0264/thumbnail.py +0 -23
  33. slidge/slixfix/xep_0313/__init__.py +0 -12
  34. slidge/slixfix/xep_0313/mam.py +0 -262
  35. slidge/slixfix/xep_0313/stanza.py +0 -359
  36. slidge/slixfix/xep_0317/__init__.py +0 -5
  37. slidge/slixfix/xep_0317/hats.py +0 -17
  38. slidge/slixfix/xep_0317/stanza.py +0 -28
  39. slidge/slixfix/xep_0424/__init__.py +0 -9
  40. slidge/slixfix/xep_0424/retraction.py +0 -77
  41. slidge/slixfix/xep_0424/stanza.py +0 -28
  42. slidge/slixfix/xep_0490/__init__.py +0 -8
  43. slidge/slixfix/xep_0490/mds.py +0 -47
  44. slidge/slixfix/xep_0490/stanza.py +0 -17
  45. slidge-0.2.2.dist-info/LICENSE +0 -661
  46. slidge-0.2.2.dist-info/METADATA +0 -116
  47. slidge-0.2.2.dist-info/entry_points.txt +0 -3
@@ -1,359 +0,0 @@
1
- # Slixmpp: The Slick XMPP Library
2
- # Copyright (C) 2012 Nathanael C. Fritz, Lance J.T. Stout
3
- # This file is part of Slixmpp.
4
- # See the file LICENSE for copying permissio
5
- from datetime import datetime
6
- from typing import Any, Iterable, List, Optional, Set, Union
7
-
8
- from slixmpp.jid import JID
9
- from slixmpp.plugins import xep_0082
10
- from slixmpp.stanza import Message
11
- from slixmpp.xmlstream import ET, ElementBase
12
-
13
-
14
- class MAM(ElementBase):
15
- """A MAM Query element.
16
-
17
- .. code-block:: xml
18
-
19
- <iq type='set' id='juliet1'>
20
- <query xmlns='urn:xmpp:mam:2'>
21
- <x xmlns='jabber:x:data' type='submit'>
22
- <field var='FORM_TYPE' type='hidden'>
23
- <value>urn:xmpp:mam:2</value>
24
- </field>
25
- <field var='with'>
26
- <value>juliet@capulet.lit</value>
27
- </field>
28
- </x>
29
- </query>
30
- </iq>
31
-
32
- """
33
-
34
- name = "query"
35
- namespace = "urn:xmpp:mam:2"
36
- plugin_attrib = "mam"
37
- #: Available interfaces:
38
- #:
39
- #: - ``queryid``: The MAM query id
40
- #: - ``start`` and ``end``: Temporal boundaries of the query
41
- #: - ``with``: JID of the other entity the conversation is with
42
- #: - ``after_id``: Fetch stanzas after this specific ID
43
- #: - ``before_id``: Fetch stanzas before this specific ID
44
- #: - ``ids``: Fetch the stanzas matching those IDs
45
- #: - ``results``: pseudo-interface used to accumulate MAM results during
46
- #: fetch, not relevant for the stanza itself.
47
- interfaces = {
48
- "queryid",
49
- "start",
50
- "end",
51
- "with",
52
- "results",
53
- "before_id",
54
- "after_id",
55
- "ids",
56
- "flip_page",
57
- }
58
- sub_interfaces = {
59
- "start",
60
- "end",
61
- "with",
62
- "before_id",
63
- "after_id",
64
- "ids",
65
- "flip_page",
66
- }
67
-
68
- def setup(self, xml=None):
69
- ElementBase.setup(self, xml)
70
- self._results: List[Message] = []
71
-
72
- def _setup_form(self):
73
- found = self.xml.find(
74
- "{jabber:x:data}x/"
75
- '{jabber:x:data}field[@var="FORM_TYPE"]/'
76
- "{jabber:x:data}value[.='urn:xmpp:mam:2']"
77
- )
78
- if found is None:
79
- self["form"]["type"] = "submit"
80
- self["form"].add_field(
81
- var="FORM_TYPE", ftype="hidden", value="urn:xmpp:mam:2"
82
- )
83
-
84
- def get_fields(self):
85
- form = self.get_plugin("form", check=True)
86
- if not form:
87
- return {}
88
- return form.get_fields()
89
-
90
- def get_start(self) -> Optional[datetime]:
91
- fields = self.get_fields()
92
- field = fields.get("start")
93
- if field and field["value"]:
94
- return xep_0082.parse(field["value"])
95
- return None
96
-
97
- def set_start(self, value: Union[str, datetime]):
98
- self._setup_form()
99
- if isinstance(value, datetime):
100
- value = xep_0082.format_datetime(value)
101
- self.set_custom_field("start", value)
102
-
103
- def get_end(self) -> Optional[datetime]:
104
- fields = self.get_fields()
105
- field = fields.get("end")
106
- if field and field["value"]:
107
- return xep_0082.parse(field["value"])
108
- return None
109
-
110
- def set_end(self, value: Union[str, datetime]):
111
- if isinstance(value, datetime):
112
- value = xep_0082.format_datetime(value)
113
- self.set_custom_field("end", value)
114
-
115
- def get_with(self) -> Optional[JID]:
116
- fields = self.get_fields()
117
- field = fields.get("with")
118
- if field:
119
- return JID(field["value"])
120
- return None
121
-
122
- def set_with(self, value: JID):
123
- self.set_custom_field("with", value)
124
-
125
- def set_custom_field(self, fieldname: str, value: Any):
126
- self._setup_form()
127
- fields = self.get_fields()
128
- field = fields.get(fieldname)
129
- if field:
130
- field["value"] = str(value)
131
- else:
132
- field = self["form"].add_field(var=fieldname)
133
- field["value"] = str(value)
134
-
135
- def get_custom_field(self, fieldname: str) -> Optional[str]:
136
- fields = self.get_fields()
137
- field = fields.get(fieldname)
138
- if field:
139
- return field["value"]
140
- return None
141
-
142
- def set_before_id(self, value: str):
143
- self.set_custom_field("before-id", value)
144
-
145
- def get_before_id(self):
146
- self.get_custom_field("before-id")
147
-
148
- def set_after_id(self, value: str):
149
- self.set_custom_field("after-id", value)
150
-
151
- def get_after_id(self):
152
- self.get_custom_field("after-id")
153
-
154
- def set_ids(self, value: List[str]):
155
- self._setup_form()
156
- fields = self.get_fields()
157
- field = fields.get("ids")
158
- if field:
159
- field["ids"] = value
160
- else:
161
- field = self["form"].add_field(var="ids")
162
- field["value"] = value
163
-
164
- def get_ids(self):
165
- self.get_custom_field("id")
166
-
167
- # The results interface is meant only as an easy
168
- # way to access the set of collected message responses
169
- # from the query.
170
-
171
- def get_results(self) -> List[Message]:
172
- return self._results
173
-
174
- def set_results(self, values: List[Message]):
175
- self._results = values
176
-
177
- def del_results(self):
178
- self._results = []
179
-
180
- def get_flip_page(self):
181
- return self.xml.find(f"{{{self.namespace}}}flip-page") is not None
182
-
183
-
184
- class Fin(ElementBase):
185
- """A MAM fin element (end of query).
186
-
187
- .. code-block:: xml
188
-
189
- <iq type='result' id='juliet1'>
190
- <fin xmlns='urn:xmpp:mam:2'>
191
- <set xmlns='http://jabber.org/protocol/rsm'>
192
- <first index='0'>28482-98726-73623</first>
193
- <last>09af3-cc343-b409f</last>
194
- </set>
195
- </fin>
196
- </iq>
197
-
198
- """
199
-
200
- name = "fin"
201
- namespace = "urn:xmpp:mam:2"
202
- plugin_attrib = "mam_fin"
203
- interfaces = {"results", "stable", "complete"}
204
-
205
- def setup(self, xml=None):
206
- ElementBase.setup(self, xml)
207
- self._results: List[Message] = []
208
-
209
- # The results interface is meant only as an easy
210
- # way to access the set of collected message responses
211
- # from the query.
212
-
213
- def get_results(self) -> List[Message]:
214
- return self._results
215
-
216
- def set_results(self, values: List[Message]):
217
- self._results = values
218
-
219
- def del_results(self):
220
- self._results = []
221
-
222
-
223
- class Result(ElementBase):
224
- """A MAM result payload.
225
-
226
- .. code-block:: xml
227
-
228
- <message id='aeb213' to='juliet@capulet.lit/chamber'>
229
- <result xmlns='urn:xmpp:mam:2' queryid='f27' id='28482-98726-73623'>
230
- <forwarded xmlns='urn:xmpp:forward:0'>
231
- <delay xmlns='urn:xmpp:delay' stamp='2010-07-10T23:08:25Z'/>
232
- <message xmlns='jabber:client' from="witch@shakespeare.lit"
233
- to="macbeth@shakespeare.lit">
234
- <body>Hail to thee</body>
235
- </message>
236
- </forwarded>
237
- </result>
238
- </message>
239
- """
240
-
241
- name = "result"
242
- namespace = "urn:xmpp:mam:2"
243
- plugin_attrib = "mam_result"
244
- #: Available interfaces:
245
- #:
246
- #: - ``queryid``: MAM queryid
247
- #: - ``id``: ID of the result
248
- interfaces = {"queryid", "id"}
249
-
250
-
251
- class Metadata(ElementBase):
252
- """Element containing archive metadata
253
-
254
- .. code-block:: xml
255
-
256
- <iq type='result' id='jui8921rr9'>
257
- <metadata xmlns='urn:xmpp:mam:2'>
258
- <start id='YWxwaGEg' timestamp='2008-08-22T21:09:04Z' />
259
- <end id='b21lZ2Eg' timestamp='2020-04-20T14:34:21Z' />
260
- </metadata>
261
- </iq>
262
-
263
- """
264
-
265
- name = "metadata"
266
- namespace = "urn:xmpp:mam:2"
267
- plugin_attrib = "mam_metadata"
268
-
269
-
270
- class Start(ElementBase):
271
- """Metadata about the start of an archive.
272
-
273
- .. code-block:: xml
274
-
275
- <iq type='result' id='jui8921rr9'>
276
- <metadata xmlns='urn:xmpp:mam:2'>
277
- <start id='YWxwaGEg' timestamp='2008-08-22T21:09:04Z' />
278
- <end id='b21lZ2Eg' timestamp='2020-04-20T14:34:21Z' />
279
- </metadata>
280
- </iq>
281
-
282
- """
283
-
284
- name = "start"
285
- namespace = "urn:xmpp:mam:2"
286
- plugin_attrib = name
287
- #: Available interfaces:
288
- #:
289
- #: - ``id``: ID of the first message of the archive
290
- #: - ``timestamp`` (``datetime``): timestamp of the first message of the
291
- #: archive
292
- interfaces = {"id", "timestamp"}
293
-
294
- def get_timestamp(self) -> Optional[datetime]:
295
- """Get the timestamp.
296
-
297
- :returns: The timestamp.
298
- """
299
- stamp = self.xml.attrib.get("timestamp", None)
300
- if stamp is not None:
301
- return xep_0082.parse(stamp)
302
- return stamp
303
-
304
- def set_timestamp(self, value: Union[datetime, str]):
305
- """Set the timestamp.
306
-
307
- :param value: Value of the timestamp (either a datetime or a
308
- XEP-0082 timestamp string.
309
- """
310
- if isinstance(value, str):
311
- value = xep_0082.parse(value)
312
- value = xep_0082.format_datetime(value)
313
- self.xml.attrib["timestamp"] = value
314
-
315
-
316
- class End(ElementBase):
317
- """Metadata about the end of an archive.
318
-
319
- .. code-block:: xml
320
-
321
- <iq type='result' id='jui8921rr9'>
322
- <metadata xmlns='urn:xmpp:mam:2'>
323
- <start id='YWxwaGEg' timestamp='2008-08-22T21:09:04Z' />
324
- <end id='b21lZ2Eg' timestamp='2020-04-20T14:34:21Z' />
325
- </metadata>
326
- </iq>
327
-
328
- """
329
-
330
- name = "end"
331
- namespace = "urn:xmpp:mam:2"
332
- plugin_attrib = name
333
- #: Available interfaces:
334
- #:
335
- #: - ``id``: ID of the first message of the archive
336
- #: - ``timestamp`` (``datetime``): timestamp of the first message of the
337
- #: archive
338
- interfaces = {"id", "timestamp"}
339
-
340
- def get_timestamp(self) -> Optional[datetime]:
341
- """Get the timestamp.
342
-
343
- :returns: The timestamp.
344
- """
345
- stamp = self.xml.attrib.get("timestamp", None)
346
- if stamp is not None:
347
- return xep_0082.parse(stamp)
348
- return stamp
349
-
350
- def set_timestamp(self, value: Union[datetime, str]):
351
- """Set the timestamp.
352
-
353
- :param value: Value of the timestamp (either a datetime or a
354
- XEP-0082 timestamp string.
355
- """
356
- if isinstance(value, str):
357
- value = xep_0082.parse(value)
358
- value = xep_0082.format_datetime(value)
359
- self.xml.attrib["timestamp"] = value
@@ -1,5 +0,0 @@
1
- from slixmpp.plugins.base import register_plugin
2
-
3
- from .hats import XEP_0317
4
-
5
- register_plugin(XEP_0317)
@@ -1,17 +0,0 @@
1
- from slixmpp.plugins import BasePlugin
2
-
3
- from . import stanza
4
-
5
-
6
- class XEP_0317(BasePlugin):
7
- """
8
- XEP-0317: Hats
9
- """
10
-
11
- name = "xep_0317"
12
- description = "XEP-0317: Hats"
13
- dependencies = {"xep_0045"}
14
- stanza = stanza
15
-
16
- def plugin_init(self):
17
- stanza.register()
@@ -1,28 +0,0 @@
1
- from slixmpp import Presence
2
- from slixmpp.xmlstream import ElementBase, register_stanza_plugin
3
-
4
- NS = "urn:xmpp:hats:0"
5
-
6
-
7
- class Hats(ElementBase):
8
- name = plugin_attrib = "hats"
9
- namespace = NS
10
-
11
- def add_hats(self, data: list[tuple[str, str]]):
12
- for uri, title in data:
13
- hat = Hat()
14
- hat["uri"] = uri
15
- hat["title"] = title
16
- self.append(hat)
17
-
18
-
19
- class Hat(ElementBase):
20
- name = plugin_attrib = "hat"
21
- namespace = NS
22
- interfaces = {"uri", "title"}
23
- plugin_multi_attrib = "hats"
24
-
25
-
26
- def register():
27
- register_stanza_plugin(Hats, Hat, iterable=True)
28
- register_stanza_plugin(Presence, Hats)
@@ -1,9 +0,0 @@
1
- # Slixmpp: The Slick XMPP Library
2
- # Copyright (C) 2020 Mathieu Pasquet <mathieui@mathieui.net>
3
- # This file is part of Slixmpp.
4
- # See the file LICENSE for copying permission.
5
- from slixmpp.plugins.base import register_plugin
6
-
7
- from .retraction import XEP_0424
8
-
9
- register_plugin(XEP_0424)
@@ -1,77 +0,0 @@
1
- # Slixmpp: The Slick XMPP Library
2
- # Copyright (C) 2020 Mathieu Pasquet <mathieui@mathieui.net>
3
- # This file is part of Slixmpp.
4
- # See the file LICENSE for copying permission.
5
- from typing import Optional
6
-
7
- from slixmpp import JID, Message
8
- from slixmpp.exceptions import IqError, IqTimeout
9
- from slixmpp.plugins import BasePlugin
10
- from slixmpp.xmlstream.handler import Callback
11
- from slixmpp.xmlstream.matcher import StanzaPath
12
-
13
- from . import stanza
14
-
15
- DEFAULT_FALLBACK = (
16
- "This person attempted to retract a previous message, but your client "
17
- "does not support it."
18
- )
19
-
20
-
21
- class XEP_0424(BasePlugin):
22
- """XEP-0424: Message Retraction"""
23
-
24
- name = "xep_0424"
25
- description = "XEP-0424: Message Retraction (fix Slidge)"
26
- dependencies = {"xep_0422", "xep_0030", "xep_0359", "xep_0428", "xep_0334"}
27
- stanza = stanza
28
- namespace = stanza.NS
29
-
30
- def plugin_init(self) -> None:
31
- stanza.register_plugins()
32
- self.xmpp.register_handler(
33
- Callback(
34
- "Message Retracted",
35
- StanzaPath("message/retract"),
36
- self._handle_retract_message,
37
- )
38
- )
39
-
40
- def session_bind(self, jid):
41
- self.xmpp.plugin["xep_0030"].add_feature(feature=stanza.NS)
42
-
43
- def plugin_end(self):
44
- self.xmpp.plugin["xep_0030"].del_feature(feature=stanza.NS)
45
-
46
- def _handle_retract_message(self, message: Message):
47
- self.xmpp.event("message_retract", message)
48
-
49
- def send_retraction(
50
- self,
51
- mto: JID,
52
- id: str,
53
- mtype: str = "chat",
54
- include_fallback: bool = True,
55
- fallback_text: Optional[str] = None,
56
- *,
57
- mfrom: Optional[JID] = None
58
- ):
59
- """
60
- Send a message retraction
61
-
62
- :param JID mto: The JID to retract the message from
63
- :param str id: Message ID to retract
64
- :param str mtype: Message type
65
- :param bool include_fallback: Whether to include a fallback body
66
- :param Optional[str] fallback_text: The content of the fallback
67
- body. None will set the default value.
68
- """
69
- if fallback_text is None:
70
- fallback_text = DEFAULT_FALLBACK
71
- msg = self.xmpp.make_message(mto=mto, mtype=mtype, mfrom=mfrom)
72
- if include_fallback:
73
- msg["body"] = fallback_text
74
- msg.enable("fallback")
75
- msg["retract"]["id"] = id
76
- msg.enable("store")
77
- msg.send()
@@ -1,28 +0,0 @@
1
- # Slixmpp: The Slick XMPP Library
2
- # Copyright (C) 2020 Mathieu Pasquet <mathieui@mathieui.net>
3
- # This file is part of Slixmpp.
4
- # See the file LICENSE for copying permissio
5
- from slixmpp.plugins.xep_0359 import OriginID
6
- from slixmpp.stanza import Message
7
- from slixmpp.xmlstream import ElementBase, register_stanza_plugin
8
-
9
- NS = "urn:xmpp:message-retract:1"
10
-
11
-
12
- class Retract(ElementBase):
13
- namespace = NS
14
- name = "retract"
15
- plugin_attrib = "retract"
16
-
17
-
18
- class Retracted(ElementBase):
19
- namespace = NS
20
- name = "retracted"
21
- plugin_attrib = "retracted"
22
- interfaces = {"stamp"}
23
-
24
-
25
- def register_plugins():
26
- register_stanza_plugin(Message, Retract)
27
- register_stanza_plugin(Message, Retracted)
28
- register_stanza_plugin(Retracted, OriginID)
@@ -1,8 +0,0 @@
1
- from slixmpp.plugins.base import register_plugin
2
-
3
- from . import stanza
4
- from .mds import XEP_0490
5
-
6
- register_plugin(XEP_0490)
7
-
8
- __all__ = ["stanza", "XEP_0490"]
@@ -1,47 +0,0 @@
1
- from slixmpp import Iq
2
- from slixmpp.plugins import BasePlugin
3
- from slixmpp.plugins.xep_0004 import Form
4
- from slixmpp.types import JidStr
5
-
6
- from . import stanza
7
-
8
-
9
- class XEP_0490(BasePlugin):
10
- """
11
- XEP-0490: Message Displayed Synchronization
12
- """
13
-
14
- name = "xep_0490"
15
- description = "XEP-0490: Message Displayed Synchronization"
16
- dependencies = {"xep_0060", "xep_0163", "xep_0359"}
17
- stanza = stanza
18
-
19
- def plugin_init(self):
20
- stanza.register_plugin()
21
- self.xmpp.plugin["xep_0163"].register_pep(
22
- "message_displayed_synchronization",
23
- stanza.Displayed,
24
- )
25
-
26
- def flag_chat(self, chat: JidStr, stanza_id: str, **kwargs) -> Iq:
27
- displayed = stanza.Displayed()
28
- displayed["stanza_id"]["id"] = stanza_id
29
- return self.xmpp.plugin["xep_0163"].publish(
30
- displayed, node=stanza.NS, options=PUBLISH_OPTIONS, id=str(chat), **kwargs
31
- )
32
-
33
- def catch_up(self, **kwargs):
34
- return self.xmpp.plugin["xep_0060"].get_items(
35
- self.xmpp.boundjid.bare, stanza.NS, **kwargs
36
- )
37
-
38
-
39
- PUBLISH_OPTIONS = Form()
40
- PUBLISH_OPTIONS["type"] = "submit"
41
- PUBLISH_OPTIONS.add_field(
42
- "FORM_TYPE", "hidden", value="http://jabber.org/protocol/pubsub#publish-options"
43
- )
44
- PUBLISH_OPTIONS.add_field("pubsub#persist_items", value="true")
45
- PUBLISH_OPTIONS.add_field("pubsub#max_items", value="max")
46
- PUBLISH_OPTIONS.add_field("pubsub#send_last_published_item", value="never")
47
- PUBLISH_OPTIONS.add_field("pubsub#access_model", value="whitelist")
@@ -1,17 +0,0 @@
1
- from slixmpp import register_stanza_plugin
2
- from slixmpp.plugins.xep_0060.stanza import Item
3
- from slixmpp.plugins.xep_0359.stanza import StanzaID
4
- from slixmpp.xmlstream import ElementBase
5
-
6
- NS = "urn:xmpp:mds:displayed:0"
7
-
8
-
9
- class Displayed(ElementBase):
10
- namespace = NS
11
- name = "displayed"
12
- plugin_attrib = "displayed"
13
-
14
-
15
- def register_plugin():
16
- register_stanza_plugin(Displayed, StanzaID)
17
- register_stanza_plugin(Item, Displayed)