Merge Waqas<>Zash
authorMatthew Wild <mwild1@gmail.com>
Tue, 31 Jul 2012 23:07:02 +0100
changeset 5069 7b298f8bcbcb
parent 5068 14d4fc5859b9 (current diff)
parent 5065 acfaf771f10e (diff)
child 5070 4bf6bd22ad11
Merge Waqas<>Zash
util/datamanager.lua
--- a/core/rostermanager.lua	Tue Jul 31 23:43:34 2012 +0200
+++ b/core/rostermanager.lua	Tue Jul 31 23:07:02 2012 +0100
@@ -278,23 +278,21 @@
 	local roster = load_roster(username, host);
 	local item = roster[jid];
 	local pending = is_contact_pending_in(username, host, jid);
-	local changed = nil;
-	if is_contact_pending_in(username, host, jid) then
+	if pending then
 		roster.pending[jid] = nil; -- TODO maybe delete roster.pending if empty?
-		changed = true;
 	end
+	local subscribed;
 	if item then
 		if item.subscription == "from" then
 			item.subscription = "none";
-			changed = true;
+			subscribed = true;
 		elseif item.subscription == "both" then
 			item.subscription = "to";
-			changed = true;
+			subscribed = true;
 		end
 	end
-	if changed then
-		return save_roster(username, host, roster);
-	end
+	local success = (pending or subscribed) and save_roster(username, host, roster);
+	return success, pending, subscribed;
 end
 
 function process_outbound_subscription_request(username, host, jid)
--- a/plugins/mod_component.lua	Tue Jul 31 23:43:34 2012 +0200
+++ b/plugins/mod_component.lua	Tue Jul 31 23:07:02 2012 +0100
@@ -93,6 +93,18 @@
 			stanza.attr.xmlns = nil;
 			send(stanza);
 		else
+			if stanza.name == "iq" and stanza.attr.type == "get" and stanza.attr.to == module.host then
+				local query = stanza.tags[1];
+				local node = query.attr.node;
+				if query.name == "query" and query.attr.xmlns == "http://jabber.org/protocol/disco#info" and (not node or node == "") then
+					local name = module:get_option_string("name");
+					if name then
+						event.origin.send(st.reply(stanza):tag("query", { xmlns = "http://jabber.org/protocol/disco#info" })
+							:tag("identity", { category = "component", type = "generic", name = module:get_option_string("name", "Prosody") }))
+						return true;
+					end
+				end
+			end
 			module:log("warn", "Component not connected, bouncing error for: %s", stanza:top_tag());
 			if stanza.attr.type ~= "error" and stanza.attr.type ~= "result" then
 				event.origin.send(st.error_reply(stanza, "wait", "service-unavailable", "Component unavailable"));
--- a/plugins/mod_presence.lua	Tue Jul 31 23:43:34 2012 +0200
+++ b/plugins/mod_presence.lua	Tue Jul 31 23:07:02 2012 +0100
@@ -198,12 +198,19 @@
 		core_post_stanza(origin, stanza);
 		send_presence_of_available_resources(node, host, to_bare, origin);
 	elseif stanza.attr.type == "unsubscribed" then
-		-- 1. route stanza
-		-- 2. roster push (subscription = none or to)
-		if rostermanager.unsubscribed(node, host, to_bare) then
-			rostermanager.roster_push(node, host, to_bare);
+		-- 1. send unavailable
+		-- 2. route stanza
+		-- 3. roster push (subscription = from or both)
+		local success, pending_in, subscribed = rostermanager.unsubscribed(node, host, to_bare);
+		if success then
+			if subscribed then
+				rostermanager.roster_push(node, host, to_bare);
+			end
+			core_post_stanza(origin, stanza);
+			if subscribed then
+				send_presence_of_available_resources(node, host, to_bare, origin, st.presence({ type = "unavailable" }));
+			end
 		end
-		core_post_stanza(origin, stanza);
 	else
 		origin.send(st.error_reply(stanza, "modify", "bad-request", "Invalid presence type"));
 	end
--- a/plugins/muc/mod_muc.lua	Tue Jul 31 23:43:34 2012 +0200
+++ b/plugins/muc/mod_muc.lua	Tue Jul 31 23:07:02 2012 +0100
@@ -22,7 +22,8 @@
 		restrict_room_creation = nil;
 	end
 end
-local muc_new_room = module:require "muc".new_room;
+local muclib = module:require "muc";
+local muc_new_room = muclib.new_room;
 local jid_split = require "util.jid".split;
 local jid_bare = require "util.jid".bare;
 local st = require "util.stanza";
@@ -42,6 +43,17 @@
 	return um_is_admin(jid, module.host);
 end
 
+local _set_affiliation = muc_new_room.room_mt.set_affiliation;
+local _get_affiliation = muc_new_room.room_mt.get_affiliation;
+function muclib.room_mt:get_affiliation(jid)
+	if is_admin(jid) then return "owner"; end
+	return _get_affiliation(self, jid);
+end
+function muclib.room_mt:set_affiliation(actor, jid, affiliation, callback, reason)
+	if is_admin(jid) then return nil, "modify", "not-acceptable";; end
+	return _set_affiliation(self, actor, jid, affiliation, callback, reason);
+end
+
 local function room_route_stanza(room, stanza) module:send(stanza); end
 local function room_save(room, forced)
 	local node = jid_split(room.jid);
@@ -135,6 +147,10 @@
 	local bare = jid_bare(stanza.attr.to);
 	local room = rooms[bare];
 	if not room then
+		if stanza.name ~= "presence" then
+			origin.send(st.error_reply(stanza, "cancel", "item-not-found"));
+			return true;
+		end
 		if not(restrict_room_creation) or
 		  (restrict_room_creation == "admin" and is_admin(stanza.attr.from)) or
 		  (restrict_room_creation == "local" and select(2, jid_split(stanza.attr.from)) == module.host:gsub("^[^%.]+%.", "")) then
@@ -174,7 +190,9 @@
 
 hosts[module:get_host()].muc = { rooms = rooms };
 
+local saved = false;
 module.save = function()
+	saved = true;
 	return {rooms = rooms};
 end
 module.restore = function(data)
@@ -190,3 +208,28 @@
 	end
 	hosts[module:get_host()].muc = { rooms = rooms };
 end
+
+function shutdown_room(room, stanza)
+	for nick, occupant in pairs(room._occupants) do
+		stanza.attr.from = nick;
+		for jid in pairs(occupant.sessions) do
+			stanza.attr.to = jid;
+			room:_route_stanza(stanza);
+			room._jid_nick[jid] = nil;
+		end
+		room._occupants[nick] = nil;
+	end
+end
+function shutdown_component()
+	if not saved then
+		local stanza = st.presence({type = "unavailable"})
+			:tag("x", {xmlns = "http://jabber.org/protocol/muc#user"})
+				:tag("item", { affiliation='none', role='none' }):up();
+		for roomjid, room in pairs(rooms) do
+			shutdown_room(room, stanza);
+		end
+		shutdown_room(host_room, stanza);
+	end
+end
+module.unload = shutdown_component;
+module:hook_global("server-stopping", shutdown_component);
--- a/plugins/muc/muc.lib.lua	Tue Jul 31 23:43:34 2012 +0200
+++ b/plugins/muc/muc.lib.lua	Tue Jul 31 23:07:02 2012 +0100
@@ -347,6 +347,31 @@
 end
 
 
+local function construct_stanza_id(room, stanza)
+	local from_jid, to_nick = stanza.attr.from, stanza.attr.to;
+	local from_nick = room._jid_nick[from_jid];
+	local occupant = room._occupants[to_nick];
+	local to_jid = occupant.jid;
+	
+	return from_nick, to_jid, base64.encode(to_jid.."\0"..stanza.attr.id.."\0"..md5(from_jid));
+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_nick = room._jid_nick[from_jid];
+
+	if not(from_nick) then return; end
+	if not(from_jid_possiblybare == from_jid or from_jid_possiblybare == jid_bare(from_jid)) then return; end
+
+	local occupant = room._occupants[to_nick];
+	for to_jid in pairs(occupant and occupant.sessions or {}) do
+		if md5(to_jid) == to_jid_hash then
+			return from_nick, to_jid, id;
+		end
+	end
+end
+
+
 function room_mt:handle_to_occupant(origin, stanza) -- PM, vCards, etc
 	local from, to = stanza.attr.from, stanza.attr.to;
 	local room = jid_bare(to);
@@ -497,24 +522,11 @@
 			end
 		end
 	elseif not current_nick then -- not in room
-		if type == "error" or type == "result" then
-			local id = stanza.name == "iq" and stanza.attr.id and base64.decode(stanza.attr.id);
-			local _nick, _id, _hash = (id or ""):match("^(.+)%z(.*)%z(.+)$");
-			local occupant = self._occupants[stanza.attr.to];
-			if occupant and _nick and self._jid_nick[_nick] and _id and _hash then
-				local id, _to = stanza.attr.id;
-				for jid in pairs(occupant.sessions) do
-					if md5(jid) == _hash then
-						_to = jid;
-						break;
-					end
-				end
-				if _to then
-					stanza.attr.to, stanza.attr.from, stanza.attr.id = _to, self._jid_nick[_nick], _id;
-					self:_route_stanza(stanza);
-					stanza.attr.to, stanza.attr.from, stanza.attr.id = to, from, id;
-				end
-			end
+		if type == "error" or type == "result" and stanza.name == "iq" then
+			local id = stanza.attr.id;
+			stanza.attr.from, stanza.attr.to, stanza.attr.id = deconstruct_stanza_id(self, stanza);
+			self:_route_stanza(stanza);
+			stanza.attr.from, stanza.attr.to, stanza.attr.id = from, to, id;
 		else
 			origin.send(st.error_reply(stanza, "cancel", "not-acceptable"));
 		end
@@ -527,16 +539,22 @@
 		local o_data = self._occupants[to];
 		if o_data then
 			log("debug", "%s sent private stanza to %s (%s)", from, to, o_data.jid);
-			local jid = o_data.jid;
-			local bare = jid_bare(jid);
-			stanza.attr.to, stanza.attr.from = jid, current_nick;
-			local id = stanza.attr.id;
-			if stanza.name=='iq' and type=='get' and stanza.tags[1].attr.xmlns == 'vcard-temp' and bare ~= jid then
-				stanza.attr.to = bare;
-				stanza.attr.id = base64.encode(jid.."\0"..id.."\0"..md5(from));
+			if stanza.name == "iq" then
+				local id = stanza.attr.id;
+				stanza.attr.from, stanza.attr.to, stanza.attr.id = construct_stanza_id(self, stanza);
+				if type == 'get' and stanza.tags[1].attr.xmlns == 'vcard-temp' then
+					stanza.attr.to = jid_bare(stanza.attr.to);
+				end
+				self:_route_stanza(stanza);
+				stanza.attr.from, stanza.attr.to, stanza.attr.id = from, to, id;
+			else -- message
+				stanza.attr.from = current_nick;
+				for jid in pairs(o_data.sessions) do
+					stanza.attr.to = jid;
+					self:_route_stanza(stanza);
+				end
+				stanza.attr.from, stanza.attr.to = from, to;
 			end
-			self:_route_stanza(stanza);
-			stanza.attr.to, stanza.attr.from, stanza.attr.id = to, from, id;
 		elseif type ~= "error" and type ~= "result" then -- recipient not in room
 			origin.send(st.error_reply(stanza, "cancel", "item-not-found", "Recipient not in room"));
 		end
@@ -1131,4 +1149,6 @@
 	}, room_mt);
 end
 
+_M.room_mt = room_mt;
+
 return _M;
--- a/util/datamanager.lua	Tue Jul 31 23:43:34 2012 +0200
+++ b/util/datamanager.lua	Tue Jul 31 23:07:02 2012 +0100
@@ -171,6 +171,18 @@
 	return nil, msg;
 end
 
+if prosody.platform ~= "posix" then
+	-- os.rename does not overwrite existing files on Windows
+	-- TODO We could use Transactional NTFS on Vista and above
+	function atomic_store(filename, data)
+		local f, err = io_open(filename, "w");
+		if not f then return f, err; end
+		local ok, msg = f:write(data);
+		if not ok then f:close(); return ok, msg; end
+		return f:close();
+	end
+end
+
 function store(username, host, datastore, data)
 	if not data then
 		data = {};