annotate sat_pubsub/delegation.py @ 414:ccb2a22ea0fc

Python 3 port: /!\ Python 3.6+ is now needed to use SàT Pubsub /!\ instability may occur and features may not be working anymore, this will improve with time The same procedure as in backend has been applied (check backend commit ab2696e34d29 logs for details). Python minimal version has been updated in setup.py
author Goffi <goffi@goffi.org>
date Fri, 16 Aug 2019 12:53:33 +0200
parents c56a728412f1
children cebcb7f56889
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
414
ccb2a22ea0fc Python 3 port:
Goffi <goffi@goffi.org>
parents: 405
diff changeset
1 #!/usr/bin/env python3
242
a6170637690d remote roster partial support
Goffi <goffi@goffi.org>
parents:
diff changeset
2 #-*- coding: utf-8 -*-
a6170637690d remote roster partial support
Goffi <goffi@goffi.org>
parents:
diff changeset
3 #
312
5d7c3787672e fixed copyright put in docstring instead of comments
Goffi <goffi@goffi.org>
parents: 310
diff changeset
4 # Copyright (c) 2015 Jérôme Poisson
242
a6170637690d remote roster partial support
Goffi <goffi@goffi.org>
parents:
diff changeset
5
a6170637690d remote roster partial support
Goffi <goffi@goffi.org>
parents:
diff changeset
6
312
5d7c3787672e fixed copyright put in docstring instead of comments
Goffi <goffi@goffi.org>
parents: 310
diff changeset
7 # This program is free software: you can redistribute it and/or modify
5d7c3787672e fixed copyright put in docstring instead of comments
Goffi <goffi@goffi.org>
parents: 310
diff changeset
8 # it under the terms of the GNU Affero General Public License as published by
5d7c3787672e fixed copyright put in docstring instead of comments
Goffi <goffi@goffi.org>
parents: 310
diff changeset
9 # the Free Software Foundation, either version 3 of the License, or
5d7c3787672e fixed copyright put in docstring instead of comments
Goffi <goffi@goffi.org>
parents: 310
diff changeset
10 # (at your option) any later version.
242
a6170637690d remote roster partial support
Goffi <goffi@goffi.org>
parents:
diff changeset
11
312
5d7c3787672e fixed copyright put in docstring instead of comments
Goffi <goffi@goffi.org>
parents: 310
diff changeset
12 # This program is distributed in the hope that it will be useful,
5d7c3787672e fixed copyright put in docstring instead of comments
Goffi <goffi@goffi.org>
parents: 310
diff changeset
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
5d7c3787672e fixed copyright put in docstring instead of comments
Goffi <goffi@goffi.org>
parents: 310
diff changeset
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
5d7c3787672e fixed copyright put in docstring instead of comments
Goffi <goffi@goffi.org>
parents: 310
diff changeset
15 # GNU Affero General Public License for more details.
242
a6170637690d remote roster partial support
Goffi <goffi@goffi.org>
parents:
diff changeset
16
312
5d7c3787672e fixed copyright put in docstring instead of comments
Goffi <goffi@goffi.org>
parents: 310
diff changeset
17 # You should have received a copy of the GNU Affero General Public License
5d7c3787672e fixed copyright put in docstring instead of comments
Goffi <goffi@goffi.org>
parents: 310
diff changeset
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
242
a6170637690d remote roster partial support
Goffi <goffi@goffi.org>
parents:
diff changeset
19
312
5d7c3787672e fixed copyright put in docstring instead of comments
Goffi <goffi@goffi.org>
parents: 310
diff changeset
20 # ---
242
a6170637690d remote roster partial support
Goffi <goffi@goffi.org>
parents:
diff changeset
21
312
5d7c3787672e fixed copyright put in docstring instead of comments
Goffi <goffi@goffi.org>
parents: 310
diff changeset
22 # This module implements XEP-0355 (Namespace delegation) to use SàT Pubsub as PEP service
242
a6170637690d remote roster partial support
Goffi <goffi@goffi.org>
parents:
diff changeset
23
285
a87c155d0fd5 replaced former roster dirty hack by a XEP-0356 first draft implementation, only roster get is implemented so far
Goffi <goffi@goffi.org>
parents: 283
diff changeset
24 from wokkel.subprotocols import XMPPHandler
287
61f92273fb69 implementation of XEP-0355 (Namespace Delegation) to use SàT Pubsub as PEP service, first draft
Goffi <goffi@goffi.org>
parents: 286
diff changeset
25 from wokkel import pubsub
289
f08f8536cab8 mod delegation: extensions management (XEP-0128)
Goffi <goffi@goffi.org>
parents: 288
diff changeset
26 from wokkel import data_form
288
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
27 from wokkel import disco, iwokkel
292
6918a0dad359 delegation: delegated stanza are tracked
Goffi <goffi@goffi.org>
parents: 291
diff changeset
28 from wokkel.iwokkel import IPubSubService
322
54d90c73b8b5 mam: various improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
29 from wokkel import mam
285
a87c155d0fd5 replaced former roster dirty hack by a XEP-0356 first draft implementation, only roster get is implemented so far
Goffi <goffi@goffi.org>
parents: 283
diff changeset
30 from twisted.python import log
291
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
31 from twisted.words.protocols.jabber import jid, error
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
32 from twisted.words.protocols.jabber.xmlstream import toResponse
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
33 from twisted.words.xish import domish
414
ccb2a22ea0fc Python 3 port:
Goffi <goffi@goffi.org>
parents: 405
diff changeset
34 from zope.interface import implementer
242
a6170637690d remote roster partial support
Goffi <goffi@goffi.org>
parents:
diff changeset
35
287
61f92273fb69 implementation of XEP-0355 (Namespace Delegation) to use SàT Pubsub as PEP service, first draft
Goffi <goffi@goffi.org>
parents: 286
diff changeset
36 DELEGATION_NS = 'urn:xmpp:delegation:1'
61f92273fb69 implementation of XEP-0355 (Namespace Delegation) to use SàT Pubsub as PEP service, first draft
Goffi <goffi@goffi.org>
parents: 286
diff changeset
37 FORWARDED_NS = 'urn:xmpp:forward:0'
61f92273fb69 implementation of XEP-0355 (Namespace Delegation) to use SàT Pubsub as PEP service, first draft
Goffi <goffi@goffi.org>
parents: 286
diff changeset
38 DELEGATION_ADV_XPATH = '/message/delegation[@xmlns="{}"]'.format(DELEGATION_NS)
291
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
39 DELEGATION_FWD_XPATH = '/iq[@type="set"]/delegation[@xmlns="{}"]/forwarded[@xmlns="{}"]'.format(DELEGATION_NS, FORWARDED_NS)
285
a87c155d0fd5 replaced former roster dirty hack by a XEP-0356 first draft implementation, only roster get is implemented so far
Goffi <goffi@goffi.org>
parents: 283
diff changeset
40
288
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
41 DELEGATION_MAIN_SEP = "::"
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
42 DELEGATION_BARE_SEP = ":bare:"
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
43
322
54d90c73b8b5 mam: various improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
44 TO_HACK = ((IPubSubService, pubsub, "PubSubRequest"),
54d90c73b8b5 mam: various improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
45 (mam.IMAMService, mam, "MAMRequest"))
54d90c73b8b5 mam: various improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
46
54d90c73b8b5 mam: various improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
47
285
a87c155d0fd5 replaced former roster dirty hack by a XEP-0356 first draft implementation, only roster get is implemented so far
Goffi <goffi@goffi.org>
parents: 283
diff changeset
48 class InvalidStanza(Exception):
a87c155d0fd5 replaced former roster dirty hack by a XEP-0356 first draft implementation, only roster get is implemented so far
Goffi <goffi@goffi.org>
parents: 283
diff changeset
49 pass
a87c155d0fd5 replaced former roster dirty hack by a XEP-0356 first draft implementation, only roster get is implemented so far
Goffi <goffi@goffi.org>
parents: 283
diff changeset
50
292
6918a0dad359 delegation: delegated stanza are tracked
Goffi <goffi@goffi.org>
parents: 291
diff changeset
51
414
ccb2a22ea0fc Python 3 port:
Goffi <goffi@goffi.org>
parents: 405
diff changeset
52 @implementer(iwokkel.IDisco)
287
61f92273fb69 implementation of XEP-0355 (Namespace Delegation) to use SàT Pubsub as PEP service, first draft
Goffi <goffi@goffi.org>
parents: 286
diff changeset
53 class DelegationsHandler(XMPPHandler):
292
6918a0dad359 delegation: delegated stanza are tracked
Goffi <goffi@goffi.org>
parents: 291
diff changeset
54 _service_hacked = False
242
a6170637690d remote roster partial support
Goffi <goffi@goffi.org>
parents:
diff changeset
55
285
a87c155d0fd5 replaced former roster dirty hack by a XEP-0356 first draft implementation, only roster get is implemented so far
Goffi <goffi@goffi.org>
parents: 283
diff changeset
56 def __init__(self):
287
61f92273fb69 implementation of XEP-0355 (Namespace Delegation) to use SàT Pubsub as PEP service, first draft
Goffi <goffi@goffi.org>
parents: 286
diff changeset
57 super(DelegationsHandler, self).__init__()
285
a87c155d0fd5 replaced former roster dirty hack by a XEP-0356 first draft implementation, only roster get is implemented so far
Goffi <goffi@goffi.org>
parents: 283
diff changeset
58
292
6918a0dad359 delegation: delegated stanza are tracked
Goffi <goffi@goffi.org>
parents: 291
diff changeset
59 def _service_hack(self):
322
54d90c73b8b5 mam: various improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
60 """Patch the request classes of services to track delegated stanzas"""
292
6918a0dad359 delegation: delegated stanza are tracked
Goffi <goffi@goffi.org>
parents: 291
diff changeset
61 # XXX: we need to monkey patch to track origin of the stanza in PubSubRequest.
6918a0dad359 delegation: delegated stanza are tracked
Goffi <goffi@goffi.org>
parents: 291
diff changeset
62 # As PubSubRequest from sat.tmp.wokkel.pubsub use _request_class while
6918a0dad359 delegation: delegated stanza are tracked
Goffi <goffi@goffi.org>
parents: 291
diff changeset
63 # original wokkel.pubsub use directly pubsub.PubSubRequest, we need to
6918a0dad359 delegation: delegated stanza are tracked
Goffi <goffi@goffi.org>
parents: 291
diff changeset
64 # check which version is used before monkeypatching
6918a0dad359 delegation: delegated stanza are tracked
Goffi <goffi@goffi.org>
parents: 291
diff changeset
65 for handler in self.parent.handlers:
322
54d90c73b8b5 mam: various improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
66 for service, module, default_base_cls in TO_HACK:
54d90c73b8b5 mam: various improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
67 if service.providedBy(handler):
54d90c73b8b5 mam: various improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
68 if hasattr(handler, '_request_class'):
54d90c73b8b5 mam: various improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
69 request_base_class = handler._request_class
54d90c73b8b5 mam: various improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
70 else:
54d90c73b8b5 mam: various improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
71 request_base_class = getattr(module, default_base_cls)
292
6918a0dad359 delegation: delegated stanza are tracked
Goffi <goffi@goffi.org>
parents: 291
diff changeset
72
322
54d90c73b8b5 mam: various improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
73 class RequestWithDelegation(request_base_class):
54d90c73b8b5 mam: various improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
74 """A XxxRequest which put an indicator if the stanza comme from delegation"""
292
6918a0dad359 delegation: delegated stanza are tracked
Goffi <goffi@goffi.org>
parents: 291
diff changeset
75
322
54d90c73b8b5 mam: various improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
76 @classmethod
54d90c73b8b5 mam: various improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
77 def fromElement(cls, element):
54d90c73b8b5 mam: various improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
78 """Check if element comme from delegation, and set a delegated flags
292
6918a0dad359 delegation: delegated stanza are tracked
Goffi <goffi@goffi.org>
parents: 291
diff changeset
79
322
54d90c73b8b5 mam: various improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
80 delegated flag is either False, or it's a jid of the delegating server
54d90c73b8b5 mam: various improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
81 the delegated flag must be set on element before use
54d90c73b8b5 mam: various improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
82 """
54d90c73b8b5 mam: various improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
83 try:
54d90c73b8b5 mam: various improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
84 # __getattr__ is overriden in domish.Element, so we use __getattribute__
54d90c73b8b5 mam: various improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
85 delegated = element.__getattribute__('delegated')
54d90c73b8b5 mam: various improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
86 except AttributeError:
54d90c73b8b5 mam: various improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
87 delegated = False
54d90c73b8b5 mam: various improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
88 instance = cls.__base__.fromElement(element)
54d90c73b8b5 mam: various improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
89 instance.delegated = delegated
54d90c73b8b5 mam: various improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
90 return instance
292
6918a0dad359 delegation: delegated stanza are tracked
Goffi <goffi@goffi.org>
parents: 291
diff changeset
91
322
54d90c73b8b5 mam: various improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
92 if hasattr(handler, '_request_class'):
54d90c73b8b5 mam: various improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
93 handler._request_class = RequestWithDelegation
54d90c73b8b5 mam: various improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
94 else:
54d90c73b8b5 mam: various improvments:
Goffi <goffi@goffi.org>
parents: 312
diff changeset
95 setattr(module, default_base_cls, RequestWithDelegation)
292
6918a0dad359 delegation: delegated stanza are tracked
Goffi <goffi@goffi.org>
parents: 291
diff changeset
96 DelegationsHandler._service_hacked = True
6918a0dad359 delegation: delegated stanza are tracked
Goffi <goffi@goffi.org>
parents: 291
diff changeset
97
285
a87c155d0fd5 replaced former roster dirty hack by a XEP-0356 first draft implementation, only roster get is implemented so far
Goffi <goffi@goffi.org>
parents: 283
diff changeset
98 def connectionInitialized(self):
292
6918a0dad359 delegation: delegated stanza are tracked
Goffi <goffi@goffi.org>
parents: 291
diff changeset
99 if not self._service_hacked:
6918a0dad359 delegation: delegated stanza are tracked
Goffi <goffi@goffi.org>
parents: 291
diff changeset
100 self._service_hack()
287
61f92273fb69 implementation of XEP-0355 (Namespace Delegation) to use SàT Pubsub as PEP service, first draft
Goffi <goffi@goffi.org>
parents: 286
diff changeset
101 self.xmlstream.addObserver(DELEGATION_ADV_XPATH, self.onAdvertise)
291
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
102 self.xmlstream.addObserver(DELEGATION_FWD_XPATH, self._obsWrapper, 0, self.onForward)
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
103 self._current_iqs = {} # dict of iq being handler by delegation
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
104 self._xs_send = self.xmlstream.send
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
105 self.xmlstream.send = self._sendHack
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
106
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
107 def _sendHack(self, elt):
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
108 """This method is called instead of xmlstream to control sending
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
109
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
110 @param obj(domsish.Element, unicode, str): obj sent to real xmlstream
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
111 """
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
112 if isinstance(elt, domish.Element) and elt.name=='iq':
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
113 try:
292
6918a0dad359 delegation: delegated stanza are tracked
Goffi <goffi@goffi.org>
parents: 291
diff changeset
114 id_ = elt.getAttribute('id')
6918a0dad359 delegation: delegated stanza are tracked
Goffi <goffi@goffi.org>
parents: 291
diff changeset
115 ori_iq, managed_entity = self._current_iqs[id_]
291
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
116 if jid.JID(elt['to']) != managed_entity:
292
6918a0dad359 delegation: delegated stanza are tracked
Goffi <goffi@goffi.org>
parents: 291
diff changeset
117 log.msg("IQ id conflict: the managed entity doesn't match (got {got} was expecting {expected})"
6918a0dad359 delegation: delegated stanza are tracked
Goffi <goffi@goffi.org>
parents: 291
diff changeset
118 .format(got=jid.JID(elt['to']), expected=managed_entity))
291
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
119 raise KeyError
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
120 except KeyError:
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
121 # the iq is not a delegated one
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
122 self._xs_send(elt)
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
123 else:
292
6918a0dad359 delegation: delegated stanza are tracked
Goffi <goffi@goffi.org>
parents: 291
diff changeset
124 del self._current_iqs[id_]
291
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
125 iq_result_elt = toResponse(ori_iq, 'result')
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
126 fwd_elt = iq_result_elt.addElement('delegation', DELEGATION_NS).addElement('forwarded', FORWARDED_NS)
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
127 fwd_elt.addChild(elt)
292
6918a0dad359 delegation: delegated stanza are tracked
Goffi <goffi@goffi.org>
parents: 291
diff changeset
128 elt.uri = elt.defaultUri = 'jabber:client'
291
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
129 self._xs_send(iq_result_elt)
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
130 else:
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
131 self._xs_send(elt)
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
132
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
133 def _obsWrapper(self, observer, stanza):
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
134 """Wrapper to observer which catch StanzaError
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
135
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
136 @param observer(callable): method to wrap
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
137 """
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
138 try:
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
139 observer(stanza)
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
140 except error.StanzaError as e:
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
141 error_elt = e.toResponse(stanza)
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
142 self._xs_send(error_elt)
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
143 stanza.handled = True
285
a87c155d0fd5 replaced former roster dirty hack by a XEP-0356 first draft implementation, only roster get is implemented so far
Goffi <goffi@goffi.org>
parents: 283
diff changeset
144
a87c155d0fd5 replaced former roster dirty hack by a XEP-0356 first draft implementation, only roster get is implemented so far
Goffi <goffi@goffi.org>
parents: 283
diff changeset
145 def onAdvertise(self, message):
291
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
146 """Manage the <message/> advertising delegations"""
414
ccb2a22ea0fc Python 3 port:
Goffi <goffi@goffi.org>
parents: 405
diff changeset
147 delegation_elt = next(message.elements(DELEGATION_NS, 'delegation'))
287
61f92273fb69 implementation of XEP-0355 (Namespace Delegation) to use SàT Pubsub as PEP service, first draft
Goffi <goffi@goffi.org>
parents: 286
diff changeset
148 delegated = {}
61f92273fb69 implementation of XEP-0355 (Namespace Delegation) to use SàT Pubsub as PEP service, first draft
Goffi <goffi@goffi.org>
parents: 286
diff changeset
149 for delegated_elt in delegation_elt.elements(DELEGATION_NS):
285
a87c155d0fd5 replaced former roster dirty hack by a XEP-0356 first draft implementation, only roster get is implemented so far
Goffi <goffi@goffi.org>
parents: 283
diff changeset
150 try:
287
61f92273fb69 implementation of XEP-0355 (Namespace Delegation) to use SàT Pubsub as PEP service, first draft
Goffi <goffi@goffi.org>
parents: 286
diff changeset
151 if delegated_elt.name != 'delegated':
414
ccb2a22ea0fc Python 3 port:
Goffi <goffi@goffi.org>
parents: 405
diff changeset
152 raise InvalidStanza('unexpected element {}'.format(delegated_elt.name))
285
a87c155d0fd5 replaced former roster dirty hack by a XEP-0356 first draft implementation, only roster get is implemented so far
Goffi <goffi@goffi.org>
parents: 283
diff changeset
153 try:
287
61f92273fb69 implementation of XEP-0355 (Namespace Delegation) to use SàT Pubsub as PEP service, first draft
Goffi <goffi@goffi.org>
parents: 286
diff changeset
154 namespace = delegated_elt['namespace']
285
a87c155d0fd5 replaced former roster dirty hack by a XEP-0356 first draft implementation, only roster get is implemented so far
Goffi <goffi@goffi.org>
parents: 283
diff changeset
155 except KeyError:
414
ccb2a22ea0fc Python 3 port:
Goffi <goffi@goffi.org>
parents: 405
diff changeset
156 raise InvalidStanza('was expecting a "namespace" attribute in delegated element')
287
61f92273fb69 implementation of XEP-0355 (Namespace Delegation) to use SàT Pubsub as PEP service, first draft
Goffi <goffi@goffi.org>
parents: 286
diff changeset
157 delegated[namespace] = []
61f92273fb69 implementation of XEP-0355 (Namespace Delegation) to use SàT Pubsub as PEP service, first draft
Goffi <goffi@goffi.org>
parents: 286
diff changeset
158 for attribute_elt in delegated_elt.elements(DELEGATION_NS, 'attribute'):
61f92273fb69 implementation of XEP-0355 (Namespace Delegation) to use SàT Pubsub as PEP service, first draft
Goffi <goffi@goffi.org>
parents: 286
diff changeset
159 try:
61f92273fb69 implementation of XEP-0355 (Namespace Delegation) to use SàT Pubsub as PEP service, first draft
Goffi <goffi@goffi.org>
parents: 286
diff changeset
160 delegated[namespace].append(attribute_elt["name"])
61f92273fb69 implementation of XEP-0355 (Namespace Delegation) to use SàT Pubsub as PEP service, first draft
Goffi <goffi@goffi.org>
parents: 286
diff changeset
161 except KeyError:
414
ccb2a22ea0fc Python 3 port:
Goffi <goffi@goffi.org>
parents: 405
diff changeset
162 raise InvalidStanza('was expecting a "name" attribute in attribute element')
285
a87c155d0fd5 replaced former roster dirty hack by a XEP-0356 first draft implementation, only roster get is implemented so far
Goffi <goffi@goffi.org>
parents: 283
diff changeset
163 except InvalidStanza as e:
287
61f92273fb69 implementation of XEP-0355 (Namespace Delegation) to use SàT Pubsub as PEP service, first draft
Goffi <goffi@goffi.org>
parents: 286
diff changeset
164 log.msg("Invalid stanza received ({})".format(e))
285
a87c155d0fd5 replaced former roster dirty hack by a XEP-0356 first draft implementation, only roster get is implemented so far
Goffi <goffi@goffi.org>
parents: 283
diff changeset
165
414
ccb2a22ea0fc Python 3 port:
Goffi <goffi@goffi.org>
parents: 405
diff changeset
166 log.msg('delegations updated:\n{}'.format(
ccb2a22ea0fc Python 3 port:
Goffi <goffi@goffi.org>
parents: 405
diff changeset
167 '\n'.join([" - namespace {}{}".format(ns,
ccb2a22ea0fc Python 3 port:
Goffi <goffi@goffi.org>
parents: 405
diff changeset
168 "" if not attributes else " with filtering on {} attribute(s)".format(
ccb2a22ea0fc Python 3 port:
Goffi <goffi@goffi.org>
parents: 405
diff changeset
169 ", ".join(attributes))) for ns, attributes in list(delegated.items())])))
242
a6170637690d remote roster partial support
Goffi <goffi@goffi.org>
parents:
diff changeset
170
287
61f92273fb69 implementation of XEP-0355 (Namespace Delegation) to use SàT Pubsub as PEP service, first draft
Goffi <goffi@goffi.org>
parents: 286
diff changeset
171 if not pubsub.NS_PUBSUB in delegated:
414
ccb2a22ea0fc Python 3 port:
Goffi <goffi@goffi.org>
parents: 405
diff changeset
172 log.msg("Didn't got pubsub delegation from server, can't act as a PEP service")
242
a6170637690d remote roster partial support
Goffi <goffi@goffi.org>
parents:
diff changeset
173
291
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
174 def onForward(self, iq):
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
175 """Manage forwarded iq
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
176
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
177 @param iq(domish.Element): full delegation stanza
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
178 """
310
e6a9a3c93314 delegation: fixed bad security check which was rejecting all delegations from external servers:
Goffi <goffi@goffi.org>
parents: 292
diff changeset
179
e6a9a3c93314 delegation: fixed bad security check which was rejecting all delegations from external servers:
Goffi <goffi@goffi.org>
parents: 292
diff changeset
180 # FIXME: we use a hack supposing that our delegation come from hostname
e6a9a3c93314 delegation: fixed bad security check which was rejecting all delegations from external servers:
Goffi <goffi@goffi.org>
parents: 292
diff changeset
181 # and we are a component named [name].hostname
e6a9a3c93314 delegation: fixed bad security check which was rejecting all delegations from external servers:
Goffi <goffi@goffi.org>
parents: 292
diff changeset
182 # but we need to manage properly allowed servers
e6a9a3c93314 delegation: fixed bad security check which was rejecting all delegations from external servers:
Goffi <goffi@goffi.org>
parents: 292
diff changeset
183 # TODO: do proper origin security check
e6a9a3c93314 delegation: fixed bad security check which was rejecting all delegations from external servers:
Goffi <goffi@goffi.org>
parents: 292
diff changeset
184 _, allowed = iq['to'].split('.', 1)
e6a9a3c93314 delegation: fixed bad security check which was rejecting all delegations from external servers:
Goffi <goffi@goffi.org>
parents: 292
diff changeset
185 if jid.JID(iq['from']) != jid.JID(allowed):
414
ccb2a22ea0fc Python 3 port:
Goffi <goffi@goffi.org>
parents: 405
diff changeset
186 log.msg(("SECURITY WARNING: forwarded stanza doesn't come from our server: {}"
310
e6a9a3c93314 delegation: fixed bad security check which was rejecting all delegations from external servers:
Goffi <goffi@goffi.org>
parents: 292
diff changeset
187 .format(iq.toXml())).encode('utf-8'))
e6a9a3c93314 delegation: fixed bad security check which was rejecting all delegations from external servers:
Goffi <goffi@goffi.org>
parents: 292
diff changeset
188 raise error.StanzaError('not-allowed')
e6a9a3c93314 delegation: fixed bad security check which was rejecting all delegations from external servers:
Goffi <goffi@goffi.org>
parents: 292
diff changeset
189
291
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
190 try:
414
ccb2a22ea0fc Python 3 port:
Goffi <goffi@goffi.org>
parents: 405
diff changeset
191 delegation_elt = next(iq.elements(DELEGATION_NS, 'delegation'))
ccb2a22ea0fc Python 3 port:
Goffi <goffi@goffi.org>
parents: 405
diff changeset
192 forwarded_elt = next(delegation_elt.elements(FORWARDED_NS, 'forwarded'))
ccb2a22ea0fc Python 3 port:
Goffi <goffi@goffi.org>
parents: 405
diff changeset
193 fwd_iq = next(forwarded_elt.elements('jabber:client', 'iq'))
291
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
194 except StopIteration:
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
195 raise error.StanzaError('not-acceptable')
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
196
292
6918a0dad359 delegation: delegated stanza are tracked
Goffi <goffi@goffi.org>
parents: 291
diff changeset
197 managed_entity = jid.JID(fwd_iq['from'])
291
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
198
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
199 self._current_iqs[fwd_iq['id']] = (iq, managed_entity)
292
6918a0dad359 delegation: delegated stanza are tracked
Goffi <goffi@goffi.org>
parents: 291
diff changeset
200 fwd_iq.delegated = True
6918a0dad359 delegation: delegated stanza are tracked
Goffi <goffi@goffi.org>
parents: 291
diff changeset
201
6918a0dad359 delegation: delegated stanza are tracked
Goffi <goffi@goffi.org>
parents: 291
diff changeset
202 # we need a recipient in pubsub request for PEP
6918a0dad359 delegation: delegated stanza are tracked
Goffi <goffi@goffi.org>
parents: 291
diff changeset
203 # so we set "to" attribute if it doesn't exist
6918a0dad359 delegation: delegated stanza are tracked
Goffi <goffi@goffi.org>
parents: 291
diff changeset
204 if not fwd_iq.hasAttribute('to'):
6918a0dad359 delegation: delegated stanza are tracked
Goffi <goffi@goffi.org>
parents: 291
diff changeset
205 fwd_iq["to"] = jid.JID(fwd_iq["from"]).userhost()
6918a0dad359 delegation: delegated stanza are tracked
Goffi <goffi@goffi.org>
parents: 291
diff changeset
206
291
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
207 # we now inject the element in the stream
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
208 self.xmlstream.dispatch(fwd_iq)
61fb4817b77f delegation: iq forwarded management:
Goffi <goffi@goffi.org>
parents: 289
diff changeset
209
288
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
210 def getDiscoInfo(self, requestor, target, nodeIdentifier=''):
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
211 """Manage disco nesting
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
212
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
213 This method looks for DiscoHandler in sibling handlers and use it to
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
214 collect main disco infos. It then filters by delegated namespace and return it.
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
215 An identity is added for PEP if pubsub namespace is requested.
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
216
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
217 The same features/identities are returned for main and bare nodes
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
218 """
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
219 if not nodeIdentifier.startswith(DELEGATION_NS):
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
220 return []
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
221
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
222 try:
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
223 _, namespace = nodeIdentifier.split(DELEGATION_MAIN_SEP, 1)
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
224 except ValueError:
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
225 try:
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
226 _, namespace = nodeIdentifier.split(DELEGATION_BARE_SEP, 1)
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
227 except ValueError:
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
228 log.msg("Unexpected disco node: {}".format(nodeIdentifier))
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
229 raise error.StanzaError('not-acceptable')
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
230
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
231 if not namespace:
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
232 log.msg("No namespace found in node {}".format(nodeIdentifier))
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
233 return []
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
234
334
0a93d71f9503 delegation: use same disco for all pubsub namespaces
Goffi <goffi@goffi.org>
parents: 322
diff changeset
235 if namespace.startswith(pubsub.NS_PUBSUB):
0a93d71f9503 delegation: use same disco for all pubsub namespaces
Goffi <goffi@goffi.org>
parents: 322
diff changeset
236 # pubsub use several namespaces starting with NS_PUBSUB (e.g. http://jabber.org/protocol/pubsub#owner)
0a93d71f9503 delegation: use same disco for all pubsub namespaces
Goffi <goffi@goffi.org>
parents: 322
diff changeset
237 # we return the same disco for all of them
0a93d71f9503 delegation: use same disco for all pubsub namespaces
Goffi <goffi@goffi.org>
parents: 322
diff changeset
238 namespace = pubsub.NS_PUBSUB
0a93d71f9503 delegation: use same disco for all pubsub namespaces
Goffi <goffi@goffi.org>
parents: 322
diff changeset
239
288
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
240 def gotInfos(infos):
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
241 ns_features = []
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
242 for info in infos:
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
243 if isinstance(info, disco.DiscoFeature) and info.startswith(namespace):
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
244 ns_features.append(info)
289
f08f8536cab8 mod delegation: extensions management (XEP-0128)
Goffi <goffi@goffi.org>
parents: 288
diff changeset
245 elif (isinstance(info, data_form.Form) and info.formNamespace
f08f8536cab8 mod delegation: extensions management (XEP-0128)
Goffi <goffi@goffi.org>
parents: 288
diff changeset
246 and info.formNamespace.startwith(namespace)):
f08f8536cab8 mod delegation: extensions management (XEP-0128)
Goffi <goffi@goffi.org>
parents: 288
diff changeset
247 # extensions management (XEP-0128)
f08f8536cab8 mod delegation: extensions management (XEP-0128)
Goffi <goffi@goffi.org>
parents: 288
diff changeset
248 ns_features.append(info)
288
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
249
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
250 if namespace == pubsub.NS_PUBSUB:
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
251 ns_features.append(disco.DiscoIdentity('pubsub', 'pep'))
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
252
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
253 return ns_features
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
254
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
255 for handler in self.parent.handlers:
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
256 if isinstance(handler, disco.DiscoHandler):
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
257 break
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
258
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
259 if not isinstance(handler, disco.DiscoHandler):
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
260 log.err("Can't find DiscoHandler")
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
261 return []
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
262
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
263 d = handler.info(requestor, target, '')
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
264 d.addCallback(gotInfos)
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
265 return d
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
266
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
267 def getDiscoItems(self, requestor, target, nodeIdentifier=''):
073161f6f143 namespace delegation: disco nesting management
Goffi <goffi@goffi.org>
parents: 287
diff changeset
268 return []
346
3bbab2173ebc implemented disco items:
Goffi <goffi@goffi.org>
parents: 334
diff changeset
269
3bbab2173ebc implemented disco items:
Goffi <goffi@goffi.org>
parents: 334
diff changeset
270
3bbab2173ebc implemented disco items:
Goffi <goffi@goffi.org>
parents: 334
diff changeset
271 # we monkeypatch DiscoHandler to add delegation informations
3bbab2173ebc implemented disco items:
Goffi <goffi@goffi.org>
parents: 334
diff changeset
272 def _onDiscoItems(self, iq):
3bbab2173ebc implemented disco items:
Goffi <goffi@goffi.org>
parents: 334
diff changeset
273 request = disco._DiscoRequest.fromElement(iq)
3bbab2173ebc implemented disco items:
Goffi <goffi@goffi.org>
parents: 334
diff changeset
274 # it's really ugly to attach pep data to recipient
3bbab2173ebc implemented disco items:
Goffi <goffi@goffi.org>
parents: 334
diff changeset
275 # but we don't have many options
3bbab2173ebc implemented disco items:
Goffi <goffi@goffi.org>
parents: 334
diff changeset
276 request.recipient.pep = iq.delegated
3bbab2173ebc implemented disco items:
Goffi <goffi@goffi.org>
parents: 334
diff changeset
277
3bbab2173ebc implemented disco items:
Goffi <goffi@goffi.org>
parents: 334
diff changeset
278 def toResponse(items):
3bbab2173ebc implemented disco items:
Goffi <goffi@goffi.org>
parents: 334
diff changeset
279 response = disco.DiscoItems()
3bbab2173ebc implemented disco items:
Goffi <goffi@goffi.org>
parents: 334
diff changeset
280 response.nodeIdentifier = request.nodeIdentifier
3bbab2173ebc implemented disco items:
Goffi <goffi@goffi.org>
parents: 334
diff changeset
281
3bbab2173ebc implemented disco items:
Goffi <goffi@goffi.org>
parents: 334
diff changeset
282 for item in items:
3bbab2173ebc implemented disco items:
Goffi <goffi@goffi.org>
parents: 334
diff changeset
283 response.append(item)
3bbab2173ebc implemented disco items:
Goffi <goffi@goffi.org>
parents: 334
diff changeset
284
3bbab2173ebc implemented disco items:
Goffi <goffi@goffi.org>
parents: 334
diff changeset
285 return response.toElement()
3bbab2173ebc implemented disco items:
Goffi <goffi@goffi.org>
parents: 334
diff changeset
286
3bbab2173ebc implemented disco items:
Goffi <goffi@goffi.org>
parents: 334
diff changeset
287 d = self.items(request.sender, request.recipient,
3bbab2173ebc implemented disco items:
Goffi <goffi@goffi.org>
parents: 334
diff changeset
288 request.nodeIdentifier)
3bbab2173ebc implemented disco items:
Goffi <goffi@goffi.org>
parents: 334
diff changeset
289 d.addCallback(toResponse)
3bbab2173ebc implemented disco items:
Goffi <goffi@goffi.org>
parents: 334
diff changeset
290 return d
3bbab2173ebc implemented disco items:
Goffi <goffi@goffi.org>
parents: 334
diff changeset
291
3bbab2173ebc implemented disco items:
Goffi <goffi@goffi.org>
parents: 334
diff changeset
292
3bbab2173ebc implemented disco items:
Goffi <goffi@goffi.org>
parents: 334
diff changeset
293 disco.DiscoHandler._onDiscoItems = _onDiscoItems