def error(self, stanza, condition='service-unavailable', errtype='cancel', text=None): if not stanza.consumed: log.debug("error %s" % (stanza.toXml(), )) stanza.consumed = True util.resetNamespace(stanza, self.namespace) e = error.StanzaError(condition, errtype, text) self.send(e.toResponse(stanza), True)
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'))
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 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())) if sender.host != xs.otherEntity.host and sender.host != self.defaultDomain: xs.sendStreamError(error.StreamError('invalid-from')) else: # replace to with destination destination = stanza.getAttribute('destination') if destination: stanza['to'] = destination del stanza['destination'] self.router.send(stanza)
def dispatch(self, stanza): """Incoming message from router.""" if not stanza.consumed: if self.parent.logTraffic: log.debug("incoming message: %s" % (stanza.toXml().encode('utf-8'))) stanza.consumed = True util.resetNamespace(stanza, component.NS_COMPONENT_ACCEPT) self.parent.process_message(stanza)
def bounce(self, stanza): """Bounce stanzas as results.""" if not stanza.consumed: util.resetNamespace(stanza, self.namespace) if self.router.logTraffic: log.debug("bouncing %s" % (stanza.toXml(), )) stanza.consumed = True self.send(xmlstream.toResponse(stanza, 'result'))
def network_timeout(self, stanza): """ Handles errors from the net component (e.g. kontalk server not responding). """ stanza.consumed = True util.resetNamespace(stanza, component.NS_COMPONENT_ACCEPT) message = stanza.original.firstChildElement() self.parent.not_found(message) # send ack only for chat messages if message.getAttribute('type') == 'chat': self.parent.send_ack(message, 'sent')
def dispatch(self, stanza): """Handle incoming stanza from router to the proper server stream.""" if not stanza.consumed: stanza.consumed = True log.debug("incoming stanza from router %s" % (stanza.toXml().encode('utf-8'), )) to = stanza.getAttribute('to') if to is not None: to = jid.JID(to) if to.host != self.xmlstream.thisEntity.host: util.resetNamespace(stanza, component.NS_COMPONENT_ACCEPT) self.service.send(stanza)
def dispatch(self, stanza): """ Dispatch a stanza to a JID all to all available resources found locally. @raise L{KeyError}: if a destination route is not found """ userid, unused, resource = jid.parse(stanza['to']) util.resetNamespace(stanza, component.NS_COMPONENT_ACCEPT) if resource is not None: self.streams[userid][resource].send(stanza) else: for resource, manager in self.streams[userid].iteritems(): manager.send(stanza)
def forward(self, stanza): """ Forward incoming stanza from clients to the router, setting the from attribute to the sender entity. """ if not stanza.consumed: util.resetNamespace(stanza, self.namespace) if self.router.logTraffic: log.debug("forwarding %s" % (stanza.toXml().encode('utf-8'), )) stanza.consumed = True util.resetNamespace(stanza, component.NS_COMPONENT_ACCEPT) self.router.send(stanza)
def forward(self, stanza, useFrom=False): """ Forward incoming stanza from clients to the router, setting the from attribute to the sender entity. """ if not stanza.consumed: util.resetNamespace(stanza, self.namespace) if self.router.logTraffic: log.debug("forwarding %s" % (stanza.toXml().encode('utf-8'), )) stanza.consumed = True util.resetNamespace(stanza, component.NS_COMPONENT_ACCEPT) stanza['from'] = self.resolveJID(stanza['from'] if useFrom else self.xmlstream.otherEntity).full() self.router.send(stanza)
def dispatch(self, stanza): """Handle incoming stanza from router to the proper server stream.""" if not stanza.consumed: stanza.consumed = True log.debug("incoming stanza from router %s" % (stanza.toXml().encode('utf-8'), )) util.resetNamespace(stanza, component.NS_COMPONENT_ACCEPT) stanza['from'] = self.resolveJID(stanza['from']).full() to = stanza.getAttribute('to') if to is not None: sender = jid.JID(to) if sender.host == self.network or sender.host in self.keyring.hostlist(): log.debug("stanza is for %s - resolver/c2s/net is down?" % (sender.host, )) else: self.service.send(stanza)
def dispatch(self, stanza): """Handle incoming stanza from router to the proper server stream.""" if not stanza.consumed: stanza.consumed = True log.debug("incoming stanza from router %s" % (stanza.toXml().encode('utf-8'), )) util.resetNamespace(stanza, component.NS_COMPONENT_ACCEPT) stanza['from'] = self.resolveJID(stanza['from']).full() to = stanza.getAttribute('to') if to is not None: sender = jid.JID(to) if sender.host == self.network or sender.host in self.keyring.hostlist( ): log.debug("stanza is for %s - resolver/c2s/net is down?" % (sender.host, )) else: self.service.send(stanza)
def dispatch(self, stanza, hold=False, ignore_consumed=True): """ Dispatches stanzas from router and from local clients. @param hold: if true, the stanza will not be delivered but sent to offline storage instead (used only for message stanzas) @type hold: bool @param ignore_consumed: if true, stanza's consumed attribute will be ignored @type ignore_consumed: bool """ if not ignore_consumed and stanza.consumed: return stanza.consumed = True util.resetNamespace(stanza, component.NS_COMPONENT_ACCEPT) if stanza.hasAttribute('to'): to = jid.JID(stanza['to']) # process only our JIDs if util.jid_local(util.COMPONENT_C2S, self, to): # messages follow a different path if stanza.name == 'message': return self.process_message(stanza, hold) elif stanza.name == 'presence' and stanza.getAttribute( 'type') == 'subscribe': return self.process_subscription(stanza) if to.user is not None: try: """ TEST to store message anyway :) if stanza.name == 'message': raise Exception() """ self.sfactory.dispatch(stanza) except: # manager not found log.debug("c2s manager for %s not found" % (stanza['to'], )) else: self.local(stanza) else: #log.debug("stanza is not our concern or is an error") # send to router component.Component.send(self, stanza)
def dispatch(self, stanza, hold=False, ignore_consumed=True): """ Dispatches stanzas from router and from local clients. @param hold: if true, the stanza will not be delivered but sent to offline storage instead (used only for message stanzas) @type hold: bool @param ignore_consumed: if true, stanza's consumed attribute will be ignored @type ignore_consumed: bool """ if not ignore_consumed and stanza.consumed: return stanza.consumed = True util.resetNamespace(stanza, component.NS_COMPONENT_ACCEPT) if stanza.hasAttribute('to'): to = jid.JID(stanza['to']) # process only our JIDs if util.jid_local(util.COMPONENT_C2S, self, to): # messages follow a different path if stanza.name == 'message': return self.process_message(stanza, hold) elif stanza.name == 'presence' and stanza.getAttribute('type') == 'subscribe': return self.process_subscription(stanza) if to.user is not None: try: """ TEST to store message anyway :) if stanza.name == 'message': raise Exception() """ self.sfactory.dispatch(stanza) except: # manager not found log.debug("c2s manager for %s not found" % (stanza['to'], )) else: self.local(stanza) else: #log.debug("stanza is not our concern or is an error") # send to router component.Component.send(self, stanza)
def dispatch(self, xs, stanza): """ Send a stanza to the router, checking some stuff first. """ util.resetNamespace(stanza, xs.namespace) stanzaFrom = stanza.getAttribute('from') stanzaTo = stanza.getAttribute('to') if 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 error stanza with malformed JID") log.debug("sender = %s, otherEntity = %s" % (sender.full(), xs.otherEntity.full())) if sender.host != xs.otherEntity.host and sender.host != self.defaultDomain: xs.sendStreamError(error.StreamError('invalid-from')) else: self.router.send(stanza)
def route(self, stanza, xs): """ Route a stanza. @param stanza: The stanza to be routed. @type stanza: L{domish.Element}. """ if stanza.consumed: return """" TEST check sender host is component stanzaFrom = jid.JID(stanza['from']) if stanzaFrom.host != xs.thisEntity.host: log.error("stanza is not from component - dropping") return """ # reset namespace util.resetNamespace(stanza, component.NS_COMPONENT_ACCEPT) # send stanza to logging entities for lg in self.logs: lg.send(stanza) if not stanza.hasAttribute('to'): if self.logTraffic: log.debug("broadcasting stanza %s" % (stanza.toXml().encode('utf-8'), )) self.broadcast(stanza) else: """ FIXME we have encoding problems here... (why not in other components?!?!?) """ # check for stanza loops errors = 0 for child in stanza.children: if domish.IElement.providedBy(child) and child.name == 'error': errors += 1 if errors > 1: if self.logTraffic: log.debug("error loop, dropping stanza %s" % (stanza.toXml().encode('utf-8'), )) else: log.debug("error loop, dropping stanza") return if self.logTraffic: log.debug("routing stanza %s" % (stanza.toXml().encode('utf-8'), )) try: destination_host = util.jid_host(stanza['to']) if destination_host in self.routes: self.routes[destination_host].send(stanza) elif destination_host in self.private: self.private[destination_host].send(stanza) else: self.routes[None].send(stanza) except KeyError: log.warn("unroutable stanza, bouncing back to component") e = error.StanzaError('service-unavailable') xs.send(e.toResponse(stanza))
def send(self, stanza, force_delivery=False, force_bare=False, hold=False): """ Resolves stanza recipient and send the stanza to the router. @param stanza: the stanza to be sent @type stanza: domish.Element @param force_delivery: if true, deliver the stanza to the first available resource found if the intended one is not available @type force_delivery bool @param force_bare: if true, deliver the stanza to the bare JID despite of the indicated destination @type force_bare bool @param hold: this parameter is passed directly to the dispatch method, instructing it to not deliver the stanza and hold it in offline storage instead (e.g. delayed/unauthorized messages) @type hold bool """ # send raw xml if you really know what you are doing if not domish.IElement.providedBy(stanza): return component.Component.send(self, stanza) util.resetNamespace(stanza, component.NS_COMPONENT_ACCEPT) # force host in sender component_jid = util.component_jid(self.servername, util.COMPONENT_C2S) sender = jid.JID(stanza['from']) if sender.host == self.network: sender.host = component_jid stanza['from'] = sender.full() if not stanza.hasAttribute('to'): # no destination - send to router component.Component.send(self, stanza) return # save original recipient for later stanza['original-to'] = stanza['to'] to = jid.JID(stanza['to']) # stanza is intended to the network if to.full() == self.network: # TODO log.debug("stanza for the network: %s" % (stanza.toXml(), )) return # network JID - resolve and send to router elif to.host == self.network: rcpts = self.cache.lookup(to) log.debug("rcpts = %r" % (rcpts, )) if not rcpts: if not stanza.consumed: stanza.consumed = True log.debug("JID %s not found" % (to.full(), )) e = error.StanzaError('item-not-found', 'cancel') self.dispatch(e.toResponse(stanza)) else: log.debug("JID %s not found (stanza has been consumed)" % (to.full(), )) return else: """ Stanza delivery rules 1. deliver to all available resources 2. destination was a bare JID a. if all resources are unavailable, deliver to the first network bare JID (then return) 3. destination was a full JID: a. deliver to full JID """ log.debug("JID found: %r" % (rcpts, )) jids = rcpts.jids() # destination was a full JID if to.resource and not force_bare: # no available resources, deliver to bare JID if force delivery if len(jids) == 0 and force_delivery: stanza['to'] = rcpts.jid.userhost() self.dispatch(stanza, hold=hold) # deliver if resource is available else: sent = False for _to in jids: if _to.resource == to.resource: stanza['to'] = _to.full() self.dispatch(stanza, hold=hold) sent = True break # if sent=False it means that the intended resource has vanished # if force delivery is enabled, deliver to the first available resource if not sent and len(jids) > 0 and force_delivery: stanza['to'] = jids[0].full() self.dispatch(stanza, hold=hold) # destination was a bare JID else: log.debug("destination was a bare JID (force_bare=%s)" % (force_bare, )) log.debug("jids = %s, rcpts = %s" % (jids, rcpts)) # no available resources, send to first network bare JID if len(jids) == 0 or force_bare: stanza['to'] = rcpts.jid.userhost() self.dispatch(stanza, hold=hold) else: for _to in jids: stanza['to'] = _to.full() self.dispatch(stanza, hold=hold) # otherwise send to router else: self.dispatch(stanza, hold=hold)
def send(self, stanza, force=False): """Send stanza to client, setting to and id attributes if not present.""" if stanza.hasAttribute('original-to'): origTo = stanza.getAttribute('original-to') del stanza['original-to'] """ Extract original recipient from stanza. If original-to is not present, we will assume that stanza was intended to the full JID. """ origTo = jid.JID(origTo) if self.router.logTraffic: log.debug("sending message to client %s (original was %s)" % (self.xmlstream.otherEntity, origTo)) if self._presence: log.debug("_presence: %s" % (self._presence.toXml(), )) # sending to bare JID # initial presence found # negative resource # => DROP STANZA try: if not origTo.resource and int(str(self._presence.priority)) < 0: return None except: pass # FIXME using deepcopy is not safe from copy import deepcopy stanza = deepcopy(stanza) util.resetNamespace(stanza, component.NS_COMPONENT_ACCEPT, self.namespace) # translate sender to network JID sender = stanza.getAttribute('from') if sender and sender != self.network: sender = jid.JID(stanza['from']) sender.host = self.network stanza['from'] = sender.full() # TODO should we force self.network if no sender? # remove reserved elements if stanza.name in ('presence', 'message'): # storage child if stanza.storage and stanza.storage.uri == xmlstream2.NS_XMPP_STORAGE: stanza.children.remove(stanza.storage) # origin in receipt if stanza.request and stanza.request.hasAttribute('from'): del stanza.request['from'] elif stanza.received and stanza.received.hasAttribute('from'): del stanza.received['from'] if stanza.name == 'presence': # push device id for c in stanza.elements(name='c', uri=xmlstream2.NS_PRESENCE_PUSH): stanza.children.remove(c) break # force destination address if self.xmlstream.otherEntity: stanza['to'] = self.xmlstream.otherEntity.full() if not stanza.hasAttribute('id'): stanza['id'] = util.rand_str(8, util.CHARSBOX_AZN_LOWERCASE) xmlstream2.StreamManager.send(self, stanza, force)
def route(self, stanza, xs): """ Route a stanza. @param stanza: The stanza to be routed. @type stanza: L{domish.Element}. """ if stanza.consumed: return """" TEST check sender host is component stanzaFrom = jid.JID(stanza['from']) if stanzaFrom.host != xs.thisEntity.host: log.error("stanza is not from component - dropping") return """ # reset namespace util.resetNamespace(stanza, component.NS_COMPONENT_ACCEPT) # send stanza to logging entities for lg in self.logs: lg.send(stanza) if not stanza.hasAttribute('to'): if self.logTraffic: log.debug("broadcasting stanza %s" % (stanza.toXml().encode('utf-8'), )) self.broadcast(stanza) else: """ FIXME we have encoding problems here... (why not in other components?!?!?) """ # check for stanza loops errors = 0 for child in stanza.children: if domish.IElement.providedBy(child) and child.name == 'error': errors += 1 if errors > 1: if self.logTraffic: log.debug("error loop, dropping stanza %s" % (stanza.toXml().encode('utf-8'), )) else: log.debug("error loop, dropping stanza") return if self.logTraffic: log.debug("routing stanza %s" % (stanza.toXml().encode('utf-8'), )) try: destination_host = util.jid_host(stanza['to']) if destination_host in self.routes: self.routes[destination_host].send(stanza) else: self.routes[None].send(stanza) except KeyError: log.warn("unroutable stanza, bouncing back to component") e = error.StanzaError('service-unavailable') xs.send(xmlstream2.errorResponse(e, stanza))
def send(self, stanza, force=False): """Send stanza to client, setting to and id attributes if not present.""" if stanza.hasAttribute('original-to'): origTo = stanza.getAttribute('original-to') del stanza['original-to'] """ Extract original recipient from stanza. If original-to is not present, we will assume that stanza was intended to the full JID. """ origTo = jid.JID(origTo) if self.router.logTraffic: log.debug("sending message to client %s (original was %s)" % (self.xmlstream.otherEntity, origTo)) if self._presence: log.debug("_presence: %s" % (self._presence.toXml().encode('utf-8'), )) # sending to bare JID # initial presence found # negative resource # => DROP STANZA try: if not origTo.resource and int(str( self._presence.priority)) < 0: return None except: pass # FIXME using deepcopy is not safe from copy import deepcopy stanza = deepcopy(stanza) util.resetNamespace(stanza, component.NS_COMPONENT_ACCEPT, self.namespace) # translate sender to network JID sender = stanza.getAttribute('from') if sender and sender != self.network: sender = jid.JID(stanza['from']) sender.host = self.network stanza['from'] = sender.full() # TODO should we force self.network if no sender? # remove reserved elements if stanza.direct and stanza.direct.uri == xmlstream2.NS_XMPP_DIRECT: stanza.children.remove(stanza.direct) if stanza.name in ('presence', 'message'): # storage child if stanza.storage and stanza.storage.uri == xmlstream2.NS_XMPP_STORAGE: stanza.children.remove(stanza.storage) # origin in receipt if stanza.request and stanza.request.hasAttribute('from'): del stanza.request['from'] elif stanza.received and stanza.received.hasAttribute('from'): del stanza.received['from'] if stanza.name == 'presence': # push device id for c in stanza.elements(name='c', uri=xmlstream2.NS_PRESENCE_PUSH): stanza.children.remove(c) break # force destination address if self.xmlstream.otherEntity: stanza['to'] = self.xmlstream.otherEntity.full() if not stanza.hasAttribute('id'): stanza['id'] = util.rand_str(8, util.CHARSBOX_AZN_LOWERCASE) xmlstream2.StreamManager.send(self, stanza, force)