plugins/groupchat.lua

changeset 56
cb7656ee4dd8
parent 46
1f0fa4af29b8
child 60
87ecc6324155
equal deleted inserted replaced
55:3a321510707c 56:cb7656ee4dd8
1 local events = require "events";
2 local st = require "util.stanza"; 1 local st = require "util.stanza";
3
4 local room_mt = {};
5 room_mt.__index = room_mt;
6
7 local xmlns_delay = "urn:xmpp:delay";
8 local xmlns_muc = "http://jabber.org/protocol/muc"; 2 local xmlns_muc = "http://jabber.org/protocol/muc";
9 3
10 function riddim.plugins.groupchat(bot) 4 function riddim.plugins.groupchat(bot)
11 bot.rooms = {}; 5 bot.stream:add_plugin("groupchat")
6 bot.rooms = bot.stream.rooms;
12 7
13 bot:hook("started", function () 8 bot:hook("started", function ()
14 for k, v in pairs(bot.config.autojoin or {}) do 9 for k, v in pairs(bot.config.autojoin or {}) do
15 if type(k) == "number" then 10 if type(k) == "number" then
16 bot:join_room(v); 11 bot:join_room(v);
20 end 15 end
21 end 16 end
22 end 17 end
23 end); 18 end);
24 19
25 bot.stream:hook("stanza", function (stanza) 20 -- Re-broadcast groupchat event on the bot
26 local room_jid = jid.bare(stanza.attr.from); 21 local reflect_events = { "groupchat/joining"; "groupchat/joined"; "groupchat/leaving"; "groupchat/left" };
27 local room = bot.rooms[room_jid] 22 for i = 1,#reflect_events do
28 if room then 23 bot.stream:hook(reflect_events[i], function(room, ...)
29 local nick = select(3, jid.split(stanza.attr.from)); 24 room.bot = bot;
30 local body = stanza:get_child("body"); 25 bot:event(reflect_events[i], room, ...)
31 local delay = stanza:get_child("delay", xmlns_delay); 26 end);
32 local event = { 27 end
33 room_jid = room_jid; 28
34 room = room; 29 function bot:join_room(room_jid, nick)
35 sender = room.occupants[nick]; 30 nick = nick or bot.config.nick or ("bot"..math.random(10000,99999));
36 nick = nick; 31 local room = bot.stream:join_room(room_jid, nick)
37 body = (body and body:get_text()) or nil; 32 room.bot = bot;
38 stanza = stanza; 33 room:hook("message", function(event)
39 delay = (delay and delay.attr.stamp); 34 if event.nick == room.nick then
40 }; 35 return true;
41 if stanza.name == "message" then 36 end
42 local replied; 37 end, 1000);
43 local r = st.reply(stanza); 38 room:hook("message", function(event)
44 if stanza.attr.type == "groupchat" then 39 local stanza = event.stanza;
45 r.attr.type = stanza.attr.type; 40 local replied;
46 r.attr.to = jid.bare(stanza.attr.to); 41 local r = st.reply(stanza);
42 if stanza.attr.type == "groupchat" then
43 r.attr.type = stanza.attr.type;
44 r.attr.to = jid.bare(stanza.attr.to);
45 end
46 function event:reply(reply)
47 if not reply then reply = "Nothing to say to you"; end
48 if replied then return false; end
49 replied = true;
50 if r.attr.type == "groupchat" then
51 reply = event.sender.nick..": "..reply;
47 end 52 end
48 function event:reply(reply) 53 room:send(r:tag("body"):text(reply));
49 if not reply then reply = "Nothing to say to you"; end
50 if replied then return false; end
51 replied = true;
52 if r.attr.type == "groupchat" then
53 reply = event.sender.nick..": "..reply;
54 end
55 room:send(r:tag("body"):text(reply));
56 end
57 end 54 end
58 local ret; 55 end, 500);
59 if stanza.name ~= "message" or nick ~= room.nick then
60 ret = room:event(stanza.name, event);
61 end
62 return ret or (stanza.name == "message") or nil;
63 end
64 end, 500);
65
66 function bot:join_room(jid, nick)
67 nick = nick or bot.config.nick or ("bot"..math.random(10000,99999));
68 local room = setmetatable({
69 bot = bot, jid = jid, nick = nick,
70 occupants = {},
71 events = events.new()
72 }, room_mt);
73 self.rooms[jid] = room;
74 local occupants = room.occupants;
75 room:hook("presence", function (presence)
76 local nick = presence.nick or nick;
77 if not occupants[nick] and presence.stanza.attr.type ~= "unavailable" then
78 occupants[nick] = {
79 nick = nick;
80 jid = presence.stanza.attr.from;
81 presence = presence.stanza;
82 };
83 local x = presence.stanza:get_child("x", xmlns_muc .. "#user");
84 if x then
85 local x_item = x:get_child("item");
86 if x_item and x_item.attr then
87 occupants[nick].real_jid = x_item.attr.jid;
88 occupants[nick].affiliation = x_item.attr.affiliation;
89 occupants[nick].role = x_item.attr.role;
90 end
91 end
92 if nick == room.nick then
93 room.bot:event("groupchat/joined", room);
94 else
95 room:event("occupant-joined", occupants[nick]);
96 end
97 elseif occupants[nick] and presence.stanza.attr.type == "unavailable" then
98 if nick == room.nick then
99 room.bot:event("groupchat/left", room);
100 self.rooms[room.jid] = nil;
101 else
102 occupants[nick].presence = presence.stanza;
103 room:event("occupant-left", occupants[nick]);
104 occupants[nick] = nil;
105 end
106 end
107 end);
108 self:send(st.presence({to = jid.."/"..nick})
109 :tag("x",{xmlns = xmlns_muc}):tag("history",{maxstanzas = 0}));
110 self:event("groupchat/joining", room);
111 return room; 56 return room;
112 end 57 end
58
59 bot.stream:hook("pre-groupchat/joining", function(presence)
60 local muc_x = presence:get_child("x", xmlns_muc);
61 if muc_x then
62 muc_x:tag("history",{maxstanzas = 0});
63 end
64 end);
113 end 65 end
114
115 function room_mt:send(stanza)
116 if stanza.name == "message" and not stanza.attr.type then
117 stanza.attr.type = "groupchat";
118 end
119 if stanza.attr.type == "groupchat" or not stanza.attr.to then
120 stanza.attr.to = self.jid;
121 end
122 self.bot:send(stanza);
123 end
124
125 function room_mt:send_message(text)
126 self:send(st.message():tag("body"):text(text));
127 end
128
129 function room_mt:leave(message)
130 self.bot:event("groupchat/leaving", room);
131 self:send(st.presence({type="unavailable"}));
132 end
133
134 function room_mt:set_role(nick, role, reason)
135 self:send(st.iq({type="set"})
136 :query(xmlns_muc .. "#admin")
137 :tag("item", {nick = nick, role = role})
138 :tag("reason"):text(reason or ""));
139 end
140
141 function room_mt:set_affiliation(nick, affiliation, reason)
142 self:send(st.iq({type="set"})
143 :query(xmlns_muc .. "#admin")
144 :tag("item", {nick = nick, affiliation = affiliation})
145 :tag("reason"):text(reason or ""));
146 end
147
148 function room_mt:event(name, arg)
149 self.bot.stream:debug("Firing room event: %s", name);
150 return self.events.fire_event(name, arg);
151 end
152
153 function room_mt:hook(name, callback, priority)
154 return self.events.add_handler(name, callback, priority);
155 end

mercurial