mirror of
https://github.com/moparisthebest/mod_xxxx
synced 2024-12-21 23:18:56 -05:00
178 lines
5.0 KiB
Lua
178 lines
5.0 KiB
Lua
local verse = require "verse";
|
|
local events = require "events";
|
|
local jid = require "util.jid";
|
|
|
|
local room_mt = {};
|
|
room_mt.__index = room_mt;
|
|
|
|
local xmlns_delay = "urn:xmpp:delay";
|
|
local xmlns_muc = "http://jabber.org/protocol/muc";
|
|
|
|
function verse.plugins.groupchat(stream)
|
|
stream:add_plugin("presence")
|
|
stream.rooms = {};
|
|
|
|
stream:hook("stanza", function (stanza)
|
|
local room_jid = jid.bare(stanza.attr.from);
|
|
if not room_jid then return end
|
|
local room = stream.rooms[room_jid]
|
|
if not room and stanza.attr.to and room_jid then
|
|
room = stream.rooms[stanza.attr.to.." "..room_jid]
|
|
end
|
|
if room and room.opts.source and stanza.attr.to ~= room.opts.source then return end
|
|
if room then
|
|
local nick = select(3, jid.split(stanza.attr.from));
|
|
local body = stanza:get_child_text("body");
|
|
local delay = stanza:get_child("delay", xmlns_delay);
|
|
local event = {
|
|
room_jid = room_jid;
|
|
room = room;
|
|
sender = room.occupants[nick];
|
|
nick = nick;
|
|
body = body;
|
|
stanza = stanza;
|
|
delay = (delay and delay.attr.stamp);
|
|
};
|
|
local ret = room:event(stanza.name, event);
|
|
return ret or (stanza.name == "message") or nil;
|
|
end
|
|
end, 500);
|
|
|
|
function stream:join_room(jid, nick, opts)
|
|
if not nick then
|
|
return false, "no nickname supplied"
|
|
end
|
|
opts = opts or {};
|
|
local room = setmetatable(verse.eventable{
|
|
stream = stream, jid = jid, nick = nick,
|
|
subject = nil,
|
|
occupants = {},
|
|
opts = opts,
|
|
}, room_mt);
|
|
if opts.source then
|
|
self.rooms[opts.source.." "..jid] = room;
|
|
else
|
|
self.rooms[jid] = room;
|
|
end
|
|
local occupants = room.occupants;
|
|
room:hook("presence", function (presence)
|
|
local nick = presence.nick or nick;
|
|
if not occupants[nick] and presence.stanza.attr.type ~= "unavailable" then
|
|
occupants[nick] = {
|
|
nick = nick;
|
|
jid = presence.stanza.attr.from;
|
|
presence = presence.stanza;
|
|
};
|
|
local x = presence.stanza:get_child("x", xmlns_muc .. "#user");
|
|
if x then
|
|
local x_item = x:get_child("item");
|
|
if x_item and x_item.attr then
|
|
occupants[nick].real_jid = x_item.attr.jid;
|
|
occupants[nick].affiliation = x_item.attr.affiliation;
|
|
occupants[nick].role = x_item.attr.role;
|
|
end
|
|
--TODO Check for status 100?
|
|
end
|
|
if nick == room.nick then
|
|
room.stream:event("groupchat/joined", room);
|
|
else
|
|
room:event("occupant-joined", occupants[nick]);
|
|
end
|
|
elseif occupants[nick] and presence.stanza.attr.type == "unavailable" then
|
|
if nick == room.nick then
|
|
room.stream:event("groupchat/left", room);
|
|
if room.opts.source then
|
|
self.rooms[room.opts.source.." "..jid] = nil;
|
|
else
|
|
self.rooms[jid] = nil;
|
|
end
|
|
else
|
|
occupants[nick].presence = presence.stanza;
|
|
room:event("occupant-left", occupants[nick]);
|
|
occupants[nick] = nil;
|
|
end
|
|
end
|
|
end);
|
|
room:hook("message", function(event)
|
|
local subject = event.stanza:get_child_text("subject");
|
|
if not subject then return end
|
|
subject = #subject > 0 and subject or nil;
|
|
if subject ~= room.subject then
|
|
local old_subject = room.subject;
|
|
room.subject = subject;
|
|
return room:event("subject-changed", { from = old_subject, to = subject, by = event.sender, event = event });
|
|
end
|
|
end, 2000);
|
|
local join_st = verse.presence():tag("x",{xmlns = xmlns_muc}):reset();
|
|
self:event("pre-groupchat/joining", join_st);
|
|
room:send(join_st)
|
|
self:event("groupchat/joining", room);
|
|
return room;
|
|
end
|
|
|
|
stream:hook("presence-out", function(presence)
|
|
if not presence.attr.to then
|
|
for _, room in pairs(stream.rooms) do
|
|
room:send(presence);
|
|
end
|
|
presence.attr.to = nil;
|
|
end
|
|
end);
|
|
end
|
|
|
|
function room_mt:send(stanza)
|
|
if stanza.name == "message" and not stanza.attr.type then
|
|
stanza.attr.type = "groupchat";
|
|
end
|
|
if stanza.name == "presence" then
|
|
stanza.attr.to = self.jid .."/"..self.nick;
|
|
end
|
|
if stanza.attr.type == "groupchat" or not stanza.attr.to then
|
|
stanza.attr.to = self.jid;
|
|
end
|
|
if self.opts.source then
|
|
stanza.attr.from = self.opts.source
|
|
end
|
|
self.stream:send(stanza);
|
|
end
|
|
|
|
function room_mt:send_message(text)
|
|
self:send(verse.message():tag("body"):text(text));
|
|
end
|
|
|
|
function room_mt:set_subject(text)
|
|
self:send(verse.message():tag("subject"):text(text));
|
|
end
|
|
|
|
function room_mt:leave(message)
|
|
self.stream:event("groupchat/leaving", self);
|
|
local presence = verse.presence({type="unavailable"});
|
|
if message then
|
|
presence:tag("status"):text(message);
|
|
end
|
|
self:send(presence);
|
|
end
|
|
|
|
function room_mt:admin_set(nick, what, value, reason)
|
|
self:send(verse.iq({type="set"})
|
|
:query(xmlns_muc .. "#admin")
|
|
:tag("item", {nick = nick, [what] = value})
|
|
:tag("reason"):text(reason or ""));
|
|
end
|
|
|
|
function room_mt:set_role(nick, role, reason)
|
|
self:admin_set(nick, "role", role, reason);
|
|
end
|
|
|
|
function room_mt:set_affiliation(nick, affiliation, reason)
|
|
self:admin_set(nick, "affiliation", affiliation, reason);
|
|
end
|
|
|
|
function room_mt:kick(nick, reason)
|
|
self:set_role(nick, "none", reason);
|
|
end
|
|
|
|
function room_mt:ban(nick, reason)
|
|
self:set_affiliation(nick, "outcast", reason);
|
|
end
|