end
stanza.attr.to = to;
if historic then -- add to history
- local history = self._data['history'];
- if not history then history = {}; self._data['history'] = history; end
- stanza = st.clone(stanza);
- stanza.attr.to = "";
- local stamp = datetime.datetime();
- stanza:tag("delay", {xmlns = "urn:xmpp:delay", from = muc_domain, stamp = stamp}):up(); -- XEP-0203
- stanza:tag("x", {xmlns = "jabber:x:delay", from = muc_domain, stamp = datetime.legacy()}):up(); -- XEP-0091 (deprecated)
- local entry = { stanza = stanza, stamp = stamp };
- t_insert(history, entry);
- while #history > (self._data.history_length or default_history_length) do t_remove(history, 1) end
+ return self:save_to_history(stanza)
end
end
+function room_mt:save_to_history(stanza)
+ local history = self._data['history'];
+ if not history then history = {}; self._data['history'] = history; end
+ stanza = st.clone(stanza);
+ stanza.attr.to = "";
+ local stamp = datetime.datetime();
+ stanza:tag("delay", {xmlns = "urn:xmpp:delay", from = muc_domain, stamp = stamp}):up(); -- XEP-0203
+ stanza:tag("x", {xmlns = "jabber:x:delay", from = muc_domain, stamp = datetime.legacy()}):up(); -- XEP-0091 (deprecated)
+ local entry = { stanza = stanza, stamp = stamp };
+ t_insert(history, entry);
+ while #history > (self._data.history_length or default_history_length) do t_remove(history, 1) end
+end
function room_mt:broadcast_except_nick(stanza, nick)
for rnick, occupant in pairs(self._occupants) do
if rnick ~= nick then
self:_route_stanza(msg);
end
end
+end
+function room_mt:send_subject(to)
if self._data['subject'] then
self:_route_stanza(st.message({type='groupchat', from=self._data['subject_from'] or self.jid, to=to}):tag("subject"):text(self._data['subject']));
end
function room_mt:get_disco_info(stanza)
local count = 0; for _ in pairs(self._occupants) do count = count + 1; end
- return st.reply(stanza):query("http://jabber.org/protocol/disco#info")
+ local reply = st.reply(stanza):query("http://jabber.org/protocol/disco#info")
:tag("identity", {category="conference", type="text", name=self:get_name()}):up()
:tag("feature", {var="http://jabber.org/protocol/muc"}):up()
:tag("feature", {var=self:get_password() and "muc_passwordprotected" or "muc_unsecured"}):up()
:tag("feature", {var=self:get_persistent() and "muc_persistent" or "muc_temporary"}):up()
:tag("feature", {var=self:get_hidden() and "muc_hidden" or "muc_public"}):up()
:tag("feature", {var=self._data.whois ~= "anyone" and "muc_semianonymous" or "muc_nonanonymous"}):up()
- :add_child(dataform.new({
- { name = "FORM_TYPE", type = "hidden", value = "http://jabber.org/protocol/muc#roominfo" },
- { name = "muc#roominfo_description", label = "Description", value = "" },
- { name = "muc#roominfo_occupants", label = "Number of occupants", value = tostring(count) }
- }):form({["muc#roominfo_description"] = self:get_description()}, 'result'))
;
+ local dataform = dataform.new({
+ { name = "FORM_TYPE", type = "hidden", value = "http://jabber.org/protocol/muc#roominfo" },
+ { name = "muc#roominfo_description", label = "Description", value = "" },
+ { name = "muc#roominfo_occupants", label = "Number of occupants", value = "" }
+ });
+ local formdata = {
+ ["muc#roominfo_description"] = self:get_description(),
+ ["muc#roominfo_occupants"] = tostring(count),
+ };
+ module:fire_event("muc-disco#info", { room = self, reply = reply, form = dataform, formdata = formdata });
+ reply:add_child(dataform:form(formdata, 'result'))
+ return reply;
end
function room_mt:get_disco_items(stanza)
local reply = st.reply(stanza):query("http://jabber.org/protocol/disco#items");
end
local function deconstruct_stanza_id(room, stanza)
local from_jid_possiblybare, to_nick = stanza.attr.from, stanza.attr.to;
- local from_jid, id, to_jid_hash = (base64.decode(stanza.attr.id) or ""):match("^(.+)%z(.*)%z(.+)$");
+ local from_jid, id, to_jid_hash = (base64.decode(stanza.attr.id) or ""):match("^(%Z+)%z(%Z*)%z(.+)$");
local from_nick = room._jid_nick[from_jid];
if not(from_nick) then return; end
pr.attr.to = from;
self:_route_stanza(pr);
self:send_history(from, stanza);
+ self:send_subject(from);
elseif not affiliation then -- registration required for entering members-only room
local reply = st.error_reply(stanza, "auth", "registration-required"):up();
reply.tags[1].attr.code = "407";
end
stanza.attr.from, stanza.attr.to, stanza.attr.id = from, to, id;
else -- message
+ stanza:tag("x", { xmlns = "http://jabber.org/protocol/muc#user" }):up();
stanza.attr.from = current_nick;
for jid in pairs(o_data.sessions) do
stanza.attr.to = jid;
if form.attr.type == "cancel" then origin.send(st.reply(stanza)); return; end
if form.attr.type ~= "submit" then origin.send(st.error_reply(stanza, "cancel", "bad-request", "Not a submitted form")); return; end
- local fields = self:get_form_layout(stanza.attr.from):data(form);
- 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
+ if form.tags[1] == nil then
+ -- instant room
+ if self.save then self:save(true); end
+ origin.send(st.reply(stanza));
+ return true;
+ end
+ local fields, errors, present = self:get_form_layout(stanza.attr.from):data(form);
+ 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
local changed = {};
local function handle_option(name, field, allowed)
+ if not present[field] then return; end
local new = fields[field];
- if new == nil then return; end
if allowed and not allowed[new] then return; end
if new == self["get_"..name](self) then return; end
changed[name] = true;
if next(changed) then
local msg = st.message({type='groupchat', from=self.jid})
- :tag('x', {xmlns='http://jabber.org/protocol/muc#user'}):up()
+ :tag('x', {xmlns='http://jabber.org/protocol/muc#user'})
:tag('status', {code = '104'}):up();
if changed.whois then
local code = (self:get_whois() == 'moderators') and "173" or "172";
local _aff = item.attr.affiliation;
local _rol = item.attr.role;
if _aff and not _rol then
- if affiliation == "owner" or (affiliation == "admin" and _aff ~= "owner" and _aff ~= "admin") then
+ if affiliation == "owner" or (affiliation == "admin" and _aff ~= "owner" and _aff ~= "admin")
+ or (affiliation and affiliation ~= "outcast" and self:get_members_only() and self:get_whois() == "anyone") then
local reply = st.reply(stanza):query("http://jabber.org/protocol/muc#admin");
for jid, affiliation in pairs(self._affiliations) do
if affiliation == _aff then
if actor_jid == true then return true; end
local actor = self._occupants[self._jid_nick[actor_jid]];
- if actor.role == "moderator" then
+ if actor and actor.role == "moderator" then
if occupant.affiliation ~= "owner" and occupant.affiliation ~= "admin" then
if actor.affiliation == "owner" or actor.affiliation == "admin" then
return true;