plugins/groupchat.lua

changeset 0
7d84f4403d67
child 9
8c3bec93087b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/groupchat.lua	Mon Dec 21 19:27:08 2009 +0000
@@ -0,0 +1,115 @@
+local events = require "events";
+local st = require "util.stanza";
+
+local room_mt = {};
+room_mt.__index = room_mt;
+
+local xmlns_delay = "urn:xmpp:delay";
+
+function riddim.plugins.groupchat(bot)
+	bot.rooms = {};
+	
+	bot.stream:hook("stanza", function (stanza)
+		local room_jid = jid.bare(stanza.attr.from);
+		local room = bot.rooms[room_jid]
+		if room then
+			local nick = select(3, jid.split(stanza.attr.from));
+			local body = stanza:get_child("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 and body:get_text()) or nil;
+					stanza = stanza;
+					delay = (delay and delay.attr.stamp);
+				};
+			if stanza.name == "message" then
+				local replied;
+				local r = st.reply(stanza);
+				if stanza.attr.type == "groupchat" then
+					r.attr.type = stanza.attr.type;
+					r.attr.to = jid.bare(stanza.attr.to);
+				end
+				function event:reply(reply)
+					if not reply then reply = "Nothing to say to you"; end
+					if replied then return false; end
+					replied = true;
+					if r.attr.type == "groupchat" then
+						reply = event.sender.nick..": "..reply;
+					end
+					room:send(r:tag("body"):text(reply));
+				end
+			end
+			local ret;
+			if stanza.name ~= "message" or nick ~= room.nick then
+				ret = room:event(stanza.name, event);
+			end
+			return ret or (stanza.name == "message") or nil;
+		end
+	end, 500);
+	
+	function bot:join_room(jid, nick)
+		nick = nick or bot.config.nick or ("bot"..math.random(10000,99999));
+		local room = setmetatable({
+			bot = bot, jid = jid, nick = nick,
+			occupants = {},
+			events = events.new() }, room_mt);
+		self.rooms[jid] = room;
+		local occupants = room.occupants;
+		room:hook("presence", function (presence)
+			local nick = presence.nick;
+			if not occupants[nick] then
+				if presence.type ~= "unavailable" then
+					occupants[nick] = {
+						nick = nick;
+						jid = presence.stanza.attr.from;
+						presence = presence.stanza;
+						};
+					if nick == room.nick then
+						room.bot:event("groupchat/joined", room);
+					else
+						room:event("occupant-joined", occupants[nick]);
+					end
+				else
+					occupants[nick].presence = presence.stanza;
+					room:event("occupant-left", occupants[nick]);
+					occupants[nick] = nil;
+				end
+			end
+		end);
+		self:send(st.presence({to = jid.."/"..nick}));
+		self:event("groupchat/joining", room);
+		return room;
+	end
+end
+
+function room_mt:send(stanza)
+	if stanza.name == "message" and not stanza.attr.type then
+		stanza.attr.type = "groupchat";
+	end
+	if stanza.attr.type == "groupchat" then
+		stanza.attr.to = self.jid;
+	end
+	self.bot:send(stanza);
+end
+
+function room_mt:send_message(text)
+	self:send(st.message():tag("body"):text(text));
+end
+
+function room_mt:leave(message)
+	self.bot:event("groupchat/leaving", room);
+	self:send(st.presence({type="unavailable"}));
+	self.bot:event("groupchat/left", room);
+end
+
+function room_mt:event(name, arg)
+	self.bot.stream:debug("Firing room event: %s", name);
+	return self.events.fire_event(name, arg);
+end
+
+function room_mt:hook(name, callback, priority)
+	return self.events.add_handler(name, callback, priority);
+end

mercurial