# HG changeset patch # User Goffi # Date 1429297342 -7200 # Node ID 59ba224bf1459a6db1b175cda2bf69923986086c # Parent ad7afcf86131a0a1de4759353f71eeb62dbce981 mod_delegation: XEP-0355 implementation, first draft (configuration management + delegations advertising) diff -r ad7afcf86131 -r 59ba224bf145 mod_delegation/mod_delegation.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mod_delegation/mod_delegation.lua Fri Apr 17 21:02:22 2015 +0200 @@ -0,0 +1,134 @@ +-- XEP-0355 (Namespace Delegation) +-- Copyright (C) 2015 Jérôme Poisson +-- +-- This module is MIT/X11 licensed. Please see the +-- COPYING file in the source package for more information. + + +local jid = require("util/jid") +local st = require("util/stanza") +local set = require("util/set") + +local delegation_session = module:shared("/*/delegation/session") + +if delegation_session.connected_cb == nil then + -- set used to have connected event listeners + -- which allow a host to react on events from + -- other hosts + delegation_session.connected_cb = set.new() +end +local connected_cb = delegation_session.connected_cb + +local _DELEGATION_NS = 'urn:xmpp:delegation:1' +-- local _FORWARDED_NS = 'urn:xmpp:forward:0' + + +module:log("debug", "Loading namespace delegation module "); + + +--> Configuration management <-- + +local ns_delegations = module:get_option("delegations", {}) + +local jid2ns = {} +for namespace, config in pairs(ns_delegations) do + -- "connected" contain the full jid of connected managing entity + config.connected = nil + if config.jid then + if jid2ns[config.jid] == nil then + jid2ns[config.jid] = {} + end + jid2ns[config.jid][namespace] = config + else + module:log("warn", "Ignoring delegation for %s: no jid specified", tostring(namespace)) + ns_delegations[namespace] = nil + end +end + + +local function advertise_delegations(session, to_jid) + -- send stanza to advertise delegations + -- as expained in § 4.2 + local message = st.message({from=module.host, to=to_jid}) + :tag("delegation", {xmlns=_DELEGATION_NS}) + + -- we need to check if a delegation is granted because the configuration + -- can be complicated if some delegations are granted to bare jid + -- and other to full jids, and several resources are connected. + local have_delegation = false + + for namespace, config in pairs(jid2ns[to_jid]) do + if config.connected == to_jid then + have_delegation = true + message:tag("delegated", {namespace=namespace}) + if type(config.filtering) == "table" then + for _, attribute in pairs(config.filtering) do + message:tag("attribute", {name=attribute}):up() + end + message:up() + end + end + end + + if have_delegation then + session.send(message) + end +end + +local function set_connected(entity_jid) + -- set the "connected" key for all namespace managed by entity_jid + -- if the namespace has already a connected entity, ignore the new one + local function set_config(jid_) + for _, config in pairs(jid2ns[jid_]) do + if config.connected == nil then + config.connected = entity_jid + end + end + end + local bare_jid = jid.bare(entity_jid) + set_config(bare_jid) + -- We can have a bare jid of a full jid specified in configuration + -- so we try our luck with both (first connected resource will + -- manage the namespaces in case of bare jid) + if bare_jid ~= entity_jid then + set_config(entity_jid) + jid2ns[entity_jid] = jid2ns[bare_jid] + end +end + +local function on_presence(event) + local session = event.origin + local bare_jid = jid.bare(session.full_jid) + + if jid2ns[bare_jid] or jid2ns[session.full_jid] then + set_connected(session.full_jid) + advertise_delegations(session, session.full_jid) + end +end + +local function on_component_connected(event) + -- method called by the module loaded by the component + -- /!\ the event come from the component host, + -- not from the host of this module + local session = event.session + local bare_jid = jid.join(session.username, session.host) + + local jid_delegations = jid2ns[bare_jid] + if jid_delegations ~= nil then + set_connected(bare_jid) + advertise_delegations(session, bare_jid) + end +end + +local function on_component_auth(event) + -- react to component-authenticated event from this host + -- and call the on_connected methods from all other hosts + -- needed for the component to get delegations advertising + for callback in connected_cb:items() do + callback(event) + end +end + +connected_cb:add(on_component_connected) +module:hook('component-authenticated', on_component_auth) +module:hook('presence/initial', on_presence)