This file is indexed.

/usr/share/pyshared/wokkel/generic.py is in python-wokkel 0.7.1-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
# -*- test-case-name: wokkel.test.test_generic -*-
#
# Copyright (c) Ralph Meijer.
# See LICENSE for details.

"""
Generic XMPP protocol helpers.
"""

from encodings import idna

from zope.interface import implements

from twisted.internet import defer, protocol
from twisted.python import reflect
from twisted.words.protocols.jabber import error, jid, xmlstream
from twisted.words.protocols.jabber.xmlstream import toResponse
from twisted.words.xish import domish, utility
from twisted.words.xish.xmlstream import BootstrapMixin

from wokkel.iwokkel import IDisco
from wokkel.subprotocols import XMPPHandler

IQ_GET = '/iq[@type="get"]'
IQ_SET = '/iq[@type="set"]'

NS_VERSION = 'jabber:iq:version'
VERSION = IQ_GET + '/query[@xmlns="' + NS_VERSION + '"]'

def parseXml(string):
    """
    Parse serialized XML into a DOM structure.

    @param string: The serialized XML to be parsed, UTF-8 encoded.
    @type string: C{str}.
    @return: The DOM structure, or C{None} on empty or incomplete input.
    @rtype: L{domish.Element}
    """
    roots = []
    results = []
    elementStream = domish.elementStream()
    elementStream.DocumentStartEvent = roots.append
    elementStream.ElementEvent = lambda elem: roots[0].addChild(elem)
    elementStream.DocumentEndEvent = lambda: results.append(roots[0])
    elementStream.parse(string)
    return results and results[0] or None



def stripNamespace(rootElement):
    namespace = rootElement.uri

    def strip(element):
        if element.uri == namespace:
            element.uri = None
            if element.defaultUri == namespace:
                element.defaultUri = None
            for child in element.elements():
                strip(child)

    if namespace is not None:
        strip(rootElement)

    return rootElement



class FallbackHandler(XMPPHandler):
    """
    XMPP subprotocol handler that catches unhandled iq requests.

    Unhandled iq requests are replied to with a service-unavailable stanza
    error.
    """

    def connectionInitialized(self):
        self.xmlstream.addObserver(IQ_SET, self.iqFallback, -1)
        self.xmlstream.addObserver(IQ_GET, self.iqFallback, -1)

    def iqFallback(self, iq):
        if iq.handled == True:
            return

        reply = error.StanzaError('service-unavailable')
        self.xmlstream.send(reply.toResponse(iq))



class VersionHandler(XMPPHandler):
    """
    XMPP subprotocol handler for XMPP Software Version.

    This protocol is described in
    U{XEP-0092<http://xmpp.org/extensions/xep-0092.html>}.
    """

    implements(IDisco)

    def __init__(self, name, version):
        self.name = name
        self.version = version

    def connectionInitialized(self):
        self.xmlstream.addObserver(VERSION, self.onVersion)

    def onVersion(self, iq):
        response = toResponse(iq, "result")

        query = response.addElement((NS_VERSION, "query"))
        query.addElement("name", content=self.name)
        query.addElement("version", content=self.version)
        self.send(response)

        iq.handled = True

    def getDiscoInfo(self, requestor, target, node):
        info = set()

        if not node:
            from wokkel import disco
            info.add(disco.DiscoFeature(NS_VERSION))

        return defer.succeed(info)

    def getDiscoItems(self, requestor, target, node):
        return defer.succeed([])



class XmlPipe(object):
    """
    XML stream pipe.

    Connects two objects that communicate stanzas through an XML stream like
    interface. Each of the ends of the pipe (sink and source) can be used to
    send XML stanzas to the other side, or add observers to process XML stanzas
    that were sent from the other side.

    XML pipes are usually used in place of regular XML streams that are
    transported over TCP. This is the reason for the use of the names source
    and sink for both ends of the pipe. The source side corresponds with the
    entity that initiated the TCP connection, whereas the sink corresponds with
    the entity that accepts that connection. In this object, though, the source
    and sink are treated equally.

    Unlike Jabber
    L{XmlStream<twisted.words.protocols.jabber.xmlstream.XmlStream>}s, the sink
    and source objects are assumed to represent an eternal connected and
    initialized XML stream. As such, events corresponding to connection,
    disconnection, initialization and stream errors are not dispatched or
    processed.

    @ivar source: Source XML stream.
    @ivar sink: Sink XML stream.
    """

    def __init__(self):
        self.source = utility.EventDispatcher()
        self.sink = utility.EventDispatcher()
        self.source.send = lambda obj: self.sink.dispatch(obj)
        self.sink.send = lambda obj: self.source.dispatch(obj)



class Stanza(object):
    """
    Abstract representation of a stanza.

    @ivar sender: The sending entity.
    @type sender: L{jid.JID}
    @ivar recipient: The receiving entity.
    @type recipient: L{jid.JID}
    """

    recipient = None
    sender = None
    stanzaKind = None
    stanzaID = None
    stanzaType = None

    def __init__(self, recipient=None, sender=None):
        self.recipient = recipient
        self.sender = sender


    @classmethod
    def fromElement(Class, element):
        """
        Create a stanza from a L{domish.Element}.
        """
        stanza = Class()
        stanza.parseElement(element)
        return stanza


    def parseElement(self, element):
        """
        Parse the stanza element.

        This is called with the stanza's element when a L{Stanza} is
        created using L{fromElement}. It parses the stanza's core attributes
        (addressing, type and id), strips the namespace from the stanza
        element for easier transport across streams and passes on
        child elements for further parsing.

        Child element parsers are defined by providing a C{childParsers}
        attribute on a subclass, as a mapping from (URI, name) to the name
        of the handler on C{self}. C{parseElement} will accumulate
        C{childParsers} from its class hierarchy, iterate over the child
        elements and pass it to matching handlers based on the child element's
        URI and name. The special key of C{None} can be used to pass all
        child elements to.
        """
        if element.hasAttribute('from'):
            self.sender = jid.internJID(element['from'])
        if element.hasAttribute('to'):
            self.recipient = jid.internJID(element['to'])
        self.stanzaType = element.getAttribute('type')
        self.stanzaID = element.getAttribute('id')

        # Save element
        stripNamespace(element)
        self.element = element

        # accumulate all childHandlers in the class hierarchy of Class 
        handlers = {}
        reflect.accumulateClassDict(self.__class__, 'childParsers', handlers)

        for child in element.elements():
            try:
                handler = handlers[child.uri, child.name]
            except KeyError:
                try:
                    handler = handlers[None]
                except KeyError:
                    continue

            getattr(self, handler)(child)


    def toElement(self):
        element = domish.Element((None, self.stanzaKind))
        if self.sender is not None:
            element['from'] = self.sender.full()
        if self.recipient is not None:
            element['to'] = self.recipient.full()
        if self.stanzaType:
            element['type'] = self.stanzaType
        if self.stanzaID:
            element['id'] = self.stanzaID
        return element



class ErrorStanza(Stanza):

    def parseElement(self, element):
        Stanza.parseElement(self, element)
        self.exception = error.exceptionFromStanza(element)



class Request(Stanza):
    """
    IQ request stanza.

    This is a base class for IQ get or set stanzas, to be used with
    L{wokkel.subprotocols.StreamManager.request}.
    """

    stanzaKind = 'iq'
    stanzaType = 'get'
    timeout = None

    childParsers = {None: 'parseRequest'}

    def __init__(self, recipient=None, sender=None, stanzaType='get'):
        Stanza.__init__(self, recipient=recipient, sender=sender)
        self.stanzaType = stanzaType


    def parseRequest(self, element):
        """
        Called with the request's child element for parsing.

        When a request instance is created using L{fromElement}, this method
        is called with the child element of the iq. Override this method for
        parsing the request's payload.
        """


    def toElement(self):
        element = Stanza.toElement(self)

        if not self.stanzaID:
            element.addUniqueId()
            self.stanzaID = element['id']

        return element



class DeferredXmlStreamFactory(BootstrapMixin, protocol.ClientFactory):
    protocol = xmlstream.XmlStream

    def __init__(self, authenticator):
        BootstrapMixin.__init__(self)

        self.authenticator = authenticator

        deferred = defer.Deferred()
        self.deferred = deferred
        self.addBootstrap(xmlstream.STREAM_AUTHD_EVENT, self.deferred.callback)
        self.addBootstrap(xmlstream.INIT_FAILED_EVENT, deferred.errback)


    def buildProtocol(self, addr):
        """
        Create an instance of XmlStream.

        A new authenticator instance will be created and passed to the new
        XmlStream. Registered bootstrap event observers are installed as well.
        """
        xs = self.protocol(self.authenticator)
        xs.factory = self
        self.installBootstraps(xs)
        return xs


    def clientConnectionFailed(self, connector, reason):
        self.deferred.errback(reason)



def prepareIDNName(name):
    """
    Encode a unicode IDN Domain Name into its ACE equivalent.

    This will encode the domain labels, separated by allowed dot code points,
    to their ASCII Compatible Encoding (ACE) equivalent, using punycode. The
    result is an ASCII byte string of the encoded labels, separated by the
    standard full stop.
    """
    result = []
    labels = idna.dots.split(name)

    if labels and len(labels[-1]) == 0:
        trailing_dot = b'.'
        del labels[-1]
    else:
        trailing_dot = b''

    for label in labels:
        result.append(idna.ToASCII(label))

    return b'.'.join(result) + trailing_dot