8 local multitable_new = require "util.multitable".new; |
8 local multitable_new = require "util.multitable".new; |
9 |
9 |
10 local muc_domain = "conference."..module:get_host(); |
10 local muc_domain = "conference."..module:get_host(); |
11 local muc_name = "MUCMUCMUC!!!"; |
11 local muc_name = "MUCMUCMUC!!!"; |
12 |
12 |
|
13 -- room_name -> room |
|
14 -- occupant_room_nick -> data |
|
15 -- affiliation = ... |
|
16 -- role |
|
17 -- jid = occupant's real jid |
13 local rooms = multitable_new(); |
18 local rooms = multitable_new(); |
14 local jid_nick = multitable_new(); |
19 |
|
20 local jid_nick = multitable_new(); -- real jid -> room's jid -> room nick |
|
21 |
|
22 -- room_name -> info |
|
23 -- name - the room's friendly name |
|
24 -- subject - the room's subject |
|
25 -- non-anonymous = true|nil |
|
26 -- persistent = true|nil |
15 local rooms_info = multitable_new(); |
27 local rooms_info = multitable_new(); |
|
28 |
|
29 local persist_list = datamanager.load(nil, muc_domain, 'room_list') or {}; |
|
30 for room in pairs(persist_list) do |
|
31 rooms_info:set(room, datamanager.store(room, muc_domain, 'rooms') or nil); |
|
32 end |
16 |
33 |
17 local component; |
34 local component; |
18 |
35 |
19 function getUsingPath(stanza, path, getText) |
36 function getUsingPath(stanza, path, getText) |
20 local tag = stanza; |
37 local tag = stanza; |
46 :tag("feature", {var="http://jabber.org/protocol/muc"}); -- TODO cache disco reply |
63 :tag("feature", {var="http://jabber.org/protocol/muc"}); -- TODO cache disco reply |
47 end |
64 end |
48 function get_room_disco_items(stanza) |
65 function get_room_disco_items(stanza) |
49 return st.iq({type='result', id=stanza.attr.id, from=stanza.attr.to, to=stanza.attr.from}):query("http://jabber.org/protocol/disco#items"); |
66 return st.iq({type='result', id=stanza.attr.id, from=stanza.attr.to, to=stanza.attr.from}):query("http://jabber.org/protocol/disco#items"); |
50 end -- TODO allow non-private rooms |
67 end -- TODO allow non-private rooms |
|
68 |
|
69 function save_room(room) |
|
70 local persistent = rooms_info:get(room, 'persistent'); |
|
71 if persistent then |
|
72 datamanager.store(room, muc_domain, 'rooms', rooms_info:get(room)); |
|
73 end |
|
74 if persistent ~= persist_list[room] then |
|
75 if not persistent then |
|
76 datamanager.store(room, muc_domain, 'rooms', nil); |
|
77 end |
|
78 persist_list[room] = persistent; |
|
79 datamanager.store(nil, muc_domain, 'room_list', persist_list); |
|
80 end |
|
81 end |
|
82 |
|
83 function set_subject(current_nick, room, subject) |
|
84 -- TODO check nick's authority |
|
85 if subject == "" then subject = nil; end |
|
86 rooms_info:set(room, 'subject', subject); |
|
87 save_room(); |
|
88 broadcast_message(current_nick, room, subject or "", nil); |
|
89 return true; |
|
90 end |
51 |
91 |
52 function broadcast_presence(type, from, room, code) |
92 function broadcast_presence(type, from, room, code) |
53 local data = rooms:get(room, from); |
93 local data = rooms:get(room, from); |
54 local stanza = st.presence({type=type, from=from}) |
94 local stanza = st.presence({type=type, from=from}) |
55 :tag("x", {xmlns='http://jabber.org/protocol/muc#user'}) |
95 :tag("x", {xmlns='http://jabber.org/protocol/muc#user'}) |
126 end |
166 end |
127 else -- enter room |
167 else -- enter room |
128 if rooms:get(room, to) then |
168 if rooms:get(room, to) then |
129 origin.send(st.error_reply(stanza, "cancel", "conflict")); |
169 origin.send(st.error_reply(stanza, "cancel", "conflict")); |
130 else |
170 else |
131 local data = {affiliation='none', role='participant', jid=from}; |
171 local data; |
|
172 if not rooms:get(room) and not rooms_info:get(room) then -- new room |
|
173 data = {affiliation='owner', role='moderator', jid=from}; |
|
174 end |
|
175 if not data then -- new occupant |
|
176 data = {affiliation='none', role='participant', jid=from}; |
|
177 end |
132 rooms:set(room, to, data); |
178 rooms:set(room, to, data); |
133 jid_nick:set(from, room, to); |
179 jid_nick:set(from, room, to); |
134 local r = rooms:get(room); |
180 local r = rooms:get(room); |
135 if r then |
181 if r then |
136 for occupant, o_data in pairs(r) do |
182 for occupant, o_data in pairs(r) do |
141 core_route_stanza(component, pres); |
187 core_route_stanza(component, pres); |
142 end |
188 end |
143 end |
189 end |
144 end |
190 end |
145 broadcast_presence(nil, to, room); |
191 broadcast_presence(nil, to, room); |
|
192 -- TODO send discussion history |
|
193 if rooms_info:get(room, 'subject') then |
|
194 broadcast_message(room, room, rooms_info:get(room, 'subject'), nil); |
|
195 end |
146 end |
196 end |
147 end |
197 end |
148 elseif type ~= 'result' then -- bad type |
198 elseif type ~= 'result' then -- bad type |
149 origin.send(st.error_reply(stanza, "modify", "bad-request")); -- FIXME correct error? |
199 origin.send(st.error_reply(stanza, "modify", "bad-request")); -- FIXME correct error? |
150 end |
200 end |
172 local room = jid_bare(to); |
222 local room = jid_bare(to); |
173 local current_nick = jid_nick:get(from, room); |
223 local current_nick = jid_nick:get(from, room); |
174 if not current_nick then -- not in room |
224 if not current_nick then -- not in room |
175 origin.send(st.error_reply(stanza, "cancel", "not-acceptable")); |
225 origin.send(st.error_reply(stanza, "cancel", "not-acceptable")); |
176 else |
226 else |
177 broadcast_message(current_nick, room, getText(stanza, {"subject"}), getText(stanza, {"body"})); |
227 local subject = getText(stanza, {"subject"}); |
|
228 if subject then |
|
229 set_subject(current_nick, room, subject); |
|
230 else |
|
231 broadcast_message(current_nick, room, nil, getText(stanza, {"body"})); |
|
232 -- TODO add to discussion history |
|
233 end |
178 end |
234 end |
179 else |
235 else |
180 if type == "error" or type == "result" then return; end |
236 if type == "error" or type == "result" then return; end |
181 origin.send(st.error_reply(stanza, "cancel", "service-unavailable")); |
237 origin.send(st.error_reply(stanza, "cancel", "service-unavailable")); |
182 end |
238 end |