diff --git a/mod_mix_pam/mod_mix_pam.lua b/mod_mix_pam/mod_mix_pam.lua index f333e0f..bd92ab7 100644 --- a/mod_mix_pam/mod_mix_pam.lua +++ b/mod_mix_pam/mod_mix_pam.lua @@ -1,6 +1,6 @@ -local host = module:get_host() +local module_host = module:get_host(); --[[ -if host ~= "*" then +if module_host ~= "*" then module:log("error", "mix_pam should be used on the user host!"); end ]]-- @@ -26,13 +26,13 @@ module:add_feature(mix_pam_xmlns); -- NOTE: To show that we archive messages -- module:add_feature(mix_pam_xmlns.."#archive"); -function contains_key(table, key) +local function contains_key(table, key) -- Returns true if table contains the key key. Returns false -- otherwise. return table[key] ~= nil; end -function set_mix_spid(user, channel, spid) +local function set_mix_spid(user, channel, spid) if mix_spids[user] ~= nil then mix_spids[user][channel] = spid; else @@ -41,10 +41,10 @@ function set_mix_spid(user, channel, spid) mix_pam:set("spids", mix_spids); end -function get_mix_spid(user, channel) +local function get_mix_spid(user, channel) return mix_spids[user][channel]; end; -function remove_mix_spid(user, channel) +local function remove_mix_spid(user, channel) mix_spids[user][channel] = nil; if mix_spids[user][channel] == {} then mix_spids[user][channel] = nil; @@ -53,7 +53,7 @@ function remove_mix_spid(user, channel) mix_pam:set("spids", mix_spids); end -function add_mix_host(host) +local function add_mix_host(host) if mix_hosts[host] ~= nil then mix_hosts[host] = mix_hosts[host] + 1; module:log("debug", "Known MIX host has a new user"); @@ -64,9 +64,8 @@ function add_mix_host(host) mix_pam:set("hosts", mix_hosts); end - -function remove_mix_host(host) - if mix_hosts[host] ~= nil then +local function remove_mix_host(host) + if mix_hosts[host] ~= nil then local count = mix_hosts[host]; if count == 1 then mix_hosts[host] = nil; @@ -81,19 +80,18 @@ function remove_mix_host(host) mix_pam:set("hosts", mix_hosts); end - -function is_mix_host(host) +local function is_mix_host(host) return mix_hosts[host] ~= nil; end -function is_mix_message(stanza) +local function is_mix_message(stanza) return stanza:get_child("mix", "urn:xmpp:mix:core:1") ~= nil; end function module.load() mix_hosts = mix_pam:get("hosts"); module:log("info", "Loaded known MIX hosts"); - + if mix_hosts == nil then module:log("info", "No known MIX hosts loaded"); mix_hosts = {}; @@ -104,7 +102,7 @@ function module.load() mix_spids = mix_pam:get("spids"); module:log("info", "Loaded known MIX SPIDs"); - + if mix_spids == nil then module:log("info", "No known MIX SPIDs loaded"); mix_spids = {}; @@ -122,14 +120,14 @@ function module.load() end local client_state_tracker = {}; -- [stanza ID] -> resource -function add_state(id, resource) +local function add_state(id, resource) client_state_tracker[id] = resource; module:log("debug", "Adding a resource %s for id %s", resource, id); end -function has_state(id) +local function has_state(id) return client_state_tracker[id] ~= nil; end -function pop_state(id) +local function pop_state(id) module:log("debug", "Popping a resource for stanza id %s", id); if has_state(id) then @@ -141,6 +139,70 @@ function pop_state(id) return nil; end +local function handle_client_join(event) + -- Client requests to join + module:log("debug", "client-join received"); + local stanza, origin = event.stanza, event.origin; + local from = jid.bare(stanza.attr.from); + + local client_join = stanza:get_child("client-join", mix_pam_xmlns); + if client_join.attr.channel == nil then + origin.send(st.error_reply(stanza, "cancel", "bad-request", "No channel specified")); + return true; + end + local join = client_join:get_child("join", "urn:xmpp:mix:core:1"); + if join == nil then + origin.send(st.error_reply(stanza, "cancel", "bad-request", "No join stanza")); + return true; + end + + -- Transform the client-join into a join + local join_iq = st.iq({ + type = "set"; + from = jid.bare(stanza.attr.from); + to = client_join.attr.channel; + id = stanza.attr.id, xmlns = "jabber:client" + }); + join_iq:add_child(join); + + add_state(stanza.attr.id, jid.resource(from)); + + module:send(join_iq); + return true; +end + +local function handle_client_leave(event) + -- Client requests to leave + module:log("debug", "client-leave received"); + local stanza, origin = event.stanza, event.origin; + local from = jid.bare(stanza.attr.from); + + local client_leave = stanza:get_child("client-leave", mix_pam_xmlns); + if client_leave.attr.channel == nil then + origin.send(st.error_reply(stanza, "cancel", "bad-request", "No channel specified")); + return true; + end + local leave = client_leave:get_child("leave", "urn:xmpp:mix:core:1"); + if leave == nil then + origin.send(st.error_reply(stanza, "cancel", "bad-request", "No leave stanza")); + return true; + end + + -- Transform the client-join into a join + local leave_iq = st.iq({ + type = "set"; + from = jid.bare(stanza.attr.from); + to = client_leave.attr.channel; + id = stanza.attr.id + }); + leave_iq:add_child(leave); + + add_state(stanza.attr.id, jid.resource(from)); + + module:send(leave_iq); + return true; +end + module:hook("iq/self", function(event) local stanza = event.stanza; if #stanza.tags == 0 then return; end @@ -152,57 +214,80 @@ module:hook("iq/self", function(event) end end); -function handle_client_join(event) - -- Client requests to join - module:log("debug", "client-join received"); - local stanza, origin = event.stanza, event.origin; - local from, to = jid.bare(stanza.attr.from), jid.bare(stanza.attr.to); - - local client_join = stanza:get_child("client-join", mix_pam_xmlns); - if client_join.attr.channel == nil then - origin.send(st.error_reply(stanza, "cancel", "bad-request", "No channel specified")); - return true; - end - local join = client_join:get_child("join", "urn:xmpp:mix:core:1"); - if join == nil then - origin.send(st.error_reply(stanza, "cancel", "bad-request", "No join stanza")); - return true; +local function handle_mix_join(event) + -- The MIX server responded + module:log("debug", "Received MIX-JOIN result"); + module:log("debug", "Adding %s as a new MIX host", jid.host(event.stanza.attr.from)); + add_mix_host(jid.host(event.stanza.attr.from)); + mix_pam:set("hosts", mix_hosts); + + local stanza = event.stanza; + local spid = stanza:get_child("join", "urn:xmpp:mix:core:1").attr.id; + local channel_jid = spid.."#"..stanza.attr.from; + local origin = pop_state(stanza.attr.id); + local resource = origin.resource; + if resource == nil then + module:log("error", "Got a MIX join result for a not-requested id %s", stanza.attr.id); + module:log("error", "Maybe the server changed the stanza ID?"); + return false; end - -- Transform the client-join into a join - local join_iq = st.iq({ type = "set", from = jid.bare(stanza.attr.from), to = client_join.attr.channel, id = stanza.attr.id, xmlns = "jabber:client" }); - join_iq:add_child(join); - - add_state(stanza.attr.id, jid.resource(from)); + -- Keep track of the SPID + set_mix_spid(stanza.attr.to, stanza.attr.from, spid); + + local client_join = st.iq({ + type = "result"; + id = stanza.attr.id; + from = jid.bare(stanza.attr.to); + to = stanza.attr.to.."/"..resource + }):tag("client-join", { xmlns = mix_pam_xmlns, jid = channel_jid }); + + client_join:add_child(stanza:get_child("join", "urn:xmpp:mix:core:1")); + module:send(client_join); + + -- TODO: Error handling? + rm_add_to_roster(origin, stanza.attr.from, { + subscription = "both", + groups = {}, + }); + rm_roster_push(jid.node(stanza.attr.to), module_host, stanza.attr.from); - module:send(join_iq); return true; end -function handle_client_leave(event) - -- Client requests to leave - module:log("debug", "client-leave received"); - local stanza, origin = event.stanza, event.origin; - local from, to = jid.bare(stanza.attr.from), jid.bare(stanza.attr.to); - - local client_leave = stanza:get_child("client-leave", mix_pam_xmlns); - if client_leave.attr.channel == nil then - origin.send(st.error_reply(stanza, "cancel", "bad-request", "No channel specified")); - return true; - end - local leave = client_leave:get_child("leave", "urn:xmpp:mix:core:1"); - if leave == nil then - origin.send(st.error_reply(stanza, "cancel", "bad-request", "No leave stanza")); - return true; +local function handle_mix_leave(event) + -- The MIX server responded + module:log("debug", "Received MIX-LEAVE result"); + remove_mix_host(jid.host(event.stanza.attr.from)); + mix_pam:set("hosts", mix_hosts); + + local stanza = event.stanza; + local origin = pop_state(stanza.attr.id); + local resource = origin.resource; + if resource == nil then + module:log("error", "Got a MIX leave result for a not-requested id %s", stanza.attr.id); + module:log("error", "Maybe the MIX server changed the stanza ID?"); + return false; end - -- Transform the client-join into a join - local leave_iq = st.iq({ type = "set", from = jid.bare(stanza.attr.from), to = client_leave.attr.channel, id = stanza.attr.id }); - leave_iq:add_child(leave); + -- Keep track of the SPID + set_mix_spid(stanza.attr.to, jid.bare(stanza.attr.from)); - add_state(stanza.attr.id, jid.resource(from)); + local client_leave = st.iq({ + type = "result"; + id = stanza.attr.id; + from = jid.bare(stanza.attr.to); + to = stanza.attr.to.."/"..resource + }):tag("client-leave", { xmlns = mix_pam_xmlns }); + + client_leave:add_child(stanza:get_child("leave", "urn:xmpp:mix:core:1")); + module:send(client_leave); + + -- Remove from roster + -- TODO: Error handling + rm_remove_from_roster(origin, jid.bare(stanza.attr.from)); + rm_roster_push(jid.node(stanza.attr.to), module_host, jid.bare(stanza.attr.from)); - module:send(leave_iq); return true; end @@ -222,98 +307,33 @@ module:hook("iq/bare", function(event) end end); -function handle_mix_join(event) - -- The MIX server responded - module:log("debug", "Received MIX-JOIN result"); - module:log("debug", "Adding %s as a new MIX host", jid.host(event.stanza.attr.from)); - add_mix_host(jid.host(event.stanza.attr.from)); - mix_pam:set("hosts", mix_hosts); - - local stanza = event.stanza; - local spid = stanza:get_child("join", "urn:xmpp:mix:core:1").attr.id; - local channel_jid = spid.."#"..stanza.attr.from; - local origin = pop_state(stanza.attr.id); - local resource = origin.resource; - if resource == nil then - module:log("error", "Got a MIX join result for a not-requested id %s. Maybe the MIX server changed the stanza ID?", stanza.attr.id); - return false; - end - - -- Keep track of the SPID - set_mix_spid(stanza.attr.to, stanza.attr.from, spid); - - local client_join = st.iq({ type = "result", id = stanza.attr.id, from = jid.bare(stanza.attr.to), to = stanza.attr.to.."/"..resource }) - :tag("client-join", { xmlns = mix_pam_xmlns, jid = channel_jid }); - client_join:add_child(stanza:get_child("join", "urn:xmpp:mix:core:1")); - module:send(client_join); - - -- TODO: Error handling? - rm_add_to_roster(origin, stanza.attr.from, { - subscription = "both", - groups = {}, - }); - rm_roster_push(jid.node(stanza.attr.to), host, stanza.attr.from); - - return true; -end - -function handle_mix_leave(event) - -- The MIX server responded - module:log("debug", "Received MIX-LEAVE result"); - remove_mix_host(jid.host(event.stanza.attr.from)); - mix_pam:set("hosts", mix_hosts); - - local stanza = event.stanza; - local origin = pop_state(stanza.attr.id); - local resource = origin.resource; - if resource == nil then - module:log("error", "Got a MIX leave result for a not-requested id %s. Maybe the MIX server changed the stanza ID?", stanza.attr.id); - return false; - end - - -- Keep track of the SPID - set_mix_spid(stanza.attr.to, jid.bare(stanza.attr.from)); - - local client_leave = st.iq({ type = "result", id = stanza.attr.id, from = jid.bare(stanza.attr.to), to = stanza.attr.to.."/"..resource }) - :tag("client-leave", { xmlns = mix_pam_xmlns }); - client_leave:add_child(stanza:get_child("leave", "urn:xmpp:mix:core:1")); - module:send(client_leave); - - -- Remove from roster - -- TODO: Error handling - rm_remove_from_roster(origin, jid.bare(stanza.attr.from)); - rm_roster_push(jid.node(stanza.attr.to), host, jid.bare(stanza.attr.from)); - - return true; -end - local user_resources = {}; -- [bare jid] -> array of bound resources module:hook("resource-bind", function(event) - local jid, resource = jid.bare(event.session.full_jid), event.session.resource; - if user_resources[jid] ~= nil then + local session_jid, resource = jid.bare(event.session.full_jid), event.session.resource; + if user_resources[session_jid] ~= nil then for _, r in pairs(user_resources) do if r == resource then return; end end - table.insert(user_resources[jid], resource); + table.insert(user_resources[session_jid], resource); else - user_resources[jid] = { resource }; + user_resources[session_jid] = { resource }; end - module:log("debug", "Caught resource %s of %s", resource, jid); + module:log("debug", "Caught resource %s of %s", resource, session_jid); end); module:hook("resource-unbind", function(event) - local jid, resource = jid.bare(event.session.full_jid), event.session.resource; - for i, r in pairs(user_resources[jid]) do + local session_jid, resource = jid.bare(event.session.full_jid), event.session.resource; + for i, r in pairs(user_resources[session_jid]) do if r == resource then - table.remove(user_resources[jid], i); + table.remove(user_resources[session_jid], i); return; end end - module:log("debug", "Unbind of not recorded resource %s (%s)", resource, jid); + module:log("debug", "Unbind of not recorded resource %s (%s)", resource, session_jid); end); module:hook("roster-get", function(event) @@ -323,7 +343,7 @@ module:hook("roster-get", function(event) :get_child("query", "jabber:iq:roster") :get_child("annotate", mix_roster_xmlns); if not annotate then return; end - local reply, stanza = event.reply, event.stanza; + local stanza = event.stanza; module:log("debug", "Annotated roster request received"); @@ -341,10 +361,10 @@ end); module:hook("message/bare", function(event) local stanza = event.stanza; - local host = jid.host(stanza.attr.from); - if not is_mix_host(host) then return; end + local jid_host = jid.host(stanza.attr.from); + if not is_mix_host(jid_host) then return; end if not is_mix_message(stanza) then return; end - + -- MIX-CORE says that if the message cannot be delivered, it should -- just be dropped if user_resources[stanza.attr.to] == nil then