slidge 0.1.0b2__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 (155) hide show
  1. slidge/__init__.py +55 -31
  2. slidge/__main__.py +118 -116
  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 +183 -0
  16. slidge/core/config.py +216 -0
  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 +19 -0
  31. slidge/core/mixins/attachment.py +506 -0
  32. slidge/core/mixins/avatar.py +167 -0
  33. slidge/core/mixins/base.py +31 -0
  34. slidge/core/mixins/disco.py +130 -0
  35. slidge/core/mixins/lock.py +31 -0
  36. slidge/core/mixins/message.py +398 -0
  37. slidge/core/mixins/message_maker.py +154 -0
  38. slidge/core/mixins/presence.py +217 -0
  39. slidge/core/mixins/recipient.py +43 -0
  40. slidge/core/pubsub.py +282 -116
  41. slidge/core/session.py +595 -372
  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_0084 → slixfix/link_preview}/__init__.py +3 -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 +14 -2
  54. slidge/slixfix/xep_0077/stanza.py +104 -0
  55. slidge/{util → slixfix}/xep_0100/gateway.py +25 -15
  56. slidge/slixfix/xep_0100/stanza.py +9 -0
  57. slidge/slixfix/xep_0153/__init__.py +10 -0
  58. slidge/slixfix/xep_0153/stanza.py +25 -0
  59. slidge/slixfix/xep_0153/vcard_avatar.py +23 -0
  60. slidge/slixfix/xep_0264/__init__.py +5 -0
  61. slidge/slixfix/xep_0264/stanza.py +36 -0
  62. slidge/slixfix/xep_0264/thumbnail.py +23 -0
  63. slidge/slixfix/xep_0292/__init__.py +5 -0
  64. slidge/slixfix/xep_0292/vcard4.py +100 -0
  65. slidge/slixfix/xep_0313/__init__.py +12 -0
  66. slidge/slixfix/xep_0313/mam.py +262 -0
  67. slidge/slixfix/xep_0313/stanza.py +359 -0
  68. slidge/slixfix/xep_0317/__init__.py +5 -0
  69. slidge/slixfix/xep_0317/hats.py +17 -0
  70. slidge/slixfix/xep_0317/stanza.py +28 -0
  71. slidge/{util → slixfix}/xep_0356_old/privilege.py +9 -7
  72. slidge/slixfix/xep_0424/__init__.py +9 -0
  73. slidge/slixfix/xep_0424/retraction.py +77 -0
  74. slidge/slixfix/xep_0424/stanza.py +28 -0
  75. slidge/slixfix/xep_0490/__init__.py +8 -0
  76. slidge/slixfix/xep_0490/mds.py +47 -0
  77. slidge/slixfix/xep_0490/stanza.py +17 -0
  78. slidge/util/__init__.py +4 -6
  79. slidge/util/archive_msg.py +61 -0
  80. slidge/util/conf.py +206 -0
  81. slidge/util/db.py +57 -76
  82. slidge/util/schema.sql +126 -0
  83. slidge/util/sql.py +508 -0
  84. slidge/util/test.py +215 -25
  85. slidge/util/types.py +177 -4
  86. slidge/util/util.py +225 -59
  87. slidge-0.1.1.dist-info/METADATA +110 -0
  88. slidge-0.1.1.dist-info/RECORD +96 -0
  89. {slidge-0.1.0b2.dist-info → slidge-0.1.1.dist-info}/WHEEL +1 -1
  90. slidge/core/contact.py +0 -891
  91. slidge/core/gateway.py +0 -916
  92. slidge/plugins/discord/__init__.py +0 -90
  93. slidge/plugins/discord/client.py +0 -108
  94. slidge/plugins/discord/session.py +0 -162
  95. slidge/plugins/dummy.py +0 -203
  96. slidge/plugins/facebook.py +0 -493
  97. slidge/plugins/hackernews.py +0 -213
  98. slidge/plugins/mattermost/__init__.py +0 -1
  99. slidge/plugins/mattermost/api.py +0 -280
  100. slidge/plugins/mattermost/gateway.py +0 -365
  101. slidge/plugins/mattermost/websocket.py +0 -252
  102. slidge/plugins/signal/__init__.py +0 -3
  103. slidge/plugins/signal/contact.py +0 -106
  104. slidge/plugins/signal/gateway.py +0 -282
  105. slidge/plugins/signal/session.py +0 -448
  106. slidge/plugins/signal/txt.py +0 -53
  107. slidge/plugins/skype.py +0 -325
  108. slidge/plugins/steam.py +0 -310
  109. slidge/plugins/telegram/__init__.py +0 -5
  110. slidge/plugins/telegram/client.py +0 -228
  111. slidge/plugins/telegram/config.py +0 -12
  112. slidge/plugins/telegram/contact.py +0 -176
  113. slidge/plugins/telegram/gateway.py +0 -150
  114. slidge/plugins/telegram/session.py +0 -256
  115. slidge/util/xep_0030/__init__.py +0 -13
  116. slidge/util/xep_0030/disco.py +0 -811
  117. slidge/util/xep_0030/stanza/__init__.py +0 -7
  118. slidge/util/xep_0030/stanza/info.py +0 -270
  119. slidge/util/xep_0030/stanza/items.py +0 -147
  120. slidge/util/xep_0030/static.py +0 -467
  121. slidge/util/xep_0055/__init__.py +0 -5
  122. slidge/util/xep_0055/search.py +0 -75
  123. slidge/util/xep_0055/stanza.py +0 -10
  124. slidge/util/xep_0077/stanza.py +0 -71
  125. slidge/util/xep_0084/avatar.py +0 -137
  126. slidge/util/xep_0084/stanza.py +0 -104
  127. slidge/util/xep_0115/__init__.py +0 -12
  128. slidge/util/xep_0115/caps.py +0 -379
  129. slidge/util/xep_0115/stanza.py +0 -16
  130. slidge/util/xep_0115/static.py +0 -137
  131. slidge/util/xep_0292/__init__.py +0 -1
  132. slidge/util/xep_0292/stanza.py +0 -167
  133. slidge/util/xep_0292/vcard4.py +0 -75
  134. slidge/util/xep_0333/__init__.py +0 -10
  135. slidge/util/xep_0333/markers.py +0 -96
  136. slidge/util/xep_0333/stanza.py +0 -34
  137. slidge/util/xep_0356/__init__.py +0 -7
  138. slidge/util/xep_0356/permissions.py +0 -35
  139. slidge/util/xep_0356/privilege.py +0 -160
  140. slidge/util/xep_0356/stanza.py +0 -44
  141. slidge/util/xep_0363/__init__.py +0 -16
  142. slidge/util/xep_0363/http_upload.py +0 -215
  143. slidge/util/xep_0363/stanza.py +0 -46
  144. slidge/util/xep_0461/__init__.py +0 -6
  145. slidge/util/xep_0461/reply.py +0 -48
  146. slidge/util/xep_0461/stanza.py +0 -47
  147. slidge-0.1.0b2.dist-info/METADATA +0 -171
  148. slidge-0.1.0b2.dist-info/RECORD +0 -81
  149. /slidge/{plugins/__init__.py → py.typed} +0 -0
  150. /slidge/{util → slixfix}/xep_0077/__init__.py +0 -0
  151. /slidge/{util → slixfix}/xep_0100/__init__.py +0 -0
  152. /slidge/{util → slixfix}/xep_0356_old/__init__.py +0 -0
  153. /slidge/{util → slixfix}/xep_0356_old/stanza.py +0 -0
  154. {slidge-0.1.0b2.dist-info → slidge-0.1.1.dist-info}/LICENSE +0 -0
  155. {slidge-0.1.0b2.dist-info → slidge-0.1.1.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,359 @@
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
@@ -0,0 +1,5 @@
1
+ from slixmpp.plugins.base import register_plugin
2
+
3
+ from .hats import XEP_0317
4
+
5
+ register_plugin(XEP_0317)
@@ -0,0 +1,17 @@
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()
@@ -0,0 +1,28 @@
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)
@@ -4,16 +4,15 @@ from collections import defaultdict
4
4
 
5
5
  from slixmpp import JID, Iq, Message
6
6
  from slixmpp.plugins.base import BasePlugin
7
- from slixmpp.types import JidStr
8
- from slixmpp.xmlstream import StanzaBase
9
- from slixmpp.xmlstream.handler import Callback
10
- from slixmpp.xmlstream.matcher import StanzaPath
11
-
12
- from slidge.util.xep_0356.permissions import (
7
+ from slixmpp.plugins.xep_0356.permissions import (
13
8
  MessagePermission,
14
9
  Permissions,
15
10
  RosterAccess,
16
11
  )
12
+ from slixmpp.types import JidStr
13
+ from slixmpp.xmlstream import StanzaBase
14
+ from slixmpp.xmlstream.handler import Callback
15
+ from slixmpp.xmlstream.matcher import StanzaPath
17
16
 
18
17
  from . import stanza
19
18
 
@@ -72,7 +71,10 @@ class XEP_0356_OLD(BasePlugin):
72
71
  self.xmpp.event("privileges_advertised_old")
73
72
 
74
73
  def send_privileged_message(self, msg: Message):
75
- if self.granted_privileges[msg.get_from().domain].message != MessagePermission.OUTGOING:
74
+ if (
75
+ self.granted_privileges[msg.get_from().domain].message
76
+ != MessagePermission.OUTGOING
77
+ ):
76
78
  raise PermissionError(
77
79
  "The server hasn't authorized us to send messages on behalf of other users"
78
80
  )
@@ -0,0 +1,9 @@
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)
@@ -0,0 +1,77 @@
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()
@@ -0,0 +1,28 @@
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)
@@ -0,0 +1,8 @@
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"]
@@ -0,0 +1,47 @@
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")
@@ -0,0 +1,17 @@
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)
slidge/util/__init__.py CHANGED
@@ -1,17 +1,15 @@
1
1
  from .util import (
2
2
  ABCSubclassableOnceAtMost,
3
- BiDict,
4
- FormField,
5
- SearchResult,
6
3
  SubclassableOnce,
7
4
  is_valid_phone_number,
5
+ replace_mentions,
6
+ strip_illegal_chars,
8
7
  )
9
8
 
10
9
  __all__ = [
11
- "BiDict",
12
- "SearchResult",
13
- "FormField",
14
10
  "SubclassableOnce",
15
11
  "ABCSubclassableOnceAtMost",
16
12
  "is_valid_phone_number",
13
+ "replace_mentions",
14
+ "strip_illegal_chars",
17
15
  ]