source: wokkel/generic.py @ 30:68535ae85c8d

Last change on this file since 30:68535ae85c8d was 30:68535ae85c8d, checked in by Ralph Meijer <ralphm@…>, 13 years ago

Add support for pubsub collections.

File size: 3.2 KB
Line 
1# -*- test-case-name: wokkel.test.test_generic -*-
2#
3# Copyright (c) 2003-2008 Ralph Meijer
4# See LICENSE for details.
5
6"""
7Generic XMPP protocol helpers.
8"""
9
10from zope.interface import implements
11
12from twisted.internet import defer
13from twisted.words.protocols.jabber import error
14from twisted.words.protocols.jabber.xmlstream import toResponse
15from twisted.words.xish import domish
16
17from wokkel import disco
18from wokkel.iwokkel import IDisco
19from wokkel.subprotocols import XMPPHandler
20
21IQ_GET = '/iq[@type="get"]'
22IQ_SET = '/iq[@type="set"]'
23
24NS_VERSION = 'jabber:iq:version'
25VERSION = IQ_GET + '/query[@xmlns="' + NS_VERSION + '"]'
26
27def parseXml(string):
28    """
29    Parse serialized XML into a DOM structure.
30
31    @param string: The serialized XML to be parsed, UTF-8 encoded.
32    @type string: C{str}.
33    @return: The DOM structure, or C{None} on empty or incomplete input.
34    @rtype: L{domish.Element}
35    """
36    roots = []
37    results = []
38    elementStream = domish.elementStream()
39    elementStream.DocumentStartEvent = roots.append
40    elementStream.ElementEvent = lambda elem: roots[0].addChild(elem)
41    elementStream.DocumentEndEvent = lambda: results.append(roots[0])
42    elementStream.parse(string)
43    return results and results[0] or None
44
45
46
47def stripNamespace(rootElement):
48    namespace = rootElement.uri
49
50    def strip(element):
51        if element.uri == namespace:
52            element.uri = None
53            if element.defaultUri == namespace:
54                element.defaultUri = None
55            for child in element.elements():
56                strip(child)
57
58    if namespace is not None:
59        strip(rootElement)
60
61    return rootElement
62
63
64
65class FallbackHandler(XMPPHandler):
66    """
67    XMPP subprotocol handler that catches unhandled iq requests.
68
69    Unhandled iq requests are replied to with a service-unavailable stanza
70    error.
71    """
72
73    def connectionInitialized(self):
74        self.xmlstream.addObserver(IQ_SET, self.iqFallback, -1)
75        self.xmlstream.addObserver(IQ_GET, self.iqFallback, -1)
76
77    def iqFallback(self, iq):
78        if iq.handled == True:
79            return
80
81        reply = error.StanzaError('service-unavailable')
82        self.xmlstream.send(reply.toResponse(iq))
83
84
85
86class VersionHandler(XMPPHandler):
87    """
88    XMPP subprotocol handler for XMPP Software Version.
89
90    This protocol is described in
91    U{XEP-0092<http://www.xmpp.org/extensions/xep-0092.html>}.
92    """
93
94    implements(IDisco)
95
96    def __init__(self, name, version):
97        self.name = name
98        self.version = version
99
100    def connectionInitialized(self):
101        self.xmlstream.addObserver(VERSION, self.onVersion)
102
103    def onVersion(self, iq):
104        response = toResponse(iq, "result")
105
106        query = response.addElement((NS_VERSION, "query"))
107        name = query.addElement("name", content=self.name)
108        version = query.addElement("version", content=self.version)
109        self.send(response)
110
111        iq.handled = True
112
113    def getDiscoInfo(self, requestor, target, node):
114        info = set()
115
116        if not node:
117            info.add(disco.DiscoFeature(NS_VERSION))
118
119        return defer.succeed(info)
120
121    def getDiscoItems(self, requestor, target, node):
122        return defer.succeed([])
Note: See TracBrowser for help on using the repository browser.