Beispiel #1
0
        def output(data, user):
            log.debug("data: %r" % (data, ))
            to = user.full()

            for msg in data:
                log.debug("msg[%s]=%s" % (msg['id'], msg['stanza'].toXml().encode('utf-8'), ))
                try:
                    """
                    Mark the stanza with our server name, so we'll receive a
                    copy of the receipt
                    """
                    if msg['stanza'].request:
                        msg['stanza'].request['from'] = self.xmlstream.thisEntity.full()
                    elif msg['stanza'].received:
                        msg['stanza'].received['from'] = self.xmlstream.thisEntity.full()

                    # mark delayed delivery
                    if 'timestamp' in msg:
                        delay = msg['stanza'].addElement((xmlstream2.NS_XMPP_DELAY, 'delay'))
                        delay['stamp'] = msg['timestamp'].strftime(xmlstream2.XMPP_STAMP_FORMAT)

                    msg['to'] = to
                    self.send(msg['stanza'])
                    """
                    If a receipt is requested, we won't delete the message from
                    storage now; we must be sure client has received it.
                    Otherwise just delete the message immediately.
                    """
                    if not xmlstream2.extract_receipt(msg['stanza'], 'request') and \
                            not xmlstream2.extract_receipt(stanza, 'received'):
                        self.parent.message_offline_delete(msg['id'], msg['stanza'].name)
                except:
                    log.debug("offline message delivery failed (%s)" % (msg['id'], ))
                    traceback.print_exc()
Beispiel #2
0
    def _local_presence_output(self, data, user):
        log.debug("data: %r" % (data, ))
        # this will be used to set a safe recipient
        # WARNING this will create a JID anyway :(
        jid_to = self.resolveJID(user)
        for msg in data:
            log.debug("msg[%s]=%s" % (msg['id'], msg['stanza'].toXml().encode('utf-8'), ))
            stanza = msg['stanza']
            try:
                """
                Mark the stanza with our server name, so we'll receive a
                copy of the receipt
                """
                if stanza.request:
                    stanza.request['from'] = self.xmlstream.thisEntity.full()
                elif stanza.received:
                    stanza.received['from'] = self.xmlstream.thisEntity.full()

                # mark delayed delivery
                if 'timestamp' in msg:
                    delay = stanza.addElement((xmlstream2.NS_XMPP_DELAY, 'delay'))
                    delay['stamp'] = msg['timestamp'].strftime(xmlstream2.XMPP_STAMP_FORMAT)

                # are we sending a message to a user we have blocked?
                jid_from = jid.JID(stanza['from'])
                if self.is_presence_allowed(jid_to, jid_from) == -1:
                    log.debug("sending message to blocked user, bouncing error")
                    e = error.StanzaError('not-acceptable', 'cancel')
                    errstanza = e.toResponse(msg['stanza'])
                    errstanza.error.addElement((xmlstream2.NS_IQ_BLOCKING_ERRORS, 'blocked'))
                    self.send(errstanza)

                else:
                    # check for permission
                    allowed = self.is_presence_allowed(jid_from, jid_to)
                    if allowed == -1:
                        # user is blocked!
                        log.debug("not allowed to send messages to %s, discarding message" % (stanza['to'], ))
                        self.message_offline_delete(msg['id'], stanza.name)
                    else:
                        """
                        We use direct delivery here: it's faster and does not
                        involve JID resolution
                        """
                        stanza['to'] = jid_to.full()
                        self.dispatch(stanza, hold=(allowed != 1))

                """
                If a receipt is requested, we won't delete the message from
                storage now; we must be sure client has received it.
                Otherwise just delete the message immediately.
                """
                if not xmlstream2.extract_receipt(stanza, 'request') and \
                        not xmlstream2.extract_receipt(stanza, 'received'):
                    self.message_offline_delete(msg['id'], stanza.name)
            except:
                log.debug("offline message delivery failed (%s)" % (msg['id'], ))
                traceback.print_exc()
Beispiel #3
0
    def message(self, stanza):
        if not stanza.consumed:
            jid_from = self.parent.resolveJID(self.xmlstream.otherEntity)
            stanza["from"] = jid_from.full()

            # no destination - use sender bare JID
            if not stanza.hasAttribute("to"):
                jid_to = jid_from
                stanza["to"] = jid_to.userhost()
            else:
                jid_to = jid.JID(stanza["to"])

            # are we sending a message to a user we have blocked?
            if self.parent.router.is_presence_allowed(jid_to, jid_from) == -1:
                log.debug("sending message to blocked user, bouncing error")
                e = error.StanzaError("not-acceptable", "cancel")
                errstanza = e.toResponse(stanza)
                errstanza.error.addElement((xmlstream2.NS_IQ_BLOCKING_ERRORS, "blocked"))
                self.parent.send(errstanza)

            else:

                # check for permission
                allowed = self.parent.router.is_presence_allowed(jid_from, jid_to)
                if allowed == -1:
                    # user is blocked!
                    log.debug("not allowed to send messages, sending fake response to %s" % (stanza["from"],))
                    if stanza.getAttribute("type") == "chat" and xmlstream2.extract_receipt(stanza, "request"):
                        self.send_fake_receipt(stanza)
                else:
                    # send to c2s hub (without implicitly consuming)
                    self.parent.router.send(stanza, force_delivery=True, hold=(allowed != 1))

            # we have now consumed the stanza
            stanza.consumed = True
Beispiel #4
0
 def send_ack(self, stanza, status, stamp=None, receipt='request'):
     request = xmlstream2.extract_receipt(stanza, receipt)
     ack = xmlstream.toResponse(stanza, stanza.getAttribute('type'))
     rec = ack.addElement((xmlstream2.NS_XMPP_SERVER_RECEIPTS, status))
     rec['id'] = request['id']
     if stamp:
         rec['stamp'] = time.strftime(xmlstream2.XMPP_STAMP_FORMAT, time.gmtime(stamp))
     self.send(ack)
Beispiel #5
0
    def message(self, stanza):
        # generate message id if receipt is requested by client
        if xmlstream2.extract_receipt(stanza, 'request'):
            stanza.request['id'] = util.rand_str(30,
                                                 util.CHARSBOX_AZN_LOWERCASE)

        # no to address, presume sender bare JID
        if not stanza.hasAttribute('to'):
            stanza['to'] = self.xmlstream.otherEntity.userhost()

        # if message is a received receipt, we can delete the original message
        # TODO move this to MessageHandler
        if stanza.getAttribute('type') == 'chat':
            received = xmlstream2.extract_receipt(stanza, 'received')
            if stanza.received:
                # delete the received message
                # TODO safe delete with sender/recipient
                self.router.message_offline_delete(received['id'], stanza.name)
Beispiel #6
0
 def send_ack(self, stanza, status, stamp=None, receipt='request'):
     request = xmlstream2.extract_receipt(stanza, receipt)
     ack = xmlstream.toResponse(stanza, stanza.getAttribute('type'))
     rec = ack.addElement((xmlstream2.NS_XMPP_SERVER_RECEIPTS, status))
     rec['id'] = request['id']
     if stamp:
         rec['stamp'] = time.strftime(xmlstream2.XMPP_STAMP_FORMAT,
                                      time.gmtime(stamp))
     self.send(ack)
Beispiel #7
0
        def output(data, user):
            log.debug("data: %r" % (data, ))
            to = user.full()

            for msg in data:
                log.debug("msg[%s]=%s" % (
                    msg['id'],
                    msg['stanza'].toXml().encode('utf-8'),
                ))
                try:
                    """
                    Mark the stanza with our server name, so we'll receive a
                    copy of the receipt
                    """
                    if msg['stanza'].request:
                        msg['stanza'].request[
                            'from'] = self.xmlstream.thisEntity.full()
                    elif msg['stanza'].received:
                        msg['stanza'].received[
                            'from'] = self.xmlstream.thisEntity.full()

                    # mark delayed delivery
                    if 'timestamp' in msg:
                        delay = msg['stanza'].addElement(
                            (xmlstream2.NS_XMPP_DELAY, 'delay'))
                        delay['stamp'] = msg['timestamp'].strftime(
                            xmlstream2.XMPP_STAMP_FORMAT)

                    msg['to'] = to
                    self.send(msg['stanza'])
                    """
                    If a receipt is requested, we won't delete the message from
                    storage now; we must be sure client has received it.
                    Otherwise just delete the message immediately.
                    """
                    if not xmlstream2.extract_receipt(msg['stanza'], 'request') and \
                            not xmlstream2.extract_receipt(stanza, 'received'):
                        self.parent.message_offline_delete(
                            msg['id'], msg['stanza'].name)
                except:
                    log.debug("offline message delivery failed (%s)" %
                              (msg['id'], ))
                    traceback.print_exc()
Beispiel #8
0
    def message(self, stanza):
        # generate message id if receipt is requested by client
        if xmlstream2.extract_receipt(stanza, 'request'):
            stanza.request['id'] = util.rand_str(30, util.CHARSBOX_AZN_LOWERCASE)

        # no to address, presume sender bare JID
        if not stanza.hasAttribute('to'):
            stanza['to'] = self.xmlstream.otherEntity.userhost()

        # if message is a received receipt, we can delete the original message
        # TODO move this to MessageHandler
        if stanza.getAttribute('type') == 'chat':
            received = xmlstream2.extract_receipt(stanza, 'received')
            if stanza.received:
                # delete the received message
                # TODO safe delete with sender/recipient
                self.router.message_offline_delete(received['id'], stanza.name)

        self.handle(stanza)
Beispiel #9
0
    def message(self, stanza):
        if not stanza.consumed:
            jid_from = self.parent.resolveJID(self.xmlstream.otherEntity)
            stanza['from'] = jid_from.full()

            # no destination - use sender bare JID
            if not stanza.hasAttribute('to'):
                jid_to = jid_from
                stanza['to'] = jid_to.userhost()
            else:
                jid_to = jid.JID(stanza['to'])

            # are we sending a message to a user we have blocked?
            if self.parent.router.is_presence_allowed(jid_to, jid_from) == -1:
                log.debug("sending message to blocked user, bouncing error")
                e = error.StanzaError('not-acceptable', 'cancel')
                errstanza = e.toResponse(stanza)
                errstanza.error.addElement(
                    (xmlstream2.NS_IQ_BLOCKING_ERRORS, 'blocked'))
                self.parent.send(errstanza)

            else:

                # check for permission
                allowed = self.parent.router.is_presence_allowed(
                    jid_from, jid_to)
                if allowed == -1:
                    # user is blocked!
                    log.debug(
                        "not allowed to send messages, sending fake response to %s"
                        % (stanza['from'], ))
                    if stanza.getAttribute(
                            'type') == 'chat' and xmlstream2.extract_receipt(
                                stanza, 'request'):
                        self.send_fake_receipt(stanza)
                else:
                    # send to c2s hub (without implicitly consuming)
                    self.parent.router.send(stanza,
                                            force_delivery=True,
                                            hold=(allowed != 1))

            # we have now consumed the stanza
            stanza.consumed = True
Beispiel #10
0
    def _local_presence_output(self, data, user):
        log.debug("data: %r" % (data, ))
        # this will be used to set a safe recipient
        # WARNING this will create a JID anyway :(
        jid_to = self.resolveJID(user)
        for msg in data:
            log.debug("msg[%s]=%s" % (
                msg['id'],
                msg['stanza'].toXml().encode('utf-8'),
            ))
            stanza = msg['stanza']
            try:
                """
                Mark the stanza with our server name, so we'll receive a
                copy of the receipt
                """
                if stanza.request:
                    stanza.request['from'] = self.xmlstream.thisEntity.full()
                elif stanza.received:
                    stanza.received['from'] = self.xmlstream.thisEntity.full()

                # mark delayed delivery
                if 'timestamp' in msg:
                    delay = stanza.addElement(
                        (xmlstream2.NS_XMPP_DELAY, 'delay'))
                    delay['stamp'] = msg['timestamp'].strftime(
                        xmlstream2.XMPP_STAMP_FORMAT)

                # are we sending a message to a user we have blocked?
                jid_from = jid.JID(stanza['from'])
                if self.is_presence_allowed(jid_to, jid_from) == -1:
                    log.debug(
                        "sending message to blocked user, bouncing error")
                    e = error.StanzaError('not-acceptable', 'cancel')
                    errstanza = e.toResponse(msg['stanza'])
                    errstanza.error.addElement(
                        (xmlstream2.NS_IQ_BLOCKING_ERRORS, 'blocked'))
                    self.send(errstanza)

                else:
                    # check for permission
                    allowed = self.is_presence_allowed(jid_from, jid_to)
                    if allowed == -1:
                        # user is blocked!
                        log.debug(
                            "not allowed to send messages to %s, discarding message"
                            % (stanza['to'], ))
                        self.message_offline_delete(msg['id'], stanza.name)
                    else:
                        """
                        We use direct delivery here: it's faster and does not
                        involve JID resolution
                        """
                        stanza['to'] = jid_to.full()
                        self.dispatch(stanza, hold=(allowed != 1))
                """
                If a receipt is requested, we won't delete the message from
                storage now; we must be sure client has received it.
                Otherwise just delete the message immediately.
                """
                if not xmlstream2.extract_receipt(stanza, 'request') and \
                        not xmlstream2.extract_receipt(stanza, 'received'):
                    self.message_offline_delete(msg['id'], stanza.name)
            except:
                log.debug("offline message delivery failed (%s)" %
                          (msg['id'], ))
                traceback.print_exc()
Beispiel #11
0
    def process_message(self, stanza, hold=False):
        if stanza.hasAttribute('to'):
            to = jid.JID(stanza['to'])
            # process only our JIDs
            if util.jid_local(util.COMPONENT_C2S, self, to):
                chat_msg = (stanza.getAttribute('type') == 'chat')
                if to.user is not None:
                    keepId = None
                    receipt = xmlstream2.extract_receipt(stanza, 'request')
                    received = xmlstream2.extract_receipt(stanza, 'received')
                    has_storage = xmlstream2.has_element(
                        stanza, xmlstream2.NS_XMPP_STORAGE, 'storage')
                    try:
                        """
                        We are deliberately ignoring messages with sent
                        receipt because they are supposed to be volatile.
                        """
                        if chat_msg and not has_storage and (receipt
                                                             or received):
                            """
                            Apply generated id if we are getting a received receipt.
                            This way stanza is received by the client with the
                            correct id to cancel preemptive storage.
                            """
                            if received:
                                keepId = stanza['id'] = util.rand_str(
                                    30, util.CHARSBOX_AZN_LOWERCASE)

                            # send message to offline storage just to be safe (delayed)
                            keepId = self.message_offline_store(stanza,
                                                                delayed=True,
                                                                reuseId=keepId)

                        if hold:
                            raise Exception()

                        # send message to sm only to non-negative resources
                        log.debug("sending message %s" % (stanza['id'], ))
                        self.sfactory.dispatch(stanza)

                    except:
                        # manager not found or holding -- send to offline storage
                        if hold:
                            log.debug("holding stanza for %s" %
                                      (stanza['to'], ))
                        else:
                            log.debug("c2s manager for %s not found" %
                                      (stanza['to'], ))
                        """
                        Since our previous call to message_offline_store()
                        was with delayed parameter, we need to store for
                        real now.
                        Do not store messages from local storage because
                        """
                        if chat_msg and not has_storage and (stanza.body
                                                             or stanza.e2e
                                                             or received):
                            self.message_offline_store(stanza,
                                                       delayed=False,
                                                       reuseId=keepId)
                        if self.push_manager and chat_msg and (
                                stanza.body or stanza.e2e) and (
                                    not receipt or receipt.name == 'request'):
                            self.push_manager.notify(to)

                    # if message is a received receipt, we can delete the original message
                    if chat_msg and received:
                        # delete the received message
                        # TODO safe delete with sender/recipient
                        self.message_offline_delete(received['id'],
                                                    stanza.name)

                    stamp = time.time()
                    """
                    Receipts will be sent only if message is not coming from
                    storage or message is from a remote server.
                    This is because if the message is coming from storage,
                    it means that it's a user collecting its offline
                    messages, so we don't need to send a <sent/> again.
                    If a message is coming from a remote server, it means
                    that is being delivered by a remote c2s by either:
                     * sm request (direct message from client)
                     * offline delivery (triggered by an initial presence from this server)
                    """
                    host = util.jid_host(stanza['from'])

                    from_storage = xmlstream2.has_element(
                        stanza, xmlstream2.NS_XMPP_STORAGE, 'storage')

                    try:
                        log.debug("host(unparsed): %s" % (host, ))
                        unused, host = util.jid_component(
                            host, util.COMPONENT_C2S)
                        log.debug("host(parsed): %s" % (host, ))
                        from_remote = host != self.servername
                    except:
                        from_remote = False

                    if chat_msg and (not from_storage or from_remote):

                        # send ack only for chat messages (if requested)
                        # do not send if coming from remote storage
                        if receipt and not from_storage:
                            self.send_ack(stanza, 'sent', stamp)

                        # send receipt to originating server, if requested
                        receipt = None
                        # receipt request: send <sent/>
                        if stanza.request:
                            receipt = stanza.request
                            request = 'request'
                            delivery = 'sent'
                        # received receipt: send <ack/>
                        elif stanza.received:
                            receipt = stanza.received
                            request = 'received'
                            delivery = 'ack'

                        # now send what we prepared
                        if receipt:
                            try:
                                from_server = receipt['from']
                                if not util.hostjid_local(
                                        util.COMPONENT_C2S, self, from_server):
                                    stanza['from'] = from_server
                                    self.send_ack(stanza, delivery, stamp,
                                                  request)
                            except KeyError:
                                pass

                else:
                    # deliver local stanza
                    self.local(stanza)
                """
                If message is a receipt coming from a remote server, delete
                the message from our storage.
                """
                r_sent = xmlstream2.extract_receipt(stanza, 'sent')
                if chat_msg and r_sent:
                    sender_host = util.jid_host(stanza['from'])
                    """
                    We are receiving a sent receipt from another server,
                    meaning that the server has now responsibility for the
                    message - we can delete it now.
                    Special case is the sender domain being the network
                    domain, meaning the resolver rejected the message.
                    """
                    unused, sender_host = util.jid_component(sender_host)
                    if sender_host != self.servername:
                        log.debug(
                            "remote server now has responsibility for message %s - deleting"
                            % (r_sent['id'], ))
                        # TODO safe delete with sender/recipient
                        self.message_offline_delete(r_sent['id'], stanza.name)

            else:
                log.debug("stanza is not our concern or is an error")
Beispiel #12
0
    def process_message(self, stanza, hold=False):
        if stanza.hasAttribute('to'):
            to = jid.JID(stanza['to'])
            # process only our JIDs
            if util.jid_local(util.COMPONENT_C2S, self, to):
                chat_msg = (stanza.getAttribute('type') == 'chat')
                if to.user is not None:
                    keepId = None
                    receipt = xmlstream2.extract_receipt(stanza, 'request')
                    received = xmlstream2.extract_receipt(stanza, 'received')
                    has_storage = xmlstream2.has_element(stanza, xmlstream2.NS_XMPP_STORAGE, 'storage')
                    try:
                        """
                        We are deliberately ignoring messages with sent
                        receipt because they are supposed to be volatile.
                        """
                        if chat_msg and not has_storage and (receipt or received):
                            """
                            Apply generated id if we are getting a received receipt.
                            This way stanza is received by the client with the
                            correct id to cancel preemptive storage.
                            """
                            if received:
                                keepId = stanza['id'] = util.rand_str(30, util.CHARSBOX_AZN_LOWERCASE)

                            # send message to offline storage just to be safe (delayed)
                            keepId = self.message_offline_store(stanza, delayed=True, reuseId=keepId)

                        if hold:
                            raise Exception()

                        # send message to sm only to non-negative resources
                        log.debug("sending message %s" % (stanza['id'], ))
                        self.sfactory.dispatch(stanza)

                    except:
                        # manager not found or holding -- send to offline storage
                        if hold:
                            log.debug("holding stanza for %s" % (stanza['to'], ))
                        else:
                            log.debug("c2s manager for %s not found" % (stanza['to'], ))

                        """
                        Since our previous call to message_offline_store()
                        was with delayed parameter, we need to store for
                        real now.
                        Do not store messages from local storage because
                        """
                        if chat_msg and not has_storage and (stanza.body or stanza.e2e or received):
                            self.message_offline_store(stanza, delayed=False, reuseId=keepId)
                        if self.push_manager and chat_msg and (stanza.body or stanza.e2e) and (not receipt or receipt.name == 'request'):
                            self.push_manager.notify(to)

                    # if message is a received receipt, we can delete the original message
                    if chat_msg and received:
                        # delete the received message
                        # TODO safe delete with sender/recipient
                        self.message_offline_delete(received['id'], stanza.name)

                    stamp = time.time()

                    """
                    Receipts will be sent only if message is not coming from
                    storage or message is from a remote server.
                    This is because if the message is coming from storage,
                    it means that it's a user collecting its offline
                    messages, so we don't need to send a <sent/> again.
                    If a message is coming from a remote server, it means
                    that is being delivered by a remote c2s by either:
                     * sm request (direct message from client)
                     * offline delivery (triggered by an initial presence from this server)
                    """
                    host = util.jid_host(stanza['from'])

                    from_storage = xmlstream2.has_element(stanza, xmlstream2.NS_XMPP_STORAGE, 'storage')

                    try:
                        log.debug("host(unparsed): %s" % (host, ))
                        unused, host = util.jid_component(host, util.COMPONENT_C2S)
                        log.debug("host(parsed): %s" % (host, ))
                        from_remote = host != self.servername
                    except:
                        from_remote = False

                    if chat_msg and (not from_storage or from_remote):

                        # send ack only for chat messages (if requested)
                        # do not send if coming from remote storage
                        if receipt and not from_storage:
                            self.send_ack(stanza, 'sent', stamp)

                        # send receipt to originating server, if requested
                        receipt = None
                        # receipt request: send <sent/>
                        if stanza.request:
                            receipt = stanza.request
                            request = 'request'
                            delivery = 'sent'
                        # received receipt: send <ack/>
                        elif stanza.received:
                            receipt = stanza.received
                            request = 'received'
                            delivery = 'ack'

                        # now send what we prepared
                        if receipt:
                            try:
                                from_server = receipt['from']
                                if not util.hostjid_local(util.COMPONENT_C2S, self, from_server):
                                    stanza['from'] = from_server
                                    self.send_ack(stanza, delivery, stamp, request)
                            except KeyError:
                                pass

                else:
                    # deliver local stanza
                    self.local(stanza)

                """
                If message is a receipt coming from a remote server, delete
                the message from our storage.
                """
                r_sent = xmlstream2.extract_receipt(stanza, 'sent')
                if chat_msg and r_sent:
                    sender_host = util.jid_host(stanza['from'])
                    """
                    We are receiving a sent receipt from another server,
                    meaning that the server has now responsibility for the
                    message - we can delete it now.
                    Special case is the sender domain being the network
                    domain, meaning the resolver rejected the message.
                    """
                    unused, sender_host = util.jid_component(sender_host)
                    if sender_host != self.servername:
                        log.debug("remote server now has responsibility for message %s - deleting" % (r_sent['id'], ))
                        # TODO safe delete with sender/recipient
                        self.message_offline_delete(r_sent['id'], stanza.name)

            else:
                log.debug("stanza is not our concern or is an error")