コード例 #1
0
ファイル: net.py プロジェクト: MilanovicB/xmppserver
    def dispatch(self, xs, stanza):
        """
        Send a stanza to the router, checking some stuff first.
        """

        log.debug("stanza from %s: %s" % (xs.otherEntity.full(), stanza.toXml()))
        util.resetNamespace(stanza, xs.namespace)
        stanzaFrom = stanza.getAttribute('from')
        stanzaTo = stanza.getAttribute('to')

        if not stanza.bind and not stanzaFrom or not stanzaTo:
            xs.sendStreamError(error.StreamError('improper-addressing'))
        else:
            try:
                sender = jid.internJID(stanzaFrom)
                jid.internJID(stanzaTo)
            except jid.InvalidFormat:
                log.debug("dropping stanza with malformed JID")

            log.debug("sender = %s, otherEntity = %s" % (sender.full(), xs.otherEntity.full()))

            try:
                unused, host = util.jid_component(sender.host)
                if host in self.keyring.hostlist():
                    self.router.send(stanza)
                else:
                    raise Exception()
            except:
                xs.sendStreamError(error.StreamError('invalid-from'))
コード例 #2
0
ファイル: net.py プロジェクト: dabusharsystems/xmppserver
    def dispatch(self, xs, stanza):
        """
        Send a stanza to the router, checking some stuff first.
        """

        log.debug("stanza from %s: %s" %
                  (xs.otherEntity.full(), stanza.toXml()))
        util.resetNamespace(stanza, xs.namespace)
        stanzaFrom = stanza.getAttribute('from')
        stanzaTo = stanza.getAttribute('to')

        if not stanza.bind and not stanzaFrom or not stanzaTo:
            xs.sendStreamError(error.StreamError('improper-addressing'))
        else:
            try:
                sender = jid.internJID(stanzaFrom)
                jid.internJID(stanzaTo)
            except jid.InvalidFormat:
                log.debug("dropping stanza with malformed JID")

            log.debug("sender = %s, otherEntity = %s" %
                      (sender.full(), xs.otherEntity.full()))

            try:
                unused, host = util.jid_component(sender.host)
                if host in self.keyring.hostlist():
                    self.router.send(stanza)
                else:
                    raise Exception()
            except:
                xs.sendStreamError(error.StreamError('invalid-from'))
コード例 #3
0
ファイル: net.py プロジェクト: MilanovicB/xmppserver
        def _bind(stanza, name):
            if not stanza.hasAttribute('error'):
                # no errors, register route
                unused, host = util.jid_component(name)

                if host not in self.routes:
                    self.routes[host] = []

                self.routes[host].append(name)
                log.debug("ROUTES: %s" % (self.routes, ))
コード例 #4
0
ファイル: net.py プロジェクト: dabusharsystems/xmppserver
        def _bind(stanza, name):
            if not stanza.hasAttribute('error'):
                # no errors, register route
                unused, host = util.jid_component(name)

                if host not in self.routes:
                    self.routes[host] = []

                self.routes[host].append(name)
                log.debug("ROUTES: %s" % (self.routes, ))
コード例 #5
0
    def translateJID(self, _jid, resource=True):
        """
        Translate a server JID ([email protected]) into a network JID
        ([email protected]).
        """
        # TODO ehm :D
        try:
            unused, host = util.jid_component(_jid.host)
            if host in self.keyring.hostlist():
                return jid.JID(tuple=(_jid.user, self.network, _jid.resource if resource else None))
        except ValueError:
            pass

        return _jid if resource else _jid.userhostJID()
コード例 #6
0
    def iq(self, stanza):
        """
        Removes the from attribute if it matches the c2s JID.
        This was actually done to "fake" IQ stanzas coming from
        remote c2s that should appear to the client as coming from nowhere.
        """

        sender = stanza.getAttribute('from')
        if sender and not ('@' in sender):
            # receiving iq from remote c2s, remove from attribute
            unused, host = util.jid_component(sender, util.COMPONENT_C2S)

            if host in self.keyring.hostlist():
                del stanza['from']
コード例 #7
0
ファイル: component.py プロジェクト: carriercomm/xmppserver
    def iq(self, stanza):
        """
        Removes the from attribute if it matches the c2s JID.
        This was actually done to "fake" IQ stanzas coming from
        remote c2s that should appear to the client as coming from nowhere.
        """

        sender = stanza.getAttribute('from')
        if sender and not ('@' in sender):
            # receiving iq from remote c2s, remove from attribute
            unused, host = util.jid_component(sender, util.COMPONENT_C2S)

            if host in self.keyring.hostlist():
                del stanza['from']
コード例 #8
0
ファイル: net.py プロジェクト: MilanovicB/xmppserver
    def unbind(self, name):
        # send unbind command to router
        unbind = domish.Element((None, 'unbind'))
        unbind['name'] = name
        self.send(unbind)

        # unregister route
        unused, host = util.jid_component(name)
        if host in self.routes:
            self.routes[host].remove(name)

            if len(self.routes[host]) == 0:
                del self.routes[host]

        else:
            # this is an error, it shouldn't happen
            log.warn("unbinding non-registered route: %s" % (name, ))
コード例 #9
0
ファイル: net.py プロジェクト: dabusharsystems/xmppserver
    def unbind(self, name):
        # send unbind command to router
        unbind = domish.Element((None, 'unbind'))
        unbind['name'] = name
        self.send(unbind)

        # unregister route
        unused, host = util.jid_component(name)
        if host in self.routes:
            self.routes[host].remove(name)

            if len(self.routes[host]) == 0:
                del self.routes[host]

        else:
            # this is an error, it shouldn't happen
            log.warn("unbinding non-registered route: %s" % (name, ))
コード例 #10
0
    def onPresenceAvailable(self, stanza):
        """Handle available presence stanzas."""

        if stanza.consumed:
            return

        try:
            # initial presence from a remote resolver
            component, host = util.jid_component(stanza['from'], util.COMPONENT_C2S)

            if host != self.parent.servername and host in self.parent.keyring.hostlist():
                self.send_privacy_lists('blocklist', self.parent.blacklists, stanza['from'])
                self.send_privacy_lists('whitelist', self.parent.whitelists, stanza['from'])

        except:
            pass

        self.parent.broadcastSubscribers(stanza)
コード例 #11
0
    def broadcastSubscribers(self, stanza):
        """Broadcast stanza to JID subscribers."""

        # direct delivery: do not broadcast
        if stanza.direct and stanza.direct.uri == xmlstream2.NS_XMPP_DIRECT:
            return

        user = jid.JID(stanza['from'])

        try:
            unused, host = util.jid_component(user.host)

            # FIXME wrong host check (this is a one of the causes of the invalid-from bug)
            if host in self.keyring.hostlist():
                # local or network user: translate host name
                watched = jid.JID(tuple=(user.user, self.network, user.resource))
            else:
                # other JIDs, use unchanged
                watched = user

        except ValueError:
            # other JIDs, use unchanged
            watched = user

        bareWatched = watched.userhostJID()
        if bareWatched in self.subscriptions:
            #stanza['from'] = watched.full()

            removed = []
            for sub in self.subscriptions[bareWatched]:
                if self.is_presence_allowed(sub, watched) == 1:
                    log.debug("notifying subscriber %s" % (sub, ))
                    stanza['to'] = sub.userhost()
                    # direct delivery to workaround presence loops
                    stanza.addElement((xmlstream2.NS_XMPP_DIRECT, 'direct'))
                    stanza.consumed = True
                    self.send(stanza)
                else:
                    log.debug("%s is not allowed to see presence" % (sub, ))
                    removed.append(sub)

            # remove unauthorized users
            for e in removed:
                self.subscriptions[bareWatched].remove(e)
コード例 #12
0
    def onPresenceUnavailable(self, stanza):
        """Handle unavailable presence stanzas."""
        if self.parent.logTraffic:
            log.debug("user unavailable: %s" % (stanza.toXml().encode('utf-8'), ))
        else:
            log.debug("user unavailable from %s" % (stanza['from'], ))

        # local c2s or remote server has disconnected, remove presences from cache
        try:
            unused, host = util.jid_component(stanza['from'], util.COMPONENT_C2S)
            if host in self.parent.keyring.hostlist():
                log.debug("server %s is disconnecting, taking over presence data" % (host, ))
                ordered_presence = []
                for stub in self.presence_cache.itervalues():
                    if stub.jid.host == stanza['from']:
                        ordered_presence.append(stub)

                # TEST TEST TEST
                # TODO this needs serious re-design from scratch (I mean the whole presence sharing architecture)
                from operator import attrgetter
                ordered_presence.sort(key=attrgetter('jid'))
                # take the N-th part
                index = 1
                for s in self.parent.keyring.hostlist():
                    # skip missing server
                    if s == host:
                        continue
                    # we found ourselves
                    if s == self.parent.servername:
                        break
                    index += 1

                if index > len(self.parent.keyring.hostlist()):
                    log.warn("we can't find ourselves on the servers table! WTF!?!?")

                else:
                    network_len = len(self.parent.keyring.hostlist())
                    presence_len = len(ordered_presence)
                    slice_start = presence_len / (network_len-1) * (index - 1)
                    slice_end = presence_len / (network_len-1) * ((index+1) - 1)
                    log.debug("slice_start = %d, slice_end = %d" % (slice_start, slice_end))
                    for i in range(slice_start, slice_end):
                        e = ordered_presence[i]
                        rewrite = None
                        presence = e.presence()
                        for p in presence:
                            if not p.hasAttribute('type'):
                                # available presence will be converted into unavailable
                                p['type'] = 'unavailable'

                            if p.getAttribute('type') == 'unavailable':
                                # unavailable presence will be broadcasted
                                rewrite = PresenceStub.fromElement(p, util
                                    .component_jid(self.parent.servername, util.COMPONENT_C2S))
                                self.presence_cache[e.jid.user] = rewrite

                        # simulate presence broadcast so resolvers will insert it into their cache
                        if rewrite:
                            p = rewrite.presence()
                            try:
                                fpr = self.parent.keyring.get_fingerprint(e.jid.user)
                                self.parent.presencedb.presence(p[0])
                                self.parent.presencedb.public_key(e.jid.user, fpr)
                            except keyring.KeyNotFoundException:
                                pass
                            self.send(p[0].toXml().encode('utf-8'))
            return

        except TypeError:
            pass
        except:
            import traceback
            traceback.print_exc()

        # normal user unavailable
        user = jid.JID(stanza['from'])

        if user.user:
            self.user_unavailable(stanza)
コード例 #13
0
ファイル: handlers.py プロジェクト: odetoyama/xmppserver
    def presence(self, stanza):
        """
        This initial presence is from a broadcast sent by external entities
        (e.g. not the sm); sm wouldn't see it because it has no observer.
        Here we are sending offline messages directly to the connected user.
        """

        log.debug("initial presence from router by %s" % (stanza['from'], ))

        try:
            # receiving initial presence from remote c2s, send all presence data
            unused, host = util.jid_component(stanza['from'],
                                              util.COMPONENT_C2S)

            if host != self.parent.servername and host in self.parent.keyring.hostlist(
            ):
                log.debug(
                    "remote c2s appeared, sending all local presence and vCards to %s"
                    % (stanza['from'], ))
                self.send_presence(stanza['from'])

        except:
            pass

        sender = jid.JID(stanza['from'])

        # check for external conflict
        self.parent.sfactory.check_conflict(sender)

        if sender.user:
            try:
                unused, host = util.jid_component(sender.host,
                                                  util.COMPONENT_C2S)

                # initial presence from a client connected to another server, clear it from our presence table
                if host != self.parent.servername and host in self.parent.keyring.hostlist(
                ):
                    log.debug("deleting %s from presence table" %
                              (sender.user, ))
                    self.parent.presencedb.delete(sender.user)

            except:
                pass

        # initial presence - deliver offline storage
        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()

        d = self.parent.stanzadb.get_by_recipient(sender)
        d.addCallback(output, sender)
コード例 #14
0
ファイル: handlers.py プロジェクト: carriercomm/xmppserver
    def presence(self, stanza):
        """
        This initial presence is from a broadcast sent by external entities
        (e.g. not the sm); sm wouldn't see it because it has no observer.
        Here we are sending offline messages directly to the connected user.
        """

        log.debug("initial presence from router by %s" % (stanza['from'], ))

        try:
            # receiving initial presence from remote c2s, send all presence data
            unused, host = util.jid_component(stanza['from'], util.COMPONENT_C2S)

            if host != self.parent.servername and host in self.parent.keyring.hostlist():
                log.debug("remote c2s appeared, sending all local presence and vCards to %s" % (stanza['from'], ))
                self.send_presence(stanza['from'])

        except:
            pass

        sender = jid.JID(stanza['from'])

        # check for external conflict
        self.parent.sfactory.check_conflict(sender)

        if sender.user:
            try:
                unused, host = util.jid_component(sender.host, util.COMPONENT_C2S)

                # initial presence from a client connected to another server, clear it from our presence table
                if host != self.parent.servername and host in self.parent.keyring.hostlist():
                    log.debug("deleting %s from presence table" % (sender.user, ))
                    self.parent.presencedb.delete(sender.user)

            except:
                pass

        # initial presence - deliver offline storage
        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()

        d = self.parent.stanzadb.get_by_recipient(sender)
        d.addCallback(output, sender)
コード例 #15
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")
コード例 #16
0
ファイル: component.py プロジェクト: carriercomm/xmppserver
    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")