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,7 +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
- from slixmpp.plugins.xep_0030.stanza.info import DiscoInfo
7
- from slixmpp.plugins.xep_0030.stanza.items import DiscoItems
@@ -1,270 +0,0 @@
1
- # Slixmpp: The Slick XMPP Library
2
- # Copyright (C) 2010 Nathanael C. Fritz, Lance J.T. Stout
3
- # This file is part of Slixmpp.
4
- # See the file LICENSE for copying permission.
5
- from typing import Iterable, List, Optional, Set, Tuple, Union
6
-
7
- from slixmpp.xmlstream import ET, ElementBase
8
-
9
- IdentityType = Tuple[str, str, Optional[str], Optional[str]]
10
-
11
-
12
- class DiscoInfo(ElementBase):
13
-
14
- """
15
- XMPP allows for users and agents to find the identities and features
16
- supported by other entities in the XMPP network through service discovery,
17
- or "disco". In particular, the "disco#info" query type for <iq> stanzas is
18
- used to request the list of identities and features offered by a JID.
19
-
20
- An identity is a combination of a category and type, such as the 'client'
21
- category with a type of 'pc' to indicate the agent is a human operated
22
- client with a GUI, or a category of 'gateway' with a type of 'aim' to
23
- identify the agent as a gateway for the legacy AIM protocol. See
24
- `XMPP Registrar Disco Categories`_ for a full list of
25
- accepted category and type combinations.
26
-
27
- .. _XMPP Registrar Disco Categories: <http://xmpp.org/registrar/disco-categories.html>
28
-
29
- Features are simply a set of the namespaces that identify the supported
30
- features. For example, a client that supports service discovery will
31
- include the feature ``http://jabber.org/protocol/disco#info``.
32
-
33
- Since clients and components may operate in several roles at once, identity
34
- and feature information may be grouped into "nodes". If one were to write
35
- all of the identities and features used by a client, then node names would
36
- be like section headings.
37
-
38
- Example disco#info stanza:
39
-
40
- .. code-block:: xml
41
-
42
- <iq type="get">
43
- <query xmlns="http://jabber.org/protocol/disco#info" />
44
- </iq>
45
-
46
- <iq type="result">
47
- <query xmlns="http://jabber.org/protocol/disco#info">
48
- <identity category="client" type="bot" name="Slixmpp Bot" />
49
- <feature var="http://jabber.org/protocol/disco#info" />
50
- <feature var="jabber:x:data" />
51
- <feature var="urn:xmpp:ping" />
52
- </query>
53
- </iq>
54
- """
55
-
56
- name = 'query'
57
- namespace = 'http://jabber.org/protocol/disco#info'
58
- plugin_attrib = 'disco_info'
59
- #: Stanza interfaces:
60
- #:
61
- #: - ``node``: The name of the node to either query or return the info from
62
- #: - ``identities``: A set of 4-tuples, where each tuple contains the
63
- #: category, type, xml:lang and name of an identity
64
- #: - ``features``: A set of namespaces for features
65
- #:
66
- interfaces = {'node', 'features', 'identities'}
67
- lang_interfaces = {'identities'}
68
-
69
- # Cache identities and features
70
- _identities: Set[Tuple[str, str, Optional[str]]]
71
- _features: Set[str]
72
-
73
- def setup(self, xml: Optional[ET.ElementTree] = None):
74
- """
75
- Populate the stanza object using an optional XML object.
76
-
77
- Overrides ElementBase.setup
78
-
79
- Caches identity and feature information.
80
-
81
- :param xml: Use an existing XML object for the stanza's values.
82
- """
83
- ElementBase.setup(self, xml)
84
-
85
- self._identities = {id[0:3] for id in self['identities']}
86
- self._features = self['features']
87
-
88
- def add_identity(self, category: str, itype: str,
89
- name: Optional[str] = None, lang: Optional[str] = None
90
- ) -> bool:
91
- """
92
- Add a new identity element. Each identity must be unique
93
- in terms of all four identity components.
94
-
95
- Multiple, identical category/type pairs are allowed only
96
- if the xml:lang values are different. Likewise, multiple
97
- category/type/xml:lang pairs are allowed so long as the names
98
- are different. In any case, a category and type are required.
99
-
100
- :param category: The general category to which the agent belongs.
101
- :param itype: A more specific designation with the category.
102
- :param name: Optional human readable name for this identity.
103
- :param lang: Optional standard xml:lang value.
104
- """
105
- identity = (category, itype, lang)
106
- if identity not in self._identities:
107
- self._identities.add(identity)
108
- id_xml = ET.Element('{%s}identity' % self.namespace)
109
- id_xml.attrib['category'] = category
110
- id_xml.attrib['type'] = itype
111
- if lang:
112
- id_xml.attrib['{%s}lang' % self.xml_ns] = lang
113
- if name:
114
- id_xml.attrib['name'] = name
115
- self.xml.insert(0, id_xml)
116
- return True
117
- return False
118
-
119
- def del_identity(self, category: str, itype: str, name=None,
120
- lang: Optional[str] = None) -> bool:
121
- """
122
- Remove a given identity.
123
-
124
- :param category: The general category to which the agent belonged.
125
- :param itype: A more specific designation with the category.
126
- :param name: Optional human readable name for this identity.
127
- :param lang: Optional, standard xml:lang value.
128
- """
129
- identity = (category, itype, lang)
130
- if identity in self._identities:
131
- self._identities.remove(identity)
132
- for id_xml in self.xml.findall('{%s}identity' % self.namespace):
133
- id = (id_xml.attrib['category'],
134
- id_xml.attrib['type'],
135
- id_xml.attrib.get('{%s}lang' % self.xml_ns, None))
136
- if id == identity:
137
- self.xml.remove(id_xml)
138
- return True
139
- return False
140
-
141
- def get_identities(self, lang: Optional[str] = None, dedupe: bool = True
142
- ) -> Iterable[IdentityType]:
143
- """
144
- Return a set of all identities in tuple form as so:
145
-
146
- (category, type, lang, name)
147
-
148
- If a language was specified, only return identities using
149
- that language.
150
-
151
- :param lang: Optional, standard xml:lang value.
152
- :param dedupe: If True, de-duplicate identities, otherwise
153
- return a list of all identities.
154
- """
155
- identities: Union[List[IdentityType], Set[IdentityType]]
156
- if dedupe:
157
- identities = set()
158
- else:
159
- identities = []
160
- for id_xml in self.xml.findall('{%s}identity' % self.namespace):
161
- xml_lang = id_xml.attrib.get('{%s}lang' % self.xml_ns, None)
162
- if lang is None or xml_lang == lang:
163
- id = (id_xml.attrib['category'],
164
- id_xml.attrib['type'],
165
- id_xml.attrib.get('{%s}lang' % self.xml_ns, None),
166
- id_xml.attrib.get('name', None))
167
- if isinstance(identities, set):
168
- identities.add(id)
169
- else:
170
- identities.append(id)
171
- return identities
172
-
173
- def set_identities(self, identities: Iterable[IdentityType],
174
- lang: Optional[str] = None):
175
- """
176
- Add or replace all identities. The identities must be a in set
177
- where each identity is a tuple of the form:
178
-
179
- (category, type, lang, name)
180
-
181
- If a language is specifified, any identities using that language
182
- will be removed to be replaced with the given identities.
183
-
184
- .. note::
185
-
186
- An identity's language will not be changed regardless of
187
- the value of lang.
188
-
189
- :param identities: A set of identities in tuple form.
190
- :param lang: Optional, standard xml:lang value.
191
- """
192
- self.del_identities(lang)
193
- for identity in identities:
194
- category, itype, lang, name = identity
195
- self.add_identity(category, itype, name, lang)
196
-
197
- def del_identities(self, lang: Optional[str] = None):
198
- """
199
- Remove all identities. If a language was specified, only
200
- remove identities using that language.
201
-
202
- :param lang: Optional, standard xml:lang value.
203
- """
204
- for id_xml in self.xml.findall('{%s}identity' % self.namespace):
205
- if lang is None:
206
- self.xml.remove(id_xml)
207
- elif id_xml.attrib.get('{%s}lang' % self.xml_ns, None) == lang:
208
- self._identities.remove((
209
- id_xml.attrib['category'],
210
- id_xml.attrib['type'],
211
- id_xml.attrib.get('{%s}lang' % self.xml_ns, None)))
212
- self.xml.remove(id_xml)
213
-
214
- def add_feature(self, feature: str) -> bool:
215
- """
216
- Add a single, new feature.
217
-
218
- :param feature: The namespace of the supported feature.
219
- """
220
- if feature not in self._features:
221
- self._features.add(feature)
222
- feature_xml = ET.Element('{%s}feature' % self.namespace)
223
- feature_xml.attrib['var'] = feature
224
- self.xml.append(feature_xml)
225
- return True
226
- return False
227
-
228
- def del_feature(self, feature: str) -> bool:
229
- """
230
- Remove a single feature.
231
-
232
- :param feature: The namespace of the removed feature.
233
- """
234
- if feature in self._features:
235
- self._features.remove(feature)
236
- for feature_xml in self.xml.findall('{%s}feature' % self.namespace):
237
- if feature_xml.attrib['var'] == feature:
238
- self.xml.remove(feature_xml)
239
- return True
240
- return False
241
-
242
- def get_features(self, dedupe: bool = True) -> Iterable[str]:
243
- """Return the set of all supported features."""
244
- features: Union[List[str], Set[str]]
245
- if dedupe:
246
- features = set()
247
- else:
248
- features = []
249
- for feature_xml in self.xml.findall('{%s}feature' % self.namespace):
250
- if isinstance(features, set):
251
- features.add(feature_xml.attrib['var'])
252
- else:
253
- features.append(feature_xml.attrib['var'])
254
- return features
255
-
256
- def set_features(self, features: Iterable[str]):
257
- """
258
- Add or replace the set of supported features.
259
-
260
- :param features: The new set of supported features.
261
- """
262
- self.del_features()
263
- for feature in features:
264
- self.add_feature(feature)
265
-
266
- def del_features(self):
267
- """Remove all features."""
268
- self._features = set()
269
- for feature_xml in self.xml.findall('{%s}feature' % self.namespace):
270
- self.xml.remove(feature_xml)
@@ -1,147 +0,0 @@
1
- # Slixmpp: The Slick XMPP Library
2
- # Copyright (C) 2010 Nathanael C. Fritz, Lance J.T. Stout
3
- # This file is part of Slixmpp.
4
- # See the file LICENSE for copying permission.
5
- from typing import Iterable, Optional, Set, Tuple
6
-
7
- from slixmpp import JID
8
- from slixmpp.xmlstream import ET, ElementBase, register_stanza_plugin
9
-
10
-
11
- class DiscoItem(ElementBase):
12
- name = 'item'
13
- namespace = 'http://jabber.org/protocol/disco#items'
14
- plugin_attrib = name
15
- interfaces = {'jid', 'node', 'name'}
16
-
17
- def get_node(self) -> Optional[str]:
18
- """Return the item's node name or ``None``."""
19
- return self._get_attr('node', None)
20
-
21
- def get_name(self) -> Optional[str]:
22
- """Return the item's human readable name, or ``None``."""
23
- return self._get_attr('name', None)
24
-
25
-
26
- class DiscoItems(ElementBase):
27
-
28
- """
29
- Example disco#items stanzas:
30
-
31
- .. code-block:: xml
32
-
33
- <iq type="get">
34
- <query xmlns="http://jabber.org/protocol/disco#items" />
35
- </iq>
36
-
37
- <iq type="result">
38
- <query xmlns="http://jabber.org/protocol/disco#items">
39
- <item jid="chat.example.com"
40
- node="xmppdev"
41
- name="XMPP Dev" />
42
- <item jid="chat.example.com"
43
- node="slixdev"
44
- name="Slixmpp Dev" />
45
- </query>
46
- </iq>
47
-
48
- """
49
-
50
- name = 'query'
51
- namespace = 'http://jabber.org/protocol/disco#items'
52
- plugin_attrib = 'disco_items'
53
- #: Stanza Interface:
54
- #:
55
- #: - ``node``: The name of the node to either
56
- #: query or return info from.
57
- #: - ``items``: A list of 3-tuples, where each tuple contains
58
- #: the JID, node, and name of an item.
59
- #:
60
- interfaces = {'node', 'items'}
61
-
62
- # Cache items
63
- _items: Set[Tuple[JID, Optional[str]]]
64
-
65
- def setup(self, xml: Optional[ET.ElementTree] = None):
66
- """
67
- Populate the stanza object using an optional XML object.
68
-
69
- Overrides ElementBase.setup
70
-
71
- Caches item information.
72
-
73
- :param xml: Use an existing XML object for the stanza's values.
74
- """
75
- ElementBase.setup(self, xml)
76
- self._items = {item[0:2] for item in self['items']}
77
-
78
- def add_item(self, jid: JID, node: Optional[str] = None,
79
- name: Optional[str] = None):
80
- """
81
- Add a new item element. Each item is required to have a
82
- JID, but may also specify a node value to reference
83
- non-addressable entitities.
84
-
85
- :param jid: The JID for the item.
86
- :param node: Optional additional information to reference
87
- non-addressable items.
88
- :param name: Optional human readable name for the item.
89
- """
90
- if (jid, node) not in self._items:
91
- self._items.add((jid, node))
92
- item = DiscoItem(parent=self)
93
- item['jid'] = jid
94
- item['node'] = node
95
- item['name'] = name
96
- self.iterables.append(item)
97
- return True
98
- return False
99
-
100
- def del_item(self, jid: JID, node: Optional[str] = None) -> bool:
101
- """
102
- Remove a single item.
103
-
104
- :param jid: JID of the item to remove.
105
- :param node: Optional extra identifying information.
106
- """
107
- if (jid, node) in self._items:
108
- for item_xml in self.xml.findall('{%s}item' % self.namespace):
109
- item = (item_xml.attrib['jid'],
110
- item_xml.attrib.get('node', None))
111
- if item == (jid, node):
112
- self.xml.remove(item_xml)
113
- return True
114
- return False
115
-
116
- def get_items(self) -> Set[DiscoItem]:
117
- """Return all items."""
118
- items = set()
119
- for item in self['substanzas']:
120
- if isinstance(item, DiscoItem):
121
- items.add((item['jid'], item['node'], item['name']))
122
- return items
123
-
124
- def set_items(self, items: Iterable[DiscoItem]):
125
- """
126
- Set or replace all items. The given items must be in a
127
- list or set where each item is a tuple of the form:
128
-
129
- (jid, node, name)
130
-
131
- :param items: A series of items in tuple format.
132
- """
133
- self.del_items()
134
- for item in items:
135
- jid, node, name = item
136
- self.add_item(jid, node, name)
137
-
138
- def del_items(self):
139
- """Remove all items."""
140
- self._items = set()
141
- items = [i for i in self.iterables if isinstance(i, DiscoItem)]
142
- for item in items:
143
- self.xml.remove(item.xml)
144
- self.iterables.remove(item)
145
-
146
-
147
- register_stanza_plugin(DiscoItems, DiscoItem, iterable=True)