Software / code / verse
Comparison
plugins/groupchat.lua @ 182:51c0baa2bd19
plugins.groupchat: Adapt from Riddim
| author | Kim Alvefur <zash@zash.se> |
|---|---|
| date | Tue, 11 Jan 2011 23:14:30 +0100 |
| child | 184:8173e57522bf |
comparison
equal
deleted
inserted
replaced
| 181:c61ba3d1b39a | 182:51c0baa2bd19 |
|---|---|
| 1 local events = require "events"; | |
| 2 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"; | |
| 9 | |
| 10 function verse.plugins.groupchat(stream) | |
| 11 stream:add_plugin("presence") | |
| 12 stream.rooms = {}; | |
| 13 | |
| 14 stream:hook("stanza", function (stanza) | |
| 15 local room_jid = jid.bare(stanza.attr.from); | |
| 16 local room = stream.rooms[room_jid] | |
| 17 if room then | |
| 18 local nick = select(3, jid.split(stanza.attr.from)); | |
| 19 local body = stanza:get_child("body"); | |
| 20 local delay = stanza:get_child("delay", xmlns_delay); | |
| 21 local event = { | |
| 22 room_jid = room_jid; | |
| 23 room = room; | |
| 24 sender = room.occupants[nick]; | |
| 25 nick = nick; | |
| 26 body = (body and body:get_text()) or nil; | |
| 27 stanza = stanza; | |
| 28 delay = (delay and delay.attr.stamp); | |
| 29 }; | |
| 30 local ret = room:event(stanza.name, event); | |
| 31 return ret or (stanza.name == "message") or nil; | |
| 32 end | |
| 33 end, 500); | |
| 34 | |
| 35 function stream:join_room(jid, nick) | |
| 36 if not nick then | |
| 37 return false, "no nickname supplied" | |
| 38 end | |
| 39 local room = setmetatable({ | |
| 40 stream = stream, jid = jid, nick = nick, | |
| 41 subject = "", | |
| 42 occupants = {}, | |
| 43 events = events.new() | |
| 44 }, room_mt); | |
| 45 self.rooms[jid] = room; | |
| 46 local occupants = room.occupants; | |
| 47 room:hook("presence", function (presence) | |
| 48 local nick = presence.nick or nick; | |
| 49 if not occupants[nick] and presence.stanza.attr.type ~= "unavailable" then | |
| 50 occupants[nick] = { | |
| 51 nick = nick; | |
| 52 jid = presence.stanza.attr.from; | |
| 53 presence = presence.stanza; | |
| 54 }; | |
| 55 local x = presence.stanza:get_child("x", xmlns_muc .. "#user"); | |
| 56 if x then | |
| 57 local x_item = x:get_child("item"); | |
| 58 if x_item and x_item.attr then | |
| 59 occupants[nick].real_jid = x_item.attr.jid; | |
| 60 occupants[nick].affiliation = x_item.attr.affiliation; | |
| 61 occupants[nick].role = x_item.attr.role; | |
| 62 end | |
| 63 --TODO Check for status 100? | |
| 64 end | |
| 65 if nick == room.nick then | |
| 66 room.stream:event("groupchat/joined", room); | |
| 67 else | |
| 68 room:event("occupant-joined", occupants[nick]); | |
| 69 end | |
| 70 elseif occupants[nick] and presence.stanza.attr.type == "unavailable" then | |
| 71 if nick == room.nick then | |
| 72 room.stream:event("groupchat/left", room); | |
| 73 self.rooms[room.jid] = nil; | |
| 74 else | |
| 75 occupants[nick].presence = presence.stanza; | |
| 76 room:event("occupant-left", occupants[nick]); | |
| 77 occupants[nick] = nil; | |
| 78 end | |
| 79 end | |
| 80 end); | |
| 81 room:hook("message", function(msg) | |
| 82 local subject = msg.stanza:get_child("subject"); | |
| 83 if subject then | |
| 84 room.subject = subject and subject:get_text() or ""; | |
| 85 end | |
| 86 end); | |
| 87 local join_st = presence({to = jid.."/"..nick}) | |
| 88 :tag("x",{xmlns = xmlns_muc}):reset(); | |
| 89 -- Is this a good API for adding stuff etc? | |
| 90 local ok, err = self:event("pre-groupchat/joining", join_st); | |
| 91 if ok then | |
| 92 self:send(join_st) | |
| 93 self:event("groupchat/joining", room); | |
| 94 end | |
| 95 return room; | |
| 96 end | |
| 97 | |
| 98 stream:hook("presence-out", function(presence) | |
| 99 if not presence.attr.to then | |
| 100 for _, room in pairs(stream.rooms) do | |
| 101 room:send(presence); | |
| 102 end | |
| 103 presence.attr.to = nil; | |
| 104 end | |
| 105 end); | |
| 106 end | |
| 107 | |
| 108 function room_mt:send(stanza) | |
| 109 if stanza.name == "message" and not stanza.attr.type then | |
| 110 stanza.attr.type = "groupchat"; | |
| 111 end | |
| 112 if stanza.attr.type == "groupchat" or not stanza.attr.to then | |
| 113 stanza.attr.to = self.jid; | |
| 114 end | |
| 115 self.stream:send(stanza); | |
| 116 end | |
| 117 | |
| 118 function room_mt:send_message(text) | |
| 119 self:send(st.message():tag("body"):text(text)); | |
| 120 end | |
| 121 | |
| 122 function room_mt:set_subject(text) | |
| 123 self:send(st.message():tag("subject"):text(text)); | |
| 124 end | |
| 125 | |
| 126 function room_mt:leave(message) | |
| 127 self.stream:event("groupchat/leaving", room); | |
| 128 self:send(st.presence({type="unavailable"})); | |
| 129 end | |
| 130 | |
| 131 function room_mt:admin_set(nick, what, value, reason) | |
| 132 self:send(st.iq({type="set"}) | |
| 133 :query(xmlns_muc .. "#admin") | |
| 134 :tag("item", {nick = nick, [what] = value}) | |
| 135 :tag("reason"):text(reason or "")); | |
| 136 end | |
| 137 | |
| 138 function room_mt:set_role(nick, role, reason) | |
| 139 self:admin_set(nick, "role", role, reason); | |
| 140 end | |
| 141 | |
| 142 function room_mt:set_affiliation(nick, affiliation, reason) | |
| 143 self:admin_set(nick, "affiliation", affiliation, reason); | |
| 144 end | |
| 145 | |
| 146 function room_mt:kick(nick, reason) | |
| 147 self:set_role(nick, "none", reason); | |
| 148 end | |
| 149 | |
| 150 function room_mt:ban(nick, reason) | |
| 151 self:set_affiliation(nick, "outcast", reason); | |
| 152 end | |
| 153 | |
| 154 function room_mt:event(name, arg) | |
| 155 self.stream:debug("Firing room event: %s", name); | |
| 156 return self.events.fire_event(name, arg); | |
| 157 end | |
| 158 | |
| 159 function room_mt:hook(name, callback, priority) | |
| 160 return self.events.add_handler(name, callback, priority); | |
| 161 end |