2 -- Copyright (C) 2008-2010 Matthew Wild
3 -- Copyright (C) 2008-2010 Waqas Hussain
4 -- Copyright (C) 2014 Daurnimator
6 -- This project is MIT/X11 licensed. Please see the
7 -- COPYING file in the source package for more information.
10 local st
= require
"util.stanza";
12 local muc_util
= module
:require
"muc/util";
13 local valid_affiliations
= muc_util
.valid_affiliations
;
15 local function get_members_only(room
)
16 return room
._data
.members_only
;
19 local function set_members_only(room
, members_only
)
20 members_only
= members_only
and true or nil;
21 if room
._data
.members_only
== members_only
then return false; end
22 room
._data
.members_only
= members_only
;
25 If as a result of a change in the room configuration the room type is
26 changed to members-only but there are non-members in the room,
27 the service MUST remove any non-members from the room and include a
28 status code of 322 in the presence unavailable stanzas sent to those users
29 as well as any remaining occupants.
31 local occupants_changed
= {};
32 for _
, occupant
in room
:each_occupant() do
33 local affiliation
= room
:get_affiliation(occupant
.bare_jid
);
34 if valid_affiliations
[affiliation
or "none"] <= valid_affiliations
.none
then
36 room
:save_occupant(occupant
);
37 occupants_changed
[occupant
] = true;
40 local x
= st
.stanza("x", {xmlns
= "http://jabber.org/protocol/muc#user"})
41 :tag("status", {code
="322"}):up();
42 for occupant
in pairs(occupants_changed
) do
43 room
:publicise_occupant_status(occupant
, x
);
44 module
:fire_event("muc-occupant-left", {room
= room
; nick
= occupant
.nick
; occupant
= occupant
;});
50 local function get_allow_member_invites(room
)
51 return room
._data
.allow_member_invites
;
54 -- Allows members to invite new members into a members-only room,
55 -- effectively creating an invite-only room
56 local function set_allow_member_invites(room
, allow_member_invites
)
57 allow_member_invites
= allow_member_invites
and true or nil;
58 if room
._data
.allow_member_invites
== allow_member_invites
then return false; end
59 room
._data
.allow_member_invites
= allow_member_invites
;
63 module
:hook("muc-disco#info", function(event
)
64 event
.reply
:tag("feature", {var
= get_members_only(event
.room
) and "muc_membersonly" or "muc_open"}):up();
65 table.insert(event
.form
, {
66 name
= "{http://prosody.im/protocol/muc}roomconfig_allowmemberinvites";
67 label
= "Allow members to invite new members";
69 value
= not not get_allow_member_invites(event
.room
);
74 module
:hook("muc-config-form", function(event
)
75 table.insert(event
.form
, {
76 name
= "muc#roomconfig_membersonly";
78 label
= "Only allow members to join";
79 desc
= "Enable this to only allow access for room owners, admins and members";
80 value
= get_members_only(event
.room
);
82 table.insert(event
.form
, {
83 name
= "{http://prosody.im/protocol/muc}roomconfig_allowmemberinvites";
85 label
= "Allow members to invite new members";
86 value
= get_allow_member_invites(event
.room
);
90 module
:hook("muc-config-submitted/muc#roomconfig_membersonly", function(event
)
91 if set_members_only(event
.room
, event
.value
) then
92 event
.status_codes
["104"] = true;
96 module
:hook("muc-config-submitted/{http://prosody.im/protocol/muc}roomconfig_allowmemberinvites", function(event
)
97 if set_allow_member_invites(event
.room
, event
.value
) then
98 event
.status_codes
["104"] = true;
102 -- No affiliation => role of "none"
103 module
:hook("muc-get-default-role", function(event
)
104 if not event
.affiliation
and get_members_only(event
.room
) then
109 -- registration required for entering members-only room
110 module
:hook("muc-occupant-pre-join", function(event
)
111 local room
= event
.room
;
112 if get_members_only(room
) then
113 local stanza
= event
.stanza
;
114 local affiliation
= room
:get_affiliation(stanza
.attr
.from
);
115 if valid_affiliations
[affiliation
or "none"] <= valid_affiliations
.none
then
116 local reply
= st
.error_reply(stanza
, "auth", "registration-required"):up();
117 reply
.tags
[1].attr
.code
= "407";
118 event
.origin
.send(reply
:tag("x", {xmlns
= "http://jabber.org/protocol/muc"}));
124 -- Invitation privileges in members-only rooms SHOULD be restricted to room admins;
125 -- if a member without privileges to edit the member list attempts to invite another user
126 -- the service SHOULD return a <forbidden/> error to the occupant
127 module
:hook("muc-pre-invite", function(event
)
128 local room
= event
.room
;
129 if get_members_only(room
) then
130 local stanza
= event
.stanza
;
131 local inviter_affiliation
= room
:get_affiliation(stanza
.attr
.from
) or "none";
132 local required_affiliation
= room
._data
.allow_member_invites
and "member" or "admin";
133 if valid_affiliations
[inviter_affiliation
] < valid_affiliations
[required_affiliation
] then
134 event
.origin
.send(st
.error_reply(stanza
, "auth", "forbidden"));
140 -- When an invite is sent; add an affiliation for the invitee
141 module
:hook("muc-invite", function(event
)
142 local room
= event
.room
;
143 if get_members_only(room
) then
144 local stanza
= event
.stanza
;
145 local invitee
= stanza
.attr
.to
;
146 local affiliation
= room
:get_affiliation(invitee
);
147 local invited_unaffiliated
= valid_affiliations
[affiliation
or "none"] <= valid_affiliations
.none
;
148 if invited_unaffiliated
then
149 local from
= stanza
:get_child("x", "http://jabber.org/protocol/muc#user")
150 :get_child("invite").attr
.from
;
151 module
:log("debug", "%s invited %s into members only room %s, granting membership",
152 from
, invitee
, room
.jid
);
153 -- This might fail; ignore for now
154 room
:set_affiliation(true, invitee
, "member", "Invited by " .. from
);
161 get
= get_members_only
;
162 set
= set_members_only
;
163 get_allow_member_invites
= get_allow_member_invites
;
164 set_allow_member_invites
= set_allow_member_invites
;