예제 #1
0
파일: stanza.py 프로젝트: mathieui/slixmpp
    def get_body(self, lang=None):
        """Return the contents of the HTML body."""
        if lang is None:
            lang = self.get_lang()

        bodies = self.xml.findall('{%s}body' % XHTML_NS)

        if lang == '*':
            result = OrderedDict()
            for body in bodies:
                body_lang = body.attrib.get('{%s}lang' % self.xml_ns, '')
                body_result = []
                body_result.append(body.text if body.text else '')
                for child in body:
                    body_result.append(tostring(child, xmlns=XHTML_NS))
                body_result.append(body.tail if body.tail else '')
                result[body_lang] = ''.join(body_result)
            return result
        else:
            for body in bodies:
                if body.attrib.get('{%s}lang' % self.xml_ns, self.get_lang()) == lang:
                    result = []
                    result.append(body.text if body.text else '')
                    for child in body:
                        result.append(tostring(child, xmlns=XHTML_NS))
                    result.append(body.tail if body.tail else '')
                    return ''.join(result)
        return ''
예제 #2
0
    def send_xml(self, data):
        """Send an XML object on the stream

        :param data: The :class:`~xml.etree.ElementTree.Element` XML object
                     to send on the stream.
        """
        return self.send(tostring(data))
예제 #3
0
    def send(self, data, use_filters=True):
        """A wrapper for :meth:`send_raw()` for sending stanza objects.

        May optionally block until an expected response is received.

        :param data: The :class:`~slixmpp.xmlstream.stanzabase.ElementBase`
                     stanza to send on the stream.
        :param bool use_filters: Indicates if outgoing filters should be
                                 applied to the given stanza data. Disabling
                                 filters is useful when resending stanzas.
                                 Defaults to ``True``.
        """
        if isinstance(data, ElementBase):
            if use_filters:
                for filter in self.__filters['out']:
                    data = filter(data)
                    if data is None:
                        return

        if isinstance(data, ElementBase):
            if use_filters:
                for filter in self.__filters['out_sync']:
                    data = filter(data)
                    if data is None:
                        return
            str_data = tostring(data.xml,
                                xmlns=self.default_ns,
                                stream=self,
                                top_level=True)
            self.send_raw(str_data)
        else:
            self.send_raw(data)
예제 #4
0
    def send(self, data, use_filters=True):
        """A wrapper for :meth:`send_raw()` for sending stanza objects.

        May optionally block until an expected response is received.

        :param data: The :class:`~slixmpp.xmlstream.stanzabase.ElementBase`
                     stanza to send on the stream.
        :param bool use_filters: Indicates if outgoing filters should be
                                 applied to the given stanza data. Disabling
                                 filters is useful when resending stanzas.
                                 Defaults to ``True``.
        """
        if isinstance(data, ElementBase):
            if use_filters:
                for filter in self.__filters['out']:
                    data = filter(data)
                    if data is None:
                        return

        if isinstance(data, ElementBase):
            if use_filters:
                for filter in self.__filters['out_sync']:
                    data = filter(data)
                    if data is None:
                        return
            str_data = tostring(data.xml, xmlns=self.default_ns,
                                          stream=self,
                                          top_level=True)
            self.send_raw(str_data)
        else:
            self.send_raw(data)
예제 #5
0
    async def _continue_slow_send(
            self,
            task: asyncio.Task,
            already_used: Set[Callable[[ElementBase], Optional[StanzaBase]]]
    ) -> None:
        """
        Used when an item in the send queue has taken too long to process.

        This is away from the send queue and can take as much time as needed.
        :param asyncio.Task task: the Task wrapping the coroutine
        :param set already_used: Filters already used on this outgoing stanza
        """
        data = await task
        self.__slow_tasks.remove(task)
        for filter in self.__filters['out']:
            if filter in already_used:
                continue
            if iscoroutinefunction(filter):
                data = await task
            else:
                data = filter(data)
            if data is None:
                return

        if isinstance(data, ElementBase):
            for filter in self.__filters['out_sync']:
                data = filter(data)
                if data is None:
                    return
            str_data = tostring(data.xml, xmlns=self.default_ns,
                                stream=self, top_level=True)
            self.send_raw(str_data)
        else:
            self.send_raw(data)
예제 #6
0
    def send_xml(self, data):
        """Send an XML object on the stream

        :param data: The :class:`~xml.etree.ElementTree.Element` XML object
                     to send on the stream.
        """
        return self.send(tostring(data))
예제 #7
0
 async def get(self):
     try:
         result = await self['xep_0060'].get_item(self.pubsub_server, self.node, self.data)
         for item in result['pubsub']['items']['substanzas']:
             logging.info('Retrieved item %s: %s', item['id'], tostring(item['payload']))
     except XMPPError as error:
         logging.error('Could not retrieve item %s from node %s: %s', self.data, self.node, error.format())
예제 #8
0
    def data_received(self, data):
        """Called when incoming data is received on the socket.

        We feed that data to the parser and the see if this produced any XML
        event.  This could trigger one or more event (a stanza is received,
        the stream is opened, etc).
        """
        self.parser.feed(data)
        for event, xml in self.parser.read_events():
            if event == 'start':
                if self.xml_depth == 0:
                    # We have received the start of the root element.
                    self.xml_root = xml
                    log.debug('RECV: %s', highlight(tostring(self.xml_root, xmlns=self.default_ns,
                                                         stream=self,
                                                         top_level=True,
                                                         open_only=True)))
                    self.start_stream_handler(self.xml_root)
                self.xml_depth += 1
            if event == 'end':
                self.xml_depth -= 1
                if self.xml_depth == 0:
                    # The stream's root element has closed,
                    # terminating the stream.
                    log.debug("End of stream received")
                    self.abort()
                elif self.xml_depth == 1:
                    # A stanza is an XML element that is a direct child of
                    # the root element, hence the check of depth == 1
                    self.loop.idle_call(functools.partial(self.__spawn_event, xml))
                    if self.xml_root is not None:
                        # Keep the root element empty of children to
                        # save on memory use.
                        self.xml_root.clear()
예제 #9
0
 def get(self):
     future, callback = make_callback()
     try:
         self["xep_0060"].get_item(self.pubsub_server, self.node, self.data, callback=callback)
         result = yield from future
         for item in result["pubsub"]["items"]["substanzas"]:
             print("Retrieved item %s: %s" % (item["id"], tostring(item["payload"])))
     except:
         logging.error("Could not retrieve item %s from node %s" % (self.data, self.node))
예제 #10
0
 async def get(self):
     try:
         result = await self['xep_0060'].get_item(self.pubsub_server,
                                                  self.node, self.data)
         for item in result['pubsub']['items']['substanzas']:
             logging.info('Retrieved item %s: %s', item['id'],
                          tostring(item['payload']))
     except XMPPError as error:
         logging.error('Could not retrieve item %s from node %s: %s',
                       self.data, self.node, error.format())
예제 #11
0
 def send_body_to(self, consumer):
     if self.bosh_wait:
         consumer.wait_handle.cancel()
     xml = self.current_body.xml
     self.current_body = None
     ack = self.rid_in - 1
     if ack != consumer.rid:
         xml.attrib['ack'] = str(ack)
     data = tostring(xml, top_level=True)
     self.send_to_consumer(consumer, data)
예제 #12
0
 def _publish(self, msg):
     """Handle receiving a publish item event."""
     print('Published item %s to %s:' % (
         msg['pubsub_event']['items']['item']['id'],
         msg['pubsub_event']['items']['node']))
     data = msg['pubsub_event']['items']['item']['payload']
     if data is not None:
         print(tostring(data))
     else:
         print('No item content')
예제 #13
0
 def _publish(self, msg):
     """Handle receiving a publish item event."""
     print('Published item %s to %s:' %
           (msg['pubsub_event']['items']['item']['id'],
            msg['pubsub_event']['items']['node']))
     data = msg['pubsub_event']['items']['item']['payload']
     if data is not None:
         print(tostring(data))
     else:
         print('No item content')
예제 #14
0
    def data_received(self, data):
        """Called when incoming data is received on the socket.

        We feed that data to the parser and the see if this produced any XML
        event.  This could trigger one or more event (a stanza is received,
        the stream is opened, etc).
        """
        if self.parser is None:
            log.warning(
                'Received data before the connection is established: %r', data)
            return
        self.parser.feed(data)
        try:
            for event, xml in self.parser.read_events():
                if event == 'start':
                    if self.xml_depth == 0:
                        # We have received the start of the root element.
                        self.xml_root = xml
                        log.debug(
                            'RECV: %s',
                            tostring(self.xml_root,
                                     xmlns=self.default_ns,
                                     stream=self,
                                     top_level=True,
                                     open_only=True))
                        self.start_stream_handler(self.xml_root)
                    self.xml_depth += 1
                if event == 'end':
                    self.xml_depth -= 1
                    if self.xml_depth == 0:
                        # The stream's root element has closed,
                        # terminating the stream.
                        self.end_session_on_disconnect = True
                        log.debug("End of stream received")
                        self.disconnect_reason = "End of stream"
                        self.abort()
                    elif self.xml_depth == 1:
                        # A stanza is an XML element that is a direct child of
                        # the root element, hence the check of depth == 1
                        self._spawn_event(xml)
                        if self.xml_root is not None:
                            # Keep the root element empty of children to
                            # save on memory use.
                            self.xml_root.clear()
        except ET.ParseError:
            log.error('Parse error: %r', data)

            # Due to cyclic dependencies, this can’t be imported at the module
            # level.
            from slixmpp.stanza.stream_error import StreamError
            error = StreamError()
            error['condition'] = 'not-well-formed'
            error['text'] = 'Server sent: %r' % data
            self.send(error)
            self.disconnect()
예제 #15
0
    def data_received(self, data):
        """Called when incoming data is received on the socket.

        We feed that data to the parser and the see if this produced any XML
        event.  This could trigger one or more event (a stanza is received,
        the stream is opened, etc).
        """
        if self.parser is None:
            log.warning('Received data before the connection is established: %r',
                        data)
            return
        self.parser.feed(data)
        try:
            for event, xml in self.parser.read_events():
                if event == 'start':
                    if self.xml_depth == 0:
                        # We have received the start of the root element.
                        self.xml_root = xml
                        log.debug('RECV: %s', tostring(self.xml_root,
                                                       xmlns=self.default_ns,
                                                       stream=self,
                                                       top_level=True,
                                                       open_only=True))
                        self.start_stream_handler(self.xml_root)
                    self.xml_depth += 1
                if event == 'end':
                    self.xml_depth -= 1
                    if self.xml_depth == 0:
                        # The stream's root element has closed,
                        # terminating the stream.
                        self.end_session_on_disconnect = True
                        log.debug("End of stream received")
                        self.disconnect_reason = "End of stream"
                        self.abort()
                    elif self.xml_depth == 1:
                        # A stanza is an XML element that is a direct child of
                        # the root element, hence the check of depth == 1
                        self._spawn_event(xml)
                        if self.xml_root is not None:
                            # Keep the root element empty of children to
                            # save on memory use.
                            self.xml_root.clear()
        except ET.ParseError:
            log.error('Parse error: %r', data)

            # Due to cyclic dependencies, this can’t be imported at the module
            # level.
            from slixmpp.stanza.stream_error import StreamError
            error = StreamError()
            error['condition'] = 'not-well-formed'
            error['text'] = 'Server sent: %r' % data
            self.send(error)
            self.disconnect()
예제 #16
0
 async def ipc_reply(self, type, channel, xml):
     if self.ipc_logger.isEnabledFor(logging.DEBUG):
         self.ipc_logger.debug("IPC-Reply type %s from %s to [%s]: %s",
                               type, self.boundjid, channel,
                               tostring(xml))
     await self.channel_layer.send(
         channel, {
             'type': type,
             'origin': self.channel_name,
             'from': self.boundjid.full,
             'xml': xml,
         })
예제 #17
0
    def send_message(self, mto, mbody, msubject=None, mtype=None,
                     mhtml=None, mfrom=None, mnick=None):

        # wild hack that is necessary
        body = mbody.replace("\r", "
\n")
        message = self.make_message(mto=mto, mfrom=mfrom, mbody=body)
        message['lang'] = None
        str_data = tostring(message.xml, xmlns=message.stream.default_ns,
                            stream=message.stream,
                            top_level=True)
        str_data = str_data.replace("
", "
")
        message.stream.send_raw(str_data)
예제 #18
0
 async def ipc_send(self, type, target, xml):
     group_name = self.group_for_user(target)
     if self.ipc_logger.isEnabledFor(logging.DEBUG):
         self.ipc_logger.debug("IPC-Send type %s from %s [%s] to %s: %s",
                               type, self.boundjid, self.channel_name,
                               target.bare, tostring(xml))
     await self.channel_layer.group_send(
         group_name, {
             'type': type,
             'origin': self.channel_name,
             'from': self.boundjid.full,
             'xml': xml,
         })
예제 #19
0
    async def run_filters(self):
        """
        Background loop that processes stanzas to send.
        """
        while True:
            (data, use_filters) = await self.waiting_queue.get()
            try:
                if isinstance(data, ElementBase):
                    if use_filters:
                        already_run_filters = set()
                        for filter in self.__filters['out']:
                            already_run_filters.add(filter)
                            if iscoroutinefunction(filter):
                                task = asyncio.create_task(filter(data))
                                completed, pending = await wait(
                                    {task},
                                    timeout=1,
                                )
                                if pending:
                                    self.slow_tasks.append(task)
                                    asyncio.ensure_future(
                                        self._continue_slow_send(
                                            task,
                                            already_run_filters
                                        ),
                                        loop=self.loop,
                                    )
                                    raise Exception("Slow coro, rescheduling")
                                data = task.result()
                            else:
                                data = filter(data)
                            if data is None:
                                raise ContinueQueue('Empty stanza')

                if isinstance(data, ElementBase):
                    if use_filters:
                        for filter in self.__filters['out_sync']:
                            data = filter(data)
                            if data is None:
                                raise ContinueQueue('Empty stanza')
                    str_data = tostring(data.xml, xmlns=self.default_ns,
                                        stream=self, top_level=True)
                    self.send_raw(str_data)
                else:
                    self.send_raw(data)
            except ContinueQueue as exc:
                log.debug('Stanza in send queue not sent: %s', exc)
            except Exception:
                log.error('Exception raised in send queue:', exc_info=True)
            self.waiting_queue.task_done()
예제 #20
0
 async def _set_presence(self, msg):
     msg['from'] = self.stream.boundjid.full
     initial = not self.available
     self.last_presence = msg
     self.available = True
     await self.stream.session_hook.set_presence(msg['priority'],
                                                 tostring(msg.xml))
     # clients usually get the roster before becoming
     # available, so use cached roster if possible
     roster = self.stream.roster.cached
     if roster is None:
         roster = await self.stream.roster_hook.get_contacts(self.stream.boundjid)
     await self._broadcast_presence(msg, roster, initial)
     if initial:
         await self._remind_pending()
예제 #21
0
 async def _ipc_received(self, msg):
     type = msg['type']
     xml = msg['xml']
     origin = msg['origin']
     ifrom = msg['from']
     if self.ipc_logger.isEnabledFor(logging.DEBUG):
         self.ipc_logger.debug("IPC-Receive type %s from %s [%s]: %s",
                               type, ifrom, origin,
                               tostring(xml))
     try:
         attrs = type.split('.')
         target = self
         for attr in attrs[:-1]:
             target = getattr(target, attr)
         target = getattr(target, 'ipc_recv_' + attrs[-1])
         await target(origin, ifrom, xml)
     except Exception as e:
         self.exception(e)
예제 #22
0
 async def _outbound_subscribe(self, msg):
     try:
         if self.stream.kicked:
             raise XMPPError('forbidden')
         user = self.stream.boundjid
         contact = msg['to']
         msg['from'] = user.bare
         if contact.resource:
             # 'to' field must be bare
             contact.resource = ''
             msg['to'] = contact
         if contact.user == '':
             # the request might be addressed to a nickname;
             # I haven't found any reference for that actually
             # being allowed, so for now, treat that as a
             # query for a username on the local server.
             contact.user = contact.domain
             contact.domain = self.stream.host
             msg['to'] = contact
         stanza_out = tostring(msg.xml)
         values = (await self.stream.roster_hook.
                   outbound_subscribe(user, contact,
                                      stanza_out))
         # Even if we're already subscribed, the RFC doesn't say not to
         # forward the stanza (maybe in case the remote server didn't receive
         # a previous subscribe?), so we're only going to suppress the
         # roster push (after all, the roster wouldn't have changed).
         if self.stream.is_local(contact.domain):
             if not await self.stream.auth_hook.valid_contact(contact.user):
                 reply = msg.reply()
                 reply['error']['condition'] = 'item-not-found'
                 reply.send()
                 return
             await self._inbound_subscribe(msg.xml, contact, user,
                                           stanza_out)
         elif not self._remote_server(msg):
             return
         if values is not None:
             await self.stream.roster.send_push(user, contact, values)
     except Exception as e:
         msg.exception(e)
         return
예제 #23
0
async def handle_bosh(consumer, xml):
    if 'sid' not in xml.attrib:
        stream = BOSHStream()
        stream.http_host = consumer.http_host
        stream.http_origin = consumer.http_origin
        stream.trust_origin = consumer.is_trusted()
        if stream.trust_origin:
            stream.web_user = await consumer.get_user()
    else:
        stream = get_local_stream(xml.attrib['sid'])
        if not stream:
            # stream is gone
            reply = BOSHBody()
            reply['type'] = 'terminate'
            reply['condition'] = 'remote-connection-failed'
            await consumer.send_data(tostring(reply.xml, top_level=True),
                                     build_headers(origin=consumer.http_origin,
                                                   trust=consumer.is_trusted()))
            return
        if stream.http_host != consumer.http_host:
            # We're going to consider an unexpected host fishy,
            # perhaps there's a man-in-the-middle attack or something.
            await consumer.send_response(status=403)
            return
        elif not stream.bosh_started and not consumer.http_origin:
            # On the first BOSH request, if it seems the browser
            # don't think it's necessary to send us origin headers,
            # don't expect them for future requests either.
            stream.http_origin = None
        elif stream.http_origin != consumer.http_origin:
            # Possible stream hijacking attempt. We'll just tell
            # the browser what origin we accept, it'll do the rest.
            await consumer.send_response(stream.http_headers)
            return
    consumer.stream = stream
    stream.add_consumer_threadsafe(consumer, xml)
예제 #24
0
 def send_element(self, xml):
     self.send_raw(tostring(xml, xmlns=self.default_ns,
                            stream=self, top_level=True))
예제 #25
0
def get_empty_body():
    return tostring(BOSHBody().xml, top_level=True)
예제 #26
0
def get_recoverable_body():
    body = BOSHBody()
    body['type'] = 'error'
    return tostring(body.xml, top_level=True)
예제 #27
0
파일: markup.py 프로젝트: mathieui/slixmpp
    def to_xhtml_im(self, body, markup_elem):
        chunks = self._split_first_level(body, markup_elem)
        final = []
        stack = []
        for chunk in chunks:
            if isinstance(chunk, str):
                chunk = (chunk.replace("&", '&')
                              .replace('<', '&lt;')
                              .replace('>', '&gt;')
                              .replace('"', '&quot;')
                              .replace("'", '&apos;')
                              .replace('\n', '<br/>'))
                final.append(chunk)
                continue
            num_end = 0
            for elem in chunk:
                if isinstance(elem, End):
                    num_end += 1

            for i in range(num_end):
                stack_top = stack.pop()
                for elem in chunk:
                    if not isinstance(elem, End):
                        continue
                    elem = elem.elem
                    if elem is stack_top:
                        if isinstance(elem, Span):
                            final.append('</span>')
                        elif isinstance(elem, BlockCode):
                            final.append('</code></pre>')
                        elif isinstance(elem, List):
                            final.append('</ul>')
                        elif isinstance(elem, Li):
                            final.append('</li>')
                        elif isinstance(elem, BlockQuote):
                            final.append('</blockquote>')
                        break
                else:
                    assert False
            for elem in chunk:
                if not isinstance(elem, Start):
                    continue
                elem = elem.elem
                stack.append(elem)
                if isinstance(elem, Span):
                    style = []
                    for type_ in elem['types']:
                        if type_ == 'emphasis':
                            style.append('font-style: italic;')
                        if type_ == 'code':
                            style.append('font-family: monospace;')
                        if type_ == 'deleted':
                            style.append('text-decoration: line-through;')
                    final.append("<span style='%s'>" % ' '.join(style))
                elif isinstance(elem, BlockCode):
                    final.append('<pre><code>')
                elif isinstance(elem, List):
                    final.append('<ul>')
                elif isinstance(elem, Li):
                    final.append('<li>')
                elif isinstance(elem, BlockQuote):
                    final.append('<blockquote>')
        p = "<p xmlns='http://www.w3.org/1999/xhtml'>%s</p>" % ''.join(final)
        p2 = ET.fromstring(p)
        print('coucou', p, tostring(p2))
        xhtml_im = XHTML_IM()
        xhtml_im['body'] = p2
        return xhtml_im
예제 #28
0
    def to_xhtml_im(self, body, markup_elem):
        chunks = self._split_first_level(body, markup_elem)
        final = []
        stack = []
        for chunk in chunks:
            if isinstance(chunk, str):
                chunk = (chunk.replace("&", '&amp;').replace(
                    '<',
                    '&lt;').replace('>',
                                    '&gt;').replace('"', '&quot;').replace(
                                        "'", '&apos;').replace('\n', '<br/>'))
                final.append(chunk)
                continue
            num_end = 0
            for elem in chunk:
                if isinstance(elem, End):
                    num_end += 1

            for i in range(num_end):
                stack_top = stack.pop()
                for elem in chunk:
                    if not isinstance(elem, End):
                        continue
                    elem = elem.elem
                    if elem is stack_top:
                        if isinstance(elem, Span):
                            final.append('</span>')
                        elif isinstance(elem, BlockCode):
                            final.append('</code></pre>')
                        elif isinstance(elem, List):
                            final.append('</ul>')
                        elif isinstance(elem, Li):
                            final.append('</li>')
                        elif isinstance(elem, BlockQuote):
                            final.append('</blockquote>')
                        break
                else:
                    assert False
            for elem in chunk:
                if not isinstance(elem, Start):
                    continue
                elem = elem.elem
                stack.append(elem)
                if isinstance(elem, Span):
                    style = []
                    for type_ in elem['types']:
                        if type_ == 'emphasis':
                            style.append('font-style: italic;')
                        if type_ == 'code':
                            style.append('font-family: monospace;')
                        if type_ == 'deleted':
                            style.append('text-decoration: line-through;')
                    final.append("<span style='%s'>" % ' '.join(style))
                elif isinstance(elem, BlockCode):
                    final.append('<pre><code>')
                elif isinstance(elem, List):
                    final.append('<ul>')
                elif isinstance(elem, Li):
                    final.append('<li>')
                elif isinstance(elem, BlockQuote):
                    final.append('<blockquote>')
        p = "<p xmlns='http://www.w3.org/1999/xhtml'>%s</p>" % ''.join(final)
        p2 = ET.fromstring(p)
        print('coucou', p, tostring(p2))
        xhtml_im = XHTML_IM()
        xhtml_im['body'] = p2
        return xhtml_im
예제 #29
0
 def send_element(self, xml):
     self.send_raw(tostring(xml, top_level=True))