slidge 0.1.0rc1__py3-none-any.whl → 0.1.2__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 +795 -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.2.dist-info/METADATA +111 -0
  87. slidge-0.1.2.dist-info/RECORD +96 -0
  88. {slidge-0.1.0rc1.dist-info → slidge-0.1.2.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.2.dist-info}/LICENSE +0 -0
  164. {slidge-0.1.0rc1.dist-info → slidge-0.1.2.dist-info}/entry_points.txt +0 -0
@@ -1,811 +0,0 @@
1
-
2
- # Slixmpp: The Slick XMPP Library
3
- # Copyright (C) 2010 Nathanael C. Fritz, Lance J.T. Stout
4
- # This file is part of Slixmpp.
5
- # See the file LICENSE for copying permission.
6
- import asyncio
7
- import logging
8
- from asyncio import Future
9
- from typing import Callable, List, Optional, Union
10
-
11
- from slixmpp import JID
12
- from slixmpp.plugins import BasePlugin
13
- from slixmpp.plugins.xep_0030 import DiscoInfo, DiscoItems, StaticDisco, stanza
14
- from slixmpp.stanza import Iq
15
- from slixmpp.types import OptJid
16
- from slixmpp.xmlstream import register_stanza_plugin
17
- from slixmpp.xmlstream.handler import CoroutineCallback
18
- from slixmpp.xmlstream.matcher import StanzaPath
19
-
20
- log = logging.getLogger(__name__)
21
-
22
-
23
- class XEP_0030(BasePlugin):
24
-
25
- """
26
- XEP-0030: Service Discovery
27
-
28
- Service discovery in XMPP allows entities to discover information about
29
- other agents in the network, such as the feature sets supported by a
30
- client, or signposts to other, related entities.
31
-
32
- Also see <http://www.xmpp.org/extensions/xep-0030.html>.
33
-
34
- The XEP-0030 plugin works using a hierarchy of dynamic
35
- node handlers, ranging from global handlers to specific
36
- JID+node handlers. The default set of handlers operate
37
- in a static manner, storing disco information in memory.
38
- However, custom handlers may use any available backend
39
- storage mechanism desired, such as SQLite or Redis.
40
-
41
- Node handler hierarchy:
42
-
43
- ====== ======= ============================
44
- JID Node Level
45
- ====== ======= ============================
46
- None None Global
47
- Given None All nodes for the JID
48
- None Given Node on self.xmpp.boundjid
49
- Given Given A single node
50
- ====== ======= ============================
51
-
52
- Stream Handlers:
53
-
54
- ::
55
-
56
- Disco Info -- Any Iq stanze that includes a query with the
57
- namespace http://jabber.org/protocol/disco#info.
58
- Disco Items -- Any Iq stanze that includes a query with the
59
- namespace http://jabber.org/protocol/disco#items.
60
-
61
- Events:
62
-
63
- - :term:`disco_info` -- Received a disco#info Iq query result.
64
- - :term:`disco_items` -- Received a disco#items Iq query result.
65
-
66
- Attributes:
67
-
68
- :var static: Object containing the default set of
69
- static node handlers.
70
- """
71
-
72
- name = 'xep_0030'
73
- description = 'XEP-0030: Service Discovery (Slidge)'
74
- dependencies = set()
75
- stanza = stanza
76
- default_config = {
77
- 'use_cache': True,
78
- 'wrap_results': False
79
- }
80
- static: StaticDisco
81
-
82
- def plugin_init(self):
83
- """
84
- Start the XEP-0030 plugin.
85
- """
86
- self.xmpp.register_handler(CoroutineCallback(
87
- 'Disco Info',
88
- StanzaPath('iq/disco_info'),
89
- self._handle_disco_info
90
- ))
91
-
92
- self.xmpp.register_handler(CoroutineCallback(
93
- 'Disco Items',
94
- StanzaPath('iq/disco_items'),
95
- self._handle_disco_items
96
- ))
97
-
98
- register_stanza_plugin(Iq, DiscoInfo)
99
- register_stanza_plugin(Iq, DiscoItems)
100
-
101
- self.static = StaticDisco(self.xmpp, self)
102
-
103
- self._disco_ops = [
104
- 'get_info', 'set_info', 'set_identities', 'set_features',
105
- 'get_items', 'set_items', 'del_items', 'add_identity',
106
- 'del_identity', 'add_feature', 'del_feature', 'add_item',
107
- 'del_item', 'del_identities', 'del_features', 'cache_info',
108
- 'get_cached_info', 'supports', 'has_identity']
109
-
110
- for op in self._disco_ops:
111
- self.api.register(getattr(self.static, op), op, default=True)
112
-
113
- self.domain_infos = {}
114
-
115
- def session_bind(self, jid):
116
- self.add_feature('http://jabber.org/protocol/disco#info')
117
-
118
- def plugin_end(self):
119
- self.del_feature('http://jabber.org/protocol/disco#info')
120
-
121
- def _add_disco_op(self, op, default_handler):
122
- self.api.register(default_handler, op)
123
- self.api.register_default(default_handler, op)
124
-
125
- def set_node_handler(self, htype: str, jid: OptJid = None,
126
- node: Optional[str] = None,
127
- handler: Optional[Callable] = None):
128
- """
129
- Add a node handler for the given hierarchy level and
130
- handler type.
131
-
132
- Node handlers are ordered in a hierarchy where the
133
- most specific handler is executed. Thus, a fallback,
134
- global handler can be used for the majority of cases
135
- with a few node specific handler that override the
136
- global behavior.
137
-
138
- Node handler hierarchy:
139
-
140
- ====== ======= ============================
141
- JID Node Level
142
- ====== ======= ============================
143
- None None Global
144
- Given None All nodes for the JID
145
- None Given Node on self.xmpp.boundjid
146
- Given Given A single node
147
- ====== ======= ============================
148
-
149
- Handler types:
150
-
151
- ::
152
-
153
- get_info
154
- get_items
155
- set_identities
156
- set_features
157
- set_items
158
- del_items
159
- del_identities
160
- del_identity
161
- del_feature
162
- del_features
163
- del_item
164
- add_identity
165
- add_feature
166
- add_item
167
-
168
- :param htype: The operation provided by the handler.
169
- :param jid: The JID the handler applies to. May be narrowed
170
- further if a node is given.
171
- :param node: The particular node the handler is for. If no JID
172
- is given, then the self.xmpp.boundjid.full is
173
- assumed.
174
- :param handler: The handler function to use.
175
- """
176
- self.api.register(handler, htype, jid, node)
177
-
178
- def del_node_handler(self, htype: str, jid: OptJid, node: Optional[str]):
179
- """
180
- Remove a handler type for a JID and node combination.
181
-
182
- The next handler in the hierarchy will be used if one
183
- exists. If removing the global handler, make sure that
184
- other handlers exist to process existing nodes.
185
-
186
- Node handler hierarchy:
187
-
188
- ====== ======= ============================
189
- JID Node Level
190
- ====== ======= ============================
191
- None None Global
192
- Given None All nodes for the JID
193
- None Given Node on self.xmpp.boundjid
194
- Given Given A single node
195
- ====== ======= ============================
196
-
197
- :param htype: The type of handler to remove.
198
- :param jid: The JID from which to remove the handler.
199
- :param node: The node from which to remove the handler.
200
- """
201
- self.api.unregister(htype, jid, node)
202
-
203
- def restore_defaults(self, jid: OptJid = None, node: Optional[str] = None,
204
- handlers: Optional[List[Callable]] = None):
205
- """
206
- Change all or some of a node's handlers to the default
207
- handlers. Useful for manually overriding the contents
208
- of a node that would otherwise be handled by a JID level
209
- or global level dynamic handler.
210
-
211
- The default is to use the built-in static handlers, but that
212
- may be changed by modifying self.default_handlers.
213
-
214
- :param jid: The JID owning the node to modify.
215
- :param node: The node to change to using static handlers.
216
- :param handlers: Optional list of handlers to change to the
217
- default version. If provided, only these
218
- handlers will be changed. Otherwise, all
219
- handlers will use the default version.
220
- """
221
- if handlers is None:
222
- handlers = self._disco_ops
223
- for op in handlers:
224
- self.api.restore_default(op, jid, node)
225
-
226
- def supports(self, jid: OptJid = None, node: Optional[str] = None,
227
- feature: Optional[str] = None, local: bool = False,
228
- cached: bool = True, ifrom: OptJid = None) -> Future:
229
- """
230
- Check if a JID supports a given feature.
231
-
232
- .. versionchanged:: 1.8.0
233
- This function now returns a Future.
234
-
235
- :param jid: Request info from this JID.
236
- :param node: The particular node to query.
237
- :param feature: The name of the feature to check.
238
- :param local: If true, then the query is for a JID/node
239
- combination handled by this Slixmpp instance and
240
- no stanzas need to be sent.
241
- Otherwise, a disco stanza must be sent to the
242
- remove JID to retrieve the info.
243
- :param cached: If true, then look for the disco info data from
244
- the local cache system. If no results are found,
245
- send the query as usual. The self.use_cache
246
- setting must be set to true for this option to
247
- be useful. If set to false, then the cache will
248
- be skipped, even if a result has already been
249
- cached. Defaults to false.
250
-
251
- :returns True: The feature is supported
252
- :returns False: The feature is not listed as supported
253
- :returns None: Nothing could be found due to a timeout
254
- """
255
- data = {'feature': feature,
256
- 'local': local,
257
- 'cached': cached}
258
- return self.api['supports'](jid, node, ifrom, data)
259
-
260
- def has_identity(self, jid: OptJid = None, node: Optional[str] = None,
261
- category: Optional[str] = None,
262
- itype: Optional[str] = None, lang: Optional[str] = None,
263
- local: bool = False, cached: bool = True,
264
- ifrom: OptJid = None) -> Future:
265
- """
266
- Check if a JID provides a given identity.
267
-
268
- .. versionchanged:: 1.8.0
269
- This function now returns a Future.
270
-
271
-
272
- :param jid: Request info from this JID.
273
- :param node: The particular node to query.
274
- :param category: The category of the identity to check.
275
- :param itype: The type of the identity to check.
276
- :param lang: The language of the identity to check.
277
- :param local: If true, then the query is for a JID/node
278
- combination handled by this Slixmpp instance and
279
- no stanzas need to be sent.
280
- Otherwise, a disco stanza must be sent to the
281
- remove JID to retrieve the info.
282
- :param cached: If true, then look for the disco info data from
283
- the local cache system. If no results are found,
284
- send the query as usual. The self.use_cache
285
- setting must be set to true for this option to
286
- be useful. If set to false, then the cache will
287
- be skipped, even if a result has already been
288
- cached. Defaults to false.
289
-
290
- :returns True: The identity is provided
291
- :returns False: The identity is not listed
292
- :returns None: Nothing could be found due to a timeout
293
- """
294
- data = {'category': category,
295
- 'itype': itype,
296
- 'lang': lang,
297
- 'local': local,
298
- 'cached': cached}
299
- return self.api['has_identity'](jid, node, ifrom, data)
300
-
301
- async def get_info_from_domain(self, domain=None, timeout=None,
302
- cached=True, callback=None, **iqkwargs):
303
- """Fetch disco#info of specified domain and one disco#items level below
304
- """
305
-
306
- if domain is None:
307
- domain = self.xmpp.boundjid.domain
308
-
309
- if not cached or domain not in self.domain_infos:
310
- infos = [self.get_info(
311
- domain, timeout=timeout, **iqkwargs)]
312
- iq_items = await self.get_items(
313
- domain, timeout=timeout)
314
- items = iq_items['disco_items']['items']
315
- infos += [
316
- self.get_info(item[0], timeout=timeout, **iqkwargs)
317
- for item in items]
318
- info_futures, _ = await asyncio.wait(
319
- infos,
320
- timeout=timeout,
321
- )
322
-
323
- self.domain_infos[domain] = [
324
- future.result()
325
- for future in info_futures if not future.exception()
326
- ]
327
-
328
- results = self.domain_infos[domain]
329
-
330
- if callback is not None:
331
- callback(results)
332
- return results
333
-
334
- async def get_info(self, jid: OptJid = None, node: Optional[str] = None,
335
- local: Optional[bool] = None,
336
- cached: Optional[bool] = None, **kwargs) -> Iq:
337
- """
338
- Retrieve the disco#info results from a given JID/node combination.
339
-
340
- Info may be retrieved from both local resources and remote agents;
341
- the local parameter indicates if the information should be gathered
342
- by executing the local node handlers, or if a disco#info stanza
343
- must be generated and sent.
344
-
345
- If requesting items from a local JID/node, then only a DiscoInfo
346
- stanza will be returned. Otherwise, an Iq stanza will be returned.
347
-
348
- .. versionchanged:: 1.8.0
349
- This function is now a coroutine.
350
-
351
- :param jid: Request info from this JID.
352
- :param node: The particular node to query.
353
- :param local: If true, then the query is for a JID/node
354
- combination handled by this Slixmpp instance and
355
- no stanzas need to be sent.
356
- Otherwise, a disco stanza must be sent to the
357
- remote JID to retrieve the info.
358
- :param cached: If true, then look for the disco info data from
359
- the local cache system. If no results are found,
360
- send the query as usual. The self.use_cache
361
- setting must be set to true for this option to
362
- be useful. If set to false, then the cache will
363
- be skipped, even if a result has already been
364
- cached. Defaults to false.
365
- """
366
- if local is None:
367
- if jid is not None and not isinstance(jid, JID):
368
- jid = JID(jid)
369
- if self.xmpp.is_component:
370
- if jid.domain == self.xmpp.boundjid.domain:
371
- local = True
372
- else:
373
- if str(jid) == str(self.xmpp.boundjid):
374
- local = True
375
- jid = jid.full
376
- elif jid in (None, ''):
377
- local = True
378
-
379
- ifrom = kwargs.pop('ifrom', self.xmpp.boundjid) or self.xmpp.boundjid
380
- if local:
381
- log.debug("Looking up local disco#info data "
382
- "for %s, node %s.", jid, node)
383
- info = await self.api['get_info'](
384
- jid, node, ifrom,
385
- kwargs
386
- )
387
- info = self._fix_default_info(info)
388
- return self._wrap(ifrom, jid, info)
389
-
390
- if cached:
391
- log.debug("Looking up cached disco#info data "
392
- "for %s, node %s.", jid, node)
393
- info = await self.api['get_cached_info'](
394
- jid, node, ifrom,
395
- kwargs
396
- )
397
- if info is not None:
398
- return self._wrap(ifrom, jid, info)
399
-
400
- iq = self.xmpp.Iq()
401
- # Check dfrom parameter for backwards compatibility
402
- iq['from'] = ifrom or kwargs.get('dfrom', '')
403
- iq['to'] = jid
404
- iq['type'] = 'get'
405
- iq['disco_info']['node'] = node if node else ''
406
- return await iq.send(**kwargs)
407
-
408
- def set_info(self, jid: OptJid = None, node: Optional[str] = None,
409
- info: Optional[Union[Iq, DiscoInfo]] = None) -> Future:
410
- """
411
- Set the disco#info data for a JID/node based on an existing
412
- disco#info stanza.
413
-
414
- .. versionchanged:: 1.8.0
415
- This function now returns a Future.
416
-
417
- """
418
- if isinstance(info, Iq):
419
- info = info['disco_info']
420
- return self.api['set_info'](jid, node, None, info)
421
-
422
- async def get_items(self, jid: OptJid = None, node: Optional[str] = None,
423
- local: bool = False, ifrom: OptJid = None,
424
- **kwargs) -> Iq:
425
- """
426
- Retrieve the disco#items results from a given JID/node combination.
427
-
428
- Items may be retrieved from both local resources and remote agents;
429
- the local parameter indicates if the items should be gathered by
430
- executing the local node handlers, or if a disco#items stanza must
431
- be generated and sent.
432
-
433
- If requesting items from a local JID/node, then only a DiscoItems
434
- stanza will be returned. Otherwise, an Iq stanza will be returned.
435
-
436
- .. versionchanged:: 1.8.0
437
- This function is now a coroutine.
438
-
439
- :param jid: Request info from this JID.
440
- :param node: The particular node to query.
441
- :param local: If true, then the query is for a JID/node
442
- combination handled by this Slixmpp instance and
443
- no stanzas need to be sent.
444
- Otherwise, a disco stanza must be sent to the
445
- remove JID to retrieve the items.
446
- :param iterator: If True, return a result set iterator using
447
- the XEP-0059 plugin, if the plugin is loaded.
448
- Otherwise the parameter is ignored.
449
- """
450
- if ifrom is None and self.xmpp.is_component:
451
- ifrom = self.xmpp.boundjid.bare
452
-
453
- if local or local is None and jid is None:
454
- items = await self.api['get_items'](jid, node, ifrom, kwargs)
455
- return self._wrap(kwargs.get('ifrom', None), jid, items)
456
-
457
- iq = self.xmpp.Iq()
458
- # Check dfrom parameter for backwards compatibility
459
- iq['from'] = ifrom or kwargs.get('dfrom', '')
460
- iq['to'] = jid
461
- iq['type'] = 'get'
462
- iq['disco_items']['node'] = node if node else ''
463
- if kwargs.get('iterator', False) and self.xmpp['xep_0059']:
464
- return self.xmpp['xep_0059'].iterate(iq, 'disco_items')
465
- else:
466
- return await iq.send(**kwargs)
467
-
468
- def set_items(self, jid: OptJid = None, node: Optional[str] = None,
469
- **kwargs) -> Future:
470
- """
471
- Set or replace all items for the specified JID/node combination.
472
-
473
- The given items must be in a list or set where each item is a
474
- tuple of the form: (jid, node, name).
475
-
476
-
477
- .. versionchanged:: 1.8.0
478
- This function now returns a Future.
479
-
480
- :param jid: The JID to modify.
481
- :param node: Optional node to modify.
482
- :param items: A series of items in tuple format.
483
- """
484
- return self.api['set_items'](jid, node, None, kwargs)
485
-
486
- def del_items(self, jid: OptJid = None, node: Optional[str] = None,
487
- **kwargs) -> Future:
488
- """
489
- Remove all items from the given JID/node combination.
490
-
491
- .. versionchanged:: 1.8.0
492
- This function now returns a Future.
493
-
494
- Arguments:
495
- :param jid: The JID to modify.
496
- :param node: Optional node to modify.
497
- """
498
- return self.api['del_items'](jid, node, None, kwargs)
499
-
500
- def add_item(self, jid: str = '', name: str = '',
501
- node: Optional[str] = None, subnode: str = '',
502
- ijid: OptJid = None) -> Future:
503
- """
504
- Add a new item element to the given JID/node combination.
505
-
506
- Each item is required to have a JID, but may also specify
507
- a node value to reference non-addressable entities.
508
-
509
- .. versionchanged:: 1.8.0
510
- This function now returns a Future.
511
-
512
- :param jid: The JID for the item.
513
- :param name: Optional name for the item.
514
- :param node: The node to modify.
515
- :param subnode: Optional node for the item.
516
- :param ijid: The JID to modify.
517
- """
518
- if not jid:
519
- jid = self.xmpp.boundjid.full
520
- kwargs = {'ijid': jid,
521
- 'name': name,
522
- 'inode': subnode}
523
- return self.api['add_item'](ijid, node, None, kwargs)
524
-
525
- def del_item(self, jid: OptJid = None, node: Optional[str] = None,
526
- **kwargs) -> Future:
527
- """
528
- Remove a single item from the given JID/node combination.
529
-
530
- :param jid: The JID to modify.
531
- :param node: The node to modify.
532
- :param ijid: The item's JID.
533
- :param inode: The item's node.
534
- """
535
- return self.api['del_item'](jid, node, None, kwargs)
536
-
537
- def add_identity(self, category: str = '', itype: str = '', name: str = '',
538
- node: Optional[str] = None, jid: OptJid = None,
539
- lang: Optional[str] = None) -> Future:
540
- """
541
- Add a new identity to the given JID/node combination.
542
-
543
- Each identity must be unique in terms of all four identity
544
- components: category, type, name, and language.
545
-
546
- Multiple, identical category/type pairs are allowed only
547
- if the xml:lang values are different. Likewise, multiple
548
- category/type/xml:lang pairs are allowed so long as the
549
- names are different. A category and type is always required.
550
-
551
- .. versionchanged:: 1.8.0
552
- This function now returns a Future.
553
-
554
- :param category: The identity's category.
555
- :param itype: The identity's type.
556
- :param name: Optional name for the identity.
557
- :param lang: Optional two-letter language code.
558
- :param node: The node to modify.
559
- :param jid: The JID to modify.
560
- """
561
- kwargs = {'category': category,
562
- 'itype': itype,
563
- 'name': name,
564
- 'lang': lang}
565
- return self.api['add_identity'](jid, node, None, kwargs)
566
-
567
- def add_feature(self, feature: str, node: Optional[str] = None,
568
- jid: OptJid = None) -> Future:
569
- """
570
- Add a feature to a JID/node combination.
571
-
572
- .. versionchanged:: 1.8.0
573
- This function now returns a Future.
574
-
575
- :param feature: The namespace of the supported feature.
576
- :param node: The node to modify.
577
- :param jid: The JID to modify.
578
- """
579
- kwargs = {'feature': feature}
580
- return self.api['add_feature'](jid, node, None, kwargs)
581
-
582
- def del_identity(self, jid: OptJid = None,
583
- node: Optional[str] = None, **kwargs) -> Future:
584
- """
585
- Remove an identity from the given JID/node combination.
586
-
587
- .. versionchanged:: 1.8.0
588
- This function now returns a Future.
589
-
590
- :param jid: The JID to modify.
591
- :param node: The node to modify.
592
- :param category: The identity's category.
593
- :param itype: The identity's type value.
594
- :param name: Optional, human readable name for the identity.
595
- :param lang: Optional, the identity's xml:lang value.
596
- """
597
- return self.api['del_identity'](jid, node, None, kwargs)
598
-
599
- def del_feature(self, jid: OptJid = None, node: Optional[str] = None,
600
- **kwargs) -> Future:
601
- """
602
- Remove a feature from a given JID/node combination.
603
-
604
- .. versionchanged:: 1.8.0
605
- This function now returns a Future.
606
-
607
- :param jid: The JID to modify.
608
- :param node: The node to modify.
609
- :param feature: The feature's namespace.
610
- """
611
- return self.api['del_feature'](jid, node, None, kwargs)
612
-
613
- def set_identities(self, jid: OptJid = None, node: Optional[str] = None,
614
- **kwargs) -> Future:
615
- """
616
- Add or replace all identities for the given JID/node combination.
617
-
618
- The identities must be in a set where each identity is a tuple
619
- of the form: (category, type, lang, name)
620
-
621
- .. versionchanged:: 1.8.0
622
- This function now returns a Future.
623
-
624
- :param jid: The JID to modify.
625
- :param node: The node to modify.
626
- :param identities: A set of identities in tuple form.
627
- :param lang: Optional, xml:lang value.
628
- """
629
- return self.api['set_identities'](jid, node, None, kwargs)
630
-
631
- def del_identities(self, jid: OptJid = None, node: Optional[str] = None,
632
- **kwargs) -> Future:
633
- """
634
- Remove all identities for a JID/node combination.
635
-
636
- If a language is specified, only identities using that
637
- language will be removed.
638
-
639
- .. versionchanged:: 1.8.0
640
- This function now returns a Future.
641
-
642
- :param jid: The JID to modify.
643
- :param node: The node to modify.
644
- :param lang: Optional. If given, only remove identities
645
- using this xml:lang value.
646
- """
647
- return self.api['del_identities'](jid, node, None, kwargs)
648
-
649
- def set_features(self, jid: OptJid = None, node: Optional[str] = None,
650
- **kwargs) -> Future:
651
- """
652
- Add or replace the set of supported features
653
- for a JID/node combination.
654
-
655
- .. versionchanged:: 1.8.0
656
- This function now returns a Future.
657
-
658
- :param jid: The JID to modify.
659
- :param node: The node to modify.
660
- :param features: The new set of supported features.
661
- """
662
- return self.api['set_features'](jid, node, None, kwargs)
663
-
664
- def del_features(self, jid: OptJid = None, node: Optional[str] = None,
665
- **kwargs) -> Future:
666
- """
667
- Remove all features from a JID/node combination.
668
-
669
- .. versionchanged:: 1.8.0
670
- This function now returns a Future.
671
-
672
- :param jid: The JID to modify.
673
- :param node: The node to modify.
674
- """
675
- return self.api['del_features'](jid, node, None, kwargs)
676
-
677
- async def _run_node_handler(self, htype, jid, node: Optional[str] = None,
678
- ifrom: OptJid = None, data=None):
679
- """
680
- Execute the most specific node handler for the given
681
- JID/node combination.
682
-
683
- :param htype: The handler type to execute.
684
- :param jid: The JID requested.
685
- :param node: The node requested.
686
- :param data: Optional, custom data to pass to the handler.
687
- """
688
- if not data:
689
- data = {}
690
-
691
- return await self.api[htype](jid, node, ifrom, data)
692
-
693
- async def _handle_disco_info(self, iq: Iq):
694
- """
695
- Process an incoming disco#info stanza. If it is a get
696
- request, find and return the appropriate identities
697
- and features. If it is an info result, fire the
698
- disco_info event.
699
-
700
- :param iq: The incoming disco#items stanza.
701
- """
702
- if iq['type'] == 'get':
703
- log.debug("Received disco info query from "
704
- "<%s> to <%s>.", iq['from'], iq['to'])
705
- info = await self.api['get_info'](iq['to'],
706
- iq['disco_info']['node'],
707
- iq['from'],
708
- iq)
709
- if isinstance(info, Iq):
710
- info['id'] = iq['id']
711
- info.send()
712
- else:
713
- node = iq['disco_info']['node']
714
- iq = iq.reply()
715
- if info:
716
- info = self._fix_default_info(info)
717
- info['node'] = node
718
- iq.set_payload(info.xml)
719
- iq.send()
720
- elif iq['type'] == 'result':
721
- log.debug("Received disco info result from "
722
- "<%s> to <%s>.", iq['from'], iq['to'])
723
- if self.use_cache:
724
- log.debug("Caching disco info result from "
725
- "<%s> to <%s>.", iq['from'], iq['to'])
726
- if self.xmpp.is_component:
727
- ito = iq['to'].full
728
- else:
729
- ito = None
730
- await self.api['cache_info'](iq['from'],
731
- iq['disco_info']['node'],
732
- ito,
733
- iq)
734
- self.xmpp.event('disco_info', iq)
735
-
736
- async def _handle_disco_items(self, iq: Iq):
737
- """
738
- Process an incoming disco#items stanza. If it is a get
739
- request, find and return the appropriate items. If it
740
- is an items result, fire the disco_items event.
741
-
742
- :param iq: The incoming disco#items stanza.
743
- """
744
- if iq['type'] == 'get':
745
- log.debug("Received disco items query from "
746
- "<%s> to <%s>.", iq['from'], iq['to'])
747
- items = await self.api['get_items'](iq['to'],
748
- iq['disco_items']['node'],
749
- iq['from'],
750
- iq)
751
- if isinstance(items, Iq):
752
- items.send()
753
- else:
754
- iq = iq.reply()
755
- if items:
756
- iq.set_payload(items.xml)
757
- iq.send()
758
- elif iq['type'] == 'result':
759
- log.debug("Received disco items result from "
760
- "%s to %s.", iq['from'], iq['to'])
761
- self.xmpp.event('disco_items', iq)
762
-
763
- def _fix_default_info(self, info: DiscoInfo):
764
- """
765
- Disco#info results for a JID are required to include at least
766
- one identity and feature. As a default, if no other identity is
767
- provided, Slixmpp will use either the generic component or the
768
- bot client identity. A the standard disco#info feature will also be
769
- added if no features are provided.
770
-
771
- :param info: The disco#info quest (not the full Iq stanza) to modify.
772
- """
773
- result = info
774
- if isinstance(info, Iq):
775
- info = info['disco_info']
776
- if not info['node']:
777
- if not info['identities']:
778
- if self.xmpp.is_component:
779
- log.debug("No identity found for this entity. "
780
- "Using default component identity.")
781
- info.add_identity('component', 'generic')
782
- else:
783
- log.debug("No identity found for this entity. "
784
- "Using default client identity.")
785
- info.add_identity('client', 'bot')
786
- if not info['features']:
787
- log.debug("No features found for this entity. "
788
- "Using default disco#info feature.")
789
- info.add_feature(info.namespace)
790
- return result
791
-
792
- def _wrap(self, ito: OptJid, ifrom: OptJid, payload, force=False) -> Iq:
793
- """
794
- Ensure that results are wrapped in an Iq stanza
795
- if self.wrap_results has been set to True.
796
-
797
- :param ito: The JID to use as the 'to' value
798
- :param ifrom: The JID to use as the 'from' value
799
- :param payload: The disco data to wrap
800
- :param force: Force wrapping, regardless of self.wrap_results
801
- """
802
- if (force or self.wrap_results) and not isinstance(payload, Iq):
803
- iq = self.xmpp.Iq()
804
- # Since we're simulating a result, we have to treat
805
- # the 'from' and 'to' values opposite the normal way.
806
- iq['to'] = self.xmpp.boundjid if ito is None else ito
807
- iq['from'] = self.xmpp.boundjid if ifrom is None else ifrom
808
- iq['type'] = 'result'
809
- iq.append(payload)
810
- return iq
811
- return payload