class Vines::Stanza

Constants

EMPTY
ROUTABLE_STANZAS
TO

Attributes

stream[R]

Public Class Methods

from_node(node, stream) click to toggle source
# File lib/vines/stanza.rb, line 19
def self.from_node(node, stream)
  # optimize common case
  return Message.new(node, stream) if node.name == MESSAGE
  found = @@types.select {|pair, v| node.xpath(*pair).any? }
    .sort {|a, b| b[0][0].length - a[0][0].length }.first
  found ? found[1].new(node, stream) : nil
end
new(node, stream) click to toggle source
# File lib/vines/stanza.rb, line 27
def initialize(node, stream)
  @node, @stream = node, stream
end
register(xpath, ns={}) click to toggle source
# File lib/vines/stanza.rb, line 15
def self.register(xpath, ns={})
  @@types[[xpath, ns]] = self
end

Public Instance Methods

broadcast(recipients) click to toggle source

Send the stanza to all recipients, stamping it with from and to addresses first.

# File lib/vines/stanza.rb, line 33
def broadcast(recipients)
  @node[FROM] = stream.user.jid.to_s
  recipients.each do |recipient|
    @node[TO] = recipient.user.jid.to_s
    recipient.write(@node)
  end
end
local?() click to toggle source

Returns true if this stanza should be processed locally. Returns false if it's destined for a remote domain or external component.

# File lib/vines/stanza.rb, line 43
def local?
  return true unless ROUTABLE_STANZAS.include?(@node.name)
  to = JID.new(@node[TO])
  to.empty? || local_jid?(to)
end
local_jid?(*jids) click to toggle source
# File lib/vines/stanza.rb, line 49
def local_jid?(*jids)
  stream.config.local_jid?(*jids)
end
method_missing(method, *args, &block) click to toggle source
# File lib/vines/stanza.rb, line 109
def method_missing(method, *args, &block)
  @node.send(method, *args, &block)
end
process() click to toggle source
# File lib/vines/stanza.rb, line 73
def process
  raise 'subclass must implement'
end
route() click to toggle source
# File lib/vines/stanza.rb, line 61
def route
  stream.router.route(@node)
end
router() click to toggle source
# File lib/vines/stanza.rb, line 65
def router
  stream.router
end
send_unavailable(from, to) click to toggle source

Broadcast unavailable presence from the user's available resources to the recipient's available resources. Route the stanza to a remote server if the recipient isn't hosted locally.

# File lib/vines/stanza.rb, line 80
def send_unavailable(from, to)
  available = router.available_resources(from, to)
  stanzas = available.map {|stream| unavailable(stream.user.jid) }
  broadcast_to_available_resources(stanzas, to)
end
storage(domain=stream.domain) click to toggle source
# File lib/vines/stanza.rb, line 69
def storage(domain=stream.domain)
  stream.storage(domain)
end
to_pubsub_domain?() click to toggle source

Return true if this stanza is addressed to a pubsub subdomain hosted at this server. This helps differentiate between IQ stanzas addressed to the server and stanzas addressed to pubsub domains, both of which must be handled locally and not routed.

# File lib/vines/stanza.rb, line 57
def to_pubsub_domain?
  stream.config.pubsub?(validate_to)
end
unavailable(from) click to toggle source

Return an unavailable presence stanza addressed from the given JID.

# File lib/vines/stanza.rb, line 87
def unavailable(from)
  doc = Document.new
  doc.create_element('presence',
    'from' => from.to_s,
    'id'   => Kit.uuid,
    'type' => 'unavailable')
end
validate_from() click to toggle source

Return nil if this stanza has no 'from' attribute. Return a Vines::JID if it contains a valid 'from' attribute. Raise a JidMalformed error if the JID is invalid.

# File lib/vines/stanza.rb, line 105
def validate_from
  validate_address(FROM)
end
validate_to() click to toggle source

Return nil if this stanza has no 'to' attribute. Return a Vines::JID if it contains a valid 'to' attribute. Raise a JidMalformed error if the JID is invalid.

# File lib/vines/stanza.rb, line 98
def validate_to
  validate_address(TO)
end

Private Instance Methods

allowed?() click to toggle source

Return true if the to and from JIDs are allowed to communicate with one another based on the cross_domain_messages setting in conf/config.rb. If a domain's users are isolated to sending messages only within their own domain, pubsub stanzas must not be processed from remote JIDs.

# File lib/vines/stanza.rb, line 163
def allowed?
  stream.config.allowed?(validate_to || stream.domain, stream.user.jid)
end
broadcast_to_available_resources(stanzas, to) click to toggle source

Send the stanzas to the destination JID, routing to a s2s stream if the address is remote. This method properly stamps the to address on each stanza before it's sent. The caller must set the from address.

# File lib/vines/stanza.rb, line 118
def broadcast_to_available_resources(stanzas, to)
  return if send_to_remote(stanzas, to)
  send_to_recipients(stanzas, stream.available_resources(to))
end
broadcast_to_interested_resources(stanzas, to) click to toggle source

Send the stanzas to the destination JID, routing to a s2s stream if the address is remote. This method properly stamps the to address on each stanza before it's sent. The caller must set the from address.

# File lib/vines/stanza.rb, line 126
def broadcast_to_interested_resources(stanzas, to)
  return if send_to_remote(stanzas, to)
  send_to_recipients(stanzas, stream.interested_resources(to))
end
send_to_recipients(stanzas, recipients) click to toggle source

Send the stanzas to the local recipient streams, stamping a full JID as the to address. It's important to use full JIDs, even when sending to local clients, because the stanzas may be routed to other cluster nodes for delivery. We need the receiving cluster node to send the stanza just to this full JID, not to lookup all JIDs for this user.

# File lib/vines/stanza.rb, line 150
def send_to_recipients(stanzas, recipients)
  recipients.each do |recipient|
    stanzas.each do |el|
      el[TO] = recipient.user.jid.to_s
      recipient.write(el)
    end
  end
end
send_to_remote(stanzas, to) click to toggle source

Route the stanzas to a remote server, stamping a bare JID as the to address. Bare JIDs are required for presence subscription stanzas sent to the remote contact's server. Return true if the stanzas were routed, false if they must be delivered locally.

# File lib/vines/stanza.rb, line 135
def send_to_remote(stanzas, to)
  return false if local_jid?(to)
  to = JID.new(to)
  stanzas.each do |el|
    el[TO] = to.bare.to_s
    router.route(el)
  end
  true
end
validate_address(attr) click to toggle source
# File lib/vines/stanza.rb, line 167
def validate_address(attr)
  jid = (self[attr] || EMPTY)
  return if jid.empty?
  JID.new(jid)
rescue
  raise StanzaErrors::JidMalformed.new(self, 'modify')
end