Mercurial > prosody-modules
diff mod_minimix/mod_minimix.lua @ 2941:a57ed544fece
mod_minimix: Experiment in account-based MUC joins
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Thu, 22 Mar 2018 14:33:46 +0100 |
parents | |
children | 24e49391d4e8 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mod_minimix/mod_minimix.lua Thu Mar 22 14:33:46 2018 +0100 @@ -0,0 +1,116 @@ +-- mod_minimix +-- +-- Rewrite MUC stanzas suich that the account / bare JID joins rooms instead of clients / full JIDs +-- +local jid_split, jid_join, jid_node, jid_bare = import("util.jid", "split", "join", "node", "bare"); +local st = require "util.stanza"; + +local users = prosody.hosts[module.host].sessions; + +local joined_rooms = module:open_store("joined_rooms", "map"); -- TODO cache? +local room_state = module:open_store("joined_rooms_state", "map"); +local all_room_state = module:open_store("joined_rooms_state"); + +-- FIXME You can join but you can never leave. + +module:hook("pre-presence/full", function (event) + local origin, stanza = event.origin, event.stanza; + + local room_node, room_host, nickname = jid_split(stanza.attr.to); + local room_jid = jid_join(room_node, room_host); + local username = origin.username; + + if stanza.attr.type == nil and stanza:get_child("x", "http://jabber.org/protocol/muc") then + module:log("debug", "Joining %s as %s", room_jid, nickname); + + -- TODO Should this be kept track of before the *initial* join has been confirmed or? + if origin.joined_rooms then + origin.joined_rooms[room_jid] = nickname; + else + origin.joined_rooms = { [room_jid] = nickname }; + end + + if joined_rooms:get(username, room_jid) then + module:log("debug", "Already joined to %s as %s", room_jid, nickname); + local state = assert(all_room_state:get(username)); + for jid, stanza in pairs(state) do + if jid ~= room_jid and jid ~= stanza.attr.to then + origin.send(st.clone(st.deserialize(stanza))); + end + end + origin.send(st.deserialize(state[stanza.attr.to])); + origin.send(st.message({type="groupchat",to=origin.full_jid,from=room_jid}):tag("subject"):text(state[room_jid])); + -- Send on-join stanzas from local state, somehow + -- Maybe tell them their nickname was changed if it doesn't match the account one + return true; + end + + joined_rooms:set(username, room_jid, nickname); + + local account_join = st.clone(stanza); + account_join.attr.from = jid_join(origin.username, origin.host); + module:send(account_join); + + return true; + elseif stanza.attr.type == "unavailable" and joined_rooms:get(username, room_jid) then + origin.send(st.reply(stanza)); + return true; + end +end); + +module:hook("pre-message/bare", function (event) + local origin, stanza = event.origin, event.stanza; + local username = origin.username; + local room_jid = jid_bare(stanza.attr.to); + + module:log("info", "%s", stanza) + if joined_rooms:get(username, room_jid) then + local from_account = st.clone(stanza); + from_account.attr.from = jid_join(origin.username, origin.host); + module:log("debug", "Sending:\n%s\nInstead of:\n%s", from_account, stanza); + module:send(from_account, origin); + return true; + end +end); + +local function handle_to_bare_jid(event) + local origin, stanza = event.origin, event.stanza; + local username = jid_node(stanza.attr.to); + local room_jid = jid_bare(stanza.attr.from); + + if joined_rooms:get(username, room_jid) then + module:log("debug", "handle_to_bare_jid %q, %s", room_jid, stanza); + -- Broadcast to clients + + if stanza.name == "message" and stanza.attr.type == "groupchat" + and not stanza:get_child("body") and stanza:get_child("subject") then + room_state:set(username, room_jid, stanza:get_child_text("subject")); + elseif stanza.name == "presence" then + if stanza.attr.type == nil then + room_state:set(username, stanza.attr.from, st.preserialize(stanza)); + elseif stanza.attr.type == "unavailable" then + room_state:set(username, stanza.attr.from, nil); + end + end + + if users[username] then + module:log("debug", "%s has sessions", username); + for _, session in pairs(users[username].sessions) do + module:log("debug", "Session: %s", jid_join(session.username, session.host, session.resource)); + if session.joined_rooms and session.joined_rooms[room_jid] then + module:log("debug", "Is joined"); + local s = st.clone(stanza); + s.attr.to = session.full_jid; + session.send(s); + else + module:log("debug", "session.joined_rooms = %s", session.joined_rooms); + end + end + end + + return true; + end +end + +module:hook("presence/bare", handle_to_bare_jid); +module:hook("message/bare", handle_to_bare_jid);