Software /
code /
prosody
Comparison
plugins/muc/muc.lib.lua @ 5580:db5d1a350cc7
mod_muc: Refactor config form handling, and allow for clients to submit incomplete forms. Fixes #246
author | Matthew Wild <mwild1@gmail.com> |
---|---|
date | Thu, 16 May 2013 14:17:25 +0100 |
parent | 5577:8b09b0d068d4 |
child | 5600:1b326a1e4da6 |
comparison
equal
deleted
inserted
replaced
5579:e449e6342e36 | 5580:db5d1a350cc7 |
---|---|
96 if affiliation == "owner" or affiliation == "admin" then | 96 if affiliation == "owner" or affiliation == "admin" then |
97 return "moderator"; | 97 return "moderator"; |
98 elseif affiliation == "member" then | 98 elseif affiliation == "member" then |
99 return "participant"; | 99 return "participant"; |
100 elseif not affiliation then | 100 elseif not affiliation then |
101 if not self:is_members_only() then | 101 if not self:get_members_only() then |
102 return self:is_moderated() and "visitor" or "participant"; | 102 return self:get_moderated() and "visitor" or "participant"; |
103 end | 103 end |
104 end | 104 end |
105 end | 105 end |
106 | 106 |
107 function room_mt:broadcast_presence(stanza, sid, code, nick) | 107 function room_mt:broadcast_presence(stanza, sid, code, nick) |
216 local count = 0; for _ in pairs(self._occupants) do count = count + 1; end | 216 local count = 0; for _ in pairs(self._occupants) do count = count + 1; end |
217 return st.reply(stanza):query("http://jabber.org/protocol/disco#info") | 217 return st.reply(stanza):query("http://jabber.org/protocol/disco#info") |
218 :tag("identity", {category="conference", type="text", name=self:get_name()}):up() | 218 :tag("identity", {category="conference", type="text", name=self:get_name()}):up() |
219 :tag("feature", {var="http://jabber.org/protocol/muc"}):up() | 219 :tag("feature", {var="http://jabber.org/protocol/muc"}):up() |
220 :tag("feature", {var=self:get_password() and "muc_passwordprotected" or "muc_unsecured"}):up() | 220 :tag("feature", {var=self:get_password() and "muc_passwordprotected" or "muc_unsecured"}):up() |
221 :tag("feature", {var=self:is_moderated() and "muc_moderated" or "muc_unmoderated"}):up() | 221 :tag("feature", {var=self:get_moderated() and "muc_moderated" or "muc_unmoderated"}):up() |
222 :tag("feature", {var=self:is_members_only() and "muc_membersonly" or "muc_open"}):up() | 222 :tag("feature", {var=self:get_members_only() and "muc_membersonly" or "muc_open"}):up() |
223 :tag("feature", {var=self:is_persistent() and "muc_persistent" or "muc_temporary"}):up() | 223 :tag("feature", {var=self:get_persistent() and "muc_persistent" or "muc_temporary"}):up() |
224 :tag("feature", {var=self:is_hidden() and "muc_hidden" or "muc_public"}):up() | 224 :tag("feature", {var=self:get_hidden() and "muc_hidden" or "muc_public"}):up() |
225 :tag("feature", {var=self._data.whois ~= "anyone" and "muc_semianonymous" or "muc_nonanonymous"}):up() | 225 :tag("feature", {var=self._data.whois ~= "anyone" and "muc_semianonymous" or "muc_nonanonymous"}):up() |
226 :add_child(dataform.new({ | 226 :add_child(dataform.new({ |
227 { name = "FORM_TYPE", type = "hidden", value = "http://jabber.org/protocol/muc#roominfo" }, | 227 { name = "FORM_TYPE", type = "hidden", value = "http://jabber.org/protocol/muc#roominfo" }, |
228 { name = "muc#roominfo_description", label = "Description"}, | 228 { name = "muc#roominfo_description", label = "Description"}, |
229 { name = "muc#roominfo_occupants", label = "Number of occupants", value = tostring(count) } | 229 { name = "muc#roominfo_occupants", label = "Number of occupants", value = tostring(count) } |
294 if self._data.moderated ~= moderated then | 294 if self._data.moderated ~= moderated then |
295 self._data.moderated = moderated; | 295 self._data.moderated = moderated; |
296 if self.save then self:save(true); end | 296 if self.save then self:save(true); end |
297 end | 297 end |
298 end | 298 end |
299 function room_mt:is_moderated() | 299 function room_mt:get_moderated() |
300 return self._data.moderated; | 300 return self._data.moderated; |
301 end | 301 end |
302 function room_mt:set_members_only(members_only) | 302 function room_mt:set_members_only(members_only) |
303 members_only = members_only and true or nil; | 303 members_only = members_only and true or nil; |
304 if self._data.members_only ~= members_only then | 304 if self._data.members_only ~= members_only then |
305 self._data.members_only = members_only; | 305 self._data.members_only = members_only; |
306 if self.save then self:save(true); end | 306 if self.save then self:save(true); end |
307 end | 307 end |
308 end | 308 end |
309 function room_mt:is_members_only() | 309 function room_mt:get_members_only() |
310 return self._data.members_only; | 310 return self._data.members_only; |
311 end | 311 end |
312 function room_mt:set_persistent(persistent) | 312 function room_mt:set_persistent(persistent) |
313 persistent = persistent and true or nil; | 313 persistent = persistent and true or nil; |
314 if self._data.persistent ~= persistent then | 314 if self._data.persistent ~= persistent then |
315 self._data.persistent = persistent; | 315 self._data.persistent = persistent; |
316 if self.save then self:save(true); end | 316 if self.save then self:save(true); end |
317 end | 317 end |
318 end | 318 end |
319 function room_mt:is_persistent() | 319 function room_mt:get_persistent() |
320 return self._data.persistent; | 320 return self._data.persistent; |
321 end | 321 end |
322 function room_mt:set_hidden(hidden) | 322 function room_mt:set_hidden(hidden) |
323 hidden = hidden and true or nil; | 323 hidden = hidden and true or nil; |
324 if self._data.hidden ~= hidden then | 324 if self._data.hidden ~= hidden then |
325 self._data.hidden = hidden; | 325 self._data.hidden = hidden; |
326 if self.save then self:save(true); end | 326 if self.save then self:save(true); end |
327 end | 327 end |
328 end | 328 end |
329 function room_mt:is_hidden() | 329 function room_mt:get_hidden() |
330 return self._data.hidden; | 330 return self._data.hidden; |
331 end | |
332 function room_mt:get_public() | |
333 return not self:get_hidden(); | |
334 end | |
335 function room_mt:set_public(public) | |
336 return self:set_hidden(not public); | |
331 end | 337 end |
332 function room_mt:set_changesubject(changesubject) | 338 function room_mt:set_changesubject(changesubject) |
333 changesubject = changesubject and true or nil; | 339 changesubject = changesubject and true or nil; |
334 if self._data.changesubject ~= changesubject then | 340 if self._data.changesubject ~= changesubject then |
335 self._data.changesubject = changesubject; | 341 self._data.changesubject = changesubject; |
602 }, | 608 }, |
603 { | 609 { |
604 name = 'muc#roomconfig_persistentroom', | 610 name = 'muc#roomconfig_persistentroom', |
605 type = 'boolean', | 611 type = 'boolean', |
606 label = 'Make Room Persistent?', | 612 label = 'Make Room Persistent?', |
607 value = self:is_persistent() | 613 value = self:get_persistent() |
608 }, | 614 }, |
609 { | 615 { |
610 name = 'muc#roomconfig_publicroom', | 616 name = 'muc#roomconfig_publicroom', |
611 type = 'boolean', | 617 type = 'boolean', |
612 label = 'Make Room Publicly Searchable?', | 618 label = 'Make Room Publicly Searchable?', |
613 value = not self:is_hidden() | 619 value = not self:get_hidden() |
614 }, | 620 }, |
615 { | 621 { |
616 name = 'muc#roomconfig_changesubject', | 622 name = 'muc#roomconfig_changesubject', |
617 type = 'boolean', | 623 type = 'boolean', |
618 label = 'Allow Occupants to Change Subject?', | 624 label = 'Allow Occupants to Change Subject?', |
635 }, | 641 }, |
636 { | 642 { |
637 name = 'muc#roomconfig_moderatedroom', | 643 name = 'muc#roomconfig_moderatedroom', |
638 type = 'boolean', | 644 type = 'boolean', |
639 label = 'Make Room Moderated?', | 645 label = 'Make Room Moderated?', |
640 value = self:is_moderated() | 646 value = self:get_moderated() |
641 }, | 647 }, |
642 { | 648 { |
643 name = 'muc#roomconfig_membersonly', | 649 name = 'muc#roomconfig_membersonly', |
644 type = 'boolean', | 650 type = 'boolean', |
645 label = 'Make Room Members-Only?', | 651 label = 'Make Room Members-Only?', |
646 value = self:is_members_only() | 652 value = self:get_members_only() |
647 }, | 653 }, |
648 { | 654 { |
649 name = 'muc#roomconfig_historylength', | 655 name = 'muc#roomconfig_historylength', |
650 type = 'text-single', | 656 type = 'text-single', |
651 label = 'Maximum Number of History Messages Returned by Room', | 657 label = 'Maximum Number of History Messages Returned by Room', |
653 } | 659 } |
654 }); | 660 }); |
655 return module:fire_event("muc-config-form", { room = self, form = form }) or form; | 661 return module:fire_event("muc-config-form", { room = self, form = form }) or form; |
656 end | 662 end |
657 | 663 |
658 local valid_whois = { | 664 local valid_whois = { moderators = true, anyone = true }; |
659 moderators = true, | |
660 anyone = true, | |
661 } | |
662 | 665 |
663 function room_mt:process_form(origin, stanza) | 666 function room_mt:process_form(origin, stanza) |
664 local query = stanza.tags[1]; | 667 local query = stanza.tags[1]; |
665 local form; | 668 local form; |
666 for _, tag in ipairs(query.tags) do if tag.name == "x" and tag.attr.xmlns == "jabber:x:data" then form = tag; break; end end | 669 for _, tag in ipairs(query.tags) do if tag.name == "x" and tag.attr.xmlns == "jabber:x:data" then form = tag; break; end end |
669 if form.attr.type ~= "submit" then origin.send(st.error_reply(stanza, "cancel", "bad-request", "Not a submitted form")); return; end | 672 if form.attr.type ~= "submit" then origin.send(st.error_reply(stanza, "cancel", "bad-request", "Not a submitted form")); return; end |
670 | 673 |
671 local fields = self:get_form_layout():data(form); | 674 local fields = self:get_form_layout():data(form); |
672 if fields.FORM_TYPE ~= "http://jabber.org/protocol/muc#roomconfig" then origin.send(st.error_reply(stanza, "cancel", "bad-request", "Form is not of type room configuration")); return; end | 675 if fields.FORM_TYPE ~= "http://jabber.org/protocol/muc#roomconfig" then origin.send(st.error_reply(stanza, "cancel", "bad-request", "Form is not of type room configuration")); return; end |
673 | 676 |
674 local dirty = false | 677 |
675 | 678 local changed = {}; |
676 local event = { room = self, fields = fields, changed = dirty }; | 679 |
680 local function handle_option(name, field, allowed) | |
681 local new = fields[field]; | |
682 if new == nil then return; end | |
683 if allowed and not allowed[new] then return; end | |
684 if new == self["get_"..name](self) then return; end | |
685 changed[name] = true; | |
686 self["set_"..name](self, new); | |
687 end | |
688 | |
689 local event = { room = self, fields = fields, changed = changed, stanza = stanza, origin = origin, update_option = handle_option }; | |
677 module:fire_event("muc-config-submitted", event); | 690 module:fire_event("muc-config-submitted", event); |
678 dirty = event.changed or dirty; | 691 |
679 | 692 handle_option("name", "muc#roomconfig_roomname"); |
680 local name = fields['muc#roomconfig_roomname']; | 693 handle_option("description", "muc#roomconfig_roomdesc"); |
681 if name ~= self:get_name() then | 694 handle_option("persistent", "muc#roomconfig_persistentroom"); |
682 self:set_name(name); | 695 handle_option("moderated", "muc#roomconfig_moderatedroom"); |
683 end | 696 handle_option("members_only", "muc#roomconfig_membersonly"); |
684 | 697 handle_option("public", "muc#roomconfig_publicroom"); |
685 local description = fields['muc#roomconfig_roomdesc']; | 698 handle_option("changesubject", "muc#roomconfig_changesubject"); |
686 if description ~= self:get_description() then | 699 handle_option("historylength", "muc#roomconfig_historylength"); |
687 self:set_description(description); | 700 handle_option("whois", "muc#roomconfig_whois", valid_whois); |
688 end | 701 handle_option("password", "muc#roomconfig_roomsecret"); |
689 | |
690 local persistent = fields['muc#roomconfig_persistentroom']; | |
691 dirty = dirty or (self:is_persistent() ~= persistent) | |
692 module:log("debug", "persistent=%s", tostring(persistent)); | |
693 | |
694 local moderated = fields['muc#roomconfig_moderatedroom']; | |
695 dirty = dirty or (self:is_moderated() ~= moderated) | |
696 module:log("debug", "moderated=%s", tostring(moderated)); | |
697 | |
698 local membersonly = fields['muc#roomconfig_membersonly']; | |
699 dirty = dirty or (self:is_members_only() ~= membersonly) | |
700 module:log("debug", "membersonly=%s", tostring(membersonly)); | |
701 | |
702 local public = fields['muc#roomconfig_publicroom']; | |
703 dirty = dirty or (self:is_hidden() ~= (not public and true or nil)) | |
704 | |
705 local changesubject = fields['muc#roomconfig_changesubject']; | |
706 dirty = dirty or (self:get_changesubject() ~= (not changesubject and true or nil)) | |
707 module:log('debug', 'changesubject=%s', changesubject and "true" or "false") | |
708 | |
709 local historylength = tonumber(fields['muc#roomconfig_historylength']); | |
710 dirty = dirty or (historylength and (self:get_historylength() ~= historylength)); | |
711 module:log('debug', 'historylength=%s', historylength) | |
712 | |
713 | |
714 local whois = fields['muc#roomconfig_whois']; | |
715 if not valid_whois[whois] then | |
716 origin.send(st.error_reply(stanza, 'cancel', 'bad-request', "Invalid value for 'whois'")); | |
717 return; | |
718 end | |
719 local whois_changed = self._data.whois ~= whois | |
720 self._data.whois = whois | |
721 module:log('debug', 'whois=%s', whois) | |
722 | |
723 local password = fields['muc#roomconfig_roomsecret']; | |
724 if self:get_password() ~= password then | |
725 self:set_password(password); | |
726 end | |
727 self:set_moderated(moderated); | |
728 self:set_members_only(membersonly); | |
729 self:set_persistent(persistent); | |
730 self:set_hidden(not public); | |
731 self:set_changesubject(changesubject); | |
732 self:set_historylength(historylength); | |
733 | 702 |
734 if self.save then self:save(true); end | 703 if self.save then self:save(true); end |
735 origin.send(st.reply(stanza)); | 704 origin.send(st.reply(stanza)); |
736 | 705 |
737 if dirty or whois_changed then | 706 if next(changed) then |
738 local msg = st.message({type='groupchat', from=self.jid}) | 707 local msg = st.message({type='groupchat', from=self.jid}) |
739 :tag('x', {xmlns='http://jabber.org/protocol/muc#user'}):up() | 708 :tag('x', {xmlns='http://jabber.org/protocol/muc#user'}):up() |
740 | 709 :tag('status', {code = '104'}):up(); |
741 if dirty then | 710 if changed.whois then |
742 msg.tags[1]:tag('status', {code = '104'}):up(); | |
743 end | |
744 if whois_changed then | |
745 local code = (whois == 'moderators') and "173" or "172"; | 711 local code = (whois == 'moderators') and "173" or "172"; |
746 msg.tags[1]:tag('status', {code = code}):up(); | 712 msg.tags[1]:tag('status', {code = code}):up(); |
747 end | 713 end |
748 | |
749 self:broadcast_message(msg, false) | 714 self:broadcast_message(msg, false) |
750 end | 715 end |
751 end | 716 end |
752 | 717 |
753 function room_mt:destroy(newjid, reason, password) | 718 function room_mt:destroy(newjid, reason, password) |
941 :text(_reason or "") | 906 :text(_reason or "") |
942 :up() | 907 :up() |
943 :tag('body') -- Add a plain message for clients which don't support invites | 908 :tag('body') -- Add a plain message for clients which don't support invites |
944 :text(_from..' invited you to the room '.._to..(_reason and (' ('.._reason..')') or "")) | 909 :text(_from..' invited you to the room '.._to..(_reason and (' ('.._reason..')') or "")) |
945 :up(); | 910 :up(); |
946 if self:is_members_only() and not self:get_affiliation(_invitee) then | 911 if self:get_members_only() and not self:get_affiliation(_invitee) then |
947 log("debug", "%s invited %s into members only room %s, granting membership", _from, _invitee, _to); | 912 log("debug", "%s invited %s into members only room %s, granting membership", _from, _invitee, _to); |
948 self:set_affiliation(_from, _invitee, "member", nil, "Invited by " .. self._jid_nick[_from]) | 913 self:set_affiliation(_from, _invitee, "member", nil, "Invited by " .. self._jid_nick[_from]) |
949 end | 914 end |
950 self:_route_stanza(invite); | 915 self:_route_stanza(invite); |
951 else | 916 else |