source: wokkel/disco.py @ 6:283b6997cf7d

Last change on this file since 6:283b6997cf7d was 6:283b6997cf7d, checked in by Ralph Meijer <ralphm@…>, 14 years ago

Support services on a JID.

Author: ralphm
Fixes #2.

File size: 4.2 KB
Line 
1# -*- test-case-name: wokkel.test.test_disco -*-
2#
3# Copyright (c) 2003-2007 Ralph Meijer
4# See LICENSE for details.
5
6"""
7XMPP Service Discovery.
8
9The XMPP service discovery protocol is documented in
10U{XEP-0030<http://www.xmpp.org/extensions/xep-0030.html>}.
11"""
12
13from twisted.internet import defer
14from twisted.words.protocols.jabber import error, jid
15from twisted.words.xish import domish
16
17from wokkel.iwokkel import IDisco
18from wokkel.subprotocols import IQHandlerMixin, XMPPHandler
19
20NS = 'http://jabber.org/protocol/disco'
21NS_INFO = NS + '#info'
22NS_ITEMS = NS + '#items'
23
24IQ_GET = '/iq[@type="get"]'
25DISCO_INFO = IQ_GET + '/query[@xmlns="' + NS_INFO + '"]'
26DISCO_ITEMS = IQ_GET + '/query[@xmlns="' + NS_ITEMS + '"]'
27
28class DiscoFeature(domish.Element):
29    """
30    Element representing an XMPP service discovery feature.
31    """
32
33    def __init__(self, feature):
34        domish.Element.__init__(self, (NS_INFO, 'feature'),
35                                attribs={'var': feature})
36
37
38class DiscoIdentity(domish.Element):
39    """
40    Element representing an XMPP service discovery identity.
41    """
42
43    def __init__(self, category, type, name = None):
44        domish.Element.__init__(self, (NS_INFO, 'identity'),
45                                attribs={'category': category,
46                                         'type': type})
47        if name:
48            self['name'] = name
49
50
51class DiscoItem(domish.Element):
52    """
53    Element representing an XMPP service discovery item.
54    """
55
56    def __init__(self, jid, node = None, name = None):
57        domish.Element.__init__(self, (NS_ITEMS, 'item'),
58                                attribs={'jid': jid.full()})
59        if node:
60            self['node'] = node
61
62        if name:
63            self['name'] = name
64
65
66class DiscoHandler(XMPPHandler, IQHandlerMixin):
67    """
68    Protocol implementation for XMPP Service Discovery.
69
70    This handler will listen to XMPP service discovery requests and
71    query the other handlers in L{parent} (see L{XMPPHandlerContainer}) for
72    their identities, features and items according to L{IDisco}.
73    """
74
75    iqHandlers = {DISCO_INFO: '_onDiscoInfo',
76                  DISCO_ITEMS: '_onDiscoItems'}
77
78    def connectionInitialized(self):
79        self.xmlstream.addObserver(DISCO_INFO, self.handleRequest)
80        self.xmlstream.addObserver(DISCO_ITEMS, self.handleRequest)
81
82    def _error(self, failure):
83        failure.trap(defer.FirstError)
84        return failure.value.subFailure
85
86    def _onDiscoInfo(self, iq):
87        requestor = jid.internJID(iq["from"])
88        target = jid.internJID(iq["to"])
89        nodeIdentifier = iq.query.getAttribute("node")
90
91        def toResponse(results):
92            info = []
93            for i in results:
94                info.extend(i[1])
95
96            if nodeIdentifier and not info:
97                raise error.StanzaError('item-not-found')
98            else:
99                response = domish.Element((NS_INFO, 'query'))
100
101                for item in info:
102                    response.addChild(item)
103
104            return response
105
106        dl = []
107        for handler in self.parent:
108            if IDisco.providedBy(handler):
109                dl.append(handler.getDiscoInfo(requestor, target,
110                                               nodeIdentifier))
111
112        d = defer.DeferredList(dl, fireOnOneErrback=1, consumeErrors=1)
113        d.addCallbacks(toResponse, self._error)
114        return d
115
116    def _onDiscoItems(self, iq):
117        requestor = jid.internJID(iq["from"])
118        target = jid.internJID(iq["to"])
119        nodeIdentifier = iq.query.getAttribute("node")
120
121        def toResponse(results):
122            items = []
123            for i in results:
124                items.extend(i[1])
125
126            response = domish.Element((NS_ITEMS, 'query'))
127
128            for item in items:
129                response.addChild(item)
130
131            return response
132
133        dl = []
134        for handler in self.parent:
135            if IDisco.providedBy(handler):
136                dl.append(handler.getDiscoItems(requestor, target,
137                                                nodeIdentifier))
138
139        d = defer.DeferredList(dl, fireOnOneErrback=1, consumeErrors=1)
140        d.addCallbacks(toResponse, self._error)
141        return d
Note: See TracBrowser for help on using the repository browser.