changeset 61:e609da067e9f

mod_muc_log: display room's current title; show kicked messages with and without reason
author Thilo Cestonaro <thilo@cestona.ro>
date Wed, 21 Oct 2009 22:32:58 +0200
parents 5cca708c9f11
children 0dfd65bfedb0
files mod_muc_log/mod_muc_log.lua
diffstat 1 files changed, 109 insertions(+), 28 deletions(-) [+]
line wrap: on
line diff
--- a/mod_muc_log/mod_muc_log.lua	Wed Oct 21 10:19:25 2009 +0200
+++ b/mod_muc_log/mod_muc_log.lua	Wed Oct 21 22:32:58 2009 +0200
@@ -36,11 +36,11 @@
 .muc_join {color: #009900; font-style: italic;}
 .muc_leave {color: #009900; font-style: italic;}
 .muc_statusChange {color: #009900; font-style: italic;}
-.muc_title {color: #009900;}
-.muc_titlenick {color: #009900; font-style: italic;}
+.muc_title {color: #BBBBBB; font-size: 32px;}
+.muc_titleChange {color: #009900; font-style: italic;}
 .muc_kick {color: #009900; font-style: italic;}
 .muc_bann {color: #009900; font-style: italic;}
-.muc_name {color: #0000AA;}
+.muc_msg_nick {color: #0000AA;}
 //-->
 </style>
 <body>
@@ -61,17 +61,21 @@
 </p><hr />]];
 
 html.day = {};
+html.day.title = [[Subject: <font class="muc_title">###TITLE###</font>]];
 html.day.time = [[<a name="###TIME###" href="####TIME###" class="timestuff">[###TIME###]</a> ]]; -- the one ####TIME### need to stay! it will evaluate to e.g. #09:10:56 which is an anker then
 html.day.presence = {};
 html.day.presence.join = [[###TIME_STUFF###<font class="muc_join"> *** ###NICK### joins the room</font><br />]];
 html.day.presence.leave = [[###TIME_STUFF###<font class="muc_leave"> *** ###NICK### leaves the room</font><br />]];
 html.day.presence.statusText = [[ and his status message is "###STATUS###"]];
 html.day.presence.statusChange = [[###TIME_STUFF###<font class="muc_statusChange"> *** ###NICK### shows now as "###SHOW###"###STATUS_STUFF###</font><br />]];
-html.day.message = [[###TIME_STUFF###<font class="muc_name">&lt;###NICK###&gt;</font> ###MSG###<br />]];
-html.day.titleChange = [[###TIME_STUFF###<font class="muc_titlenick"> *** ###NICK### changed the title to</font> <font class="muc_title">"###TITLE###"</font><br />]];
-html.day.kick = [[###TIME_STUFF###<font class="muc_titlenick"> *** ###NICK### kicked ###VICTIM###</font><br />]];
-html.day.bann = [[###TIME_STUFF###<font class="muc_titlenick"> *** ###NICK### banned ###VICTIM###</font><br />]];
-html.day.body = [[<h2>room ###JID### logging of 20###YEAR###/###MONTH###/###DAY###</h2><hr /><p>
+html.day.message = [[###TIME_STUFF###<font class="muc_msg_nick">&lt;###NICK###&gt;</font> ###MSG###<br />]];
+html.day.titleChange = [[###TIME_STUFF###<font class="muc_titleChange"> *** ###NICK### changed the title to "###TITLE###"</font><br />]];
+html.day.reason = [[, the reason was "###REASON###"]]
+html.day.kick = [[###TIME_STUFF###<font class="muc_kick"> *** ###VICTIM### got kicked###REASON_STUFF###</font><br />]];
+html.day.bann = [[###TIME_STUFF###<font class="muc_bann"> *** ###VICTIM### got banned###REASON_STUFF###</font><br />]];
+html.day.body = [[<h2>room ###JID### logging of 20###YEAR###/###MONTH###/###DAY###</h2>
+<p>###TITLE_STUFF###</p>
+<hr /><p>
 ###DAY_STUFF###
 </p><hr />]];
 
@@ -113,7 +117,8 @@
 		return;
 	end
 	
-	if	(stanza.name == "presence") or 
+	if	(stanza.name == "presence") or
+		(stanza.name == "iq") or
 	   	(stanza.name == "message" and tostring(stanza.attr.type) == "groupchat")
 	then
 		local node, host, resource = splitJid(stanza.attr.to);
@@ -124,32 +129,67 @@
 				local today = os.date("%y%m%d");
 				local now = os.date("%X")
 				local fn = config.folder .. "/" .. today .. "_" .. bare .. ".log";
+				local mucTo = nil
 				local mucFrom = nil;
+				local alreadyJoined = false;
 		
 				if stanza.name == "presence" and stanza.attr.type == nil then
 					mucFrom = stanza.attr.to;
+					if room._occupants ~= nil and room._occupants[stanza.attr.to] ~= nil then -- if true, the user has already joined the room
+						alreadyJoined = true;
+						stanza:tag("alreadyJoined"):text("true"); -- we need to log the information that the user has already joined, so add this and remove after logging
+					end
+				elseif stanza.name == "iq" and stanza.attr.type == "set" then -- kick, to is the room, from is the admin, nick who is kicked is attr of iq->query->item
+					if stanza.tags[1] ~= nil and stanza.tags[1].name == "query" then
+						local tmp = stanza.tags[1];
+						if tmp.tags[1] ~= nil and tmp.tags[1].name == "item" and tmp.tags[1].attr.nick ~= nil then
+							tmp = tmp.tags[1];
+							for jid, nick in pairs(room._jid_nick) do
+								module:log("debug", "%s == %s", nick, stanza.attr.to .. "/" .. tmp.attr.nick)
+								if nick == stanza.attr.to .. "/" .. tmp.attr.nick then
+									mucTo = nick;
+									break;
+								end
+							end
+						end
+					end
 				else
 					for jid, nick in pairs(room._jid_nick) do
 						if jid == stanza.attr.from then
 							mucFrom = nick;
+							break;
 						end
 					end
 				end
 
-				if mucFrom ~= nil then
+				if mucFrom ~= nil or mucTo ~= nil then
 					module:log("debug", "try to open room log: %s", fn);
 					local f = assert(io.open(fn, "a"));
 					local realFrom = stanza.attr.from;
 					local realTo = stanza.attr.to;
 					stanza.attr.from = mucFrom;
-					stanza.attr.to = nil;
+					stanza.attr.to = mucTo;
 					f:write("<stanza time=\"".. now .. "\">" .. tostring(stanza) .. "</stanza>\n");
 					stanza.attr.from = realFrom;
 					stanza.attr.to = realTo;
+					if alreadyJoined == true then
+						if stanza[#stanza].name == "alreadyJoined" then  -- normaly the faked element should be the last, remove it when it is the last
+							stanza[#stanza] = nil;
+						else
+							for i = 1, #stanza, 1 do
+								if stanza[i].name == "alreadyJoined" then  -- remove the faked element
+									stanza[i] = nil;
+									break;
+								end
+							end
+						end
+					end
 					f:close()
 				end
 			end
 		end
+	else
+		module:log("debug", serialize(stanza));
 	end
 	return;
 end
@@ -240,20 +280,52 @@
 	end
 end
 
+local function parseIqStanza(stanza, timeStuff, nick)
+	local text = nil;
+	-- module:log("debug", serialize(stanza));
+	for _,tag in ipairs(stanza) do
+		if tag.tag == "query" then
+			for _,item in ipairs(tag) do
+				if item.tag == "item" then
+					for _,reason in ipairs(item) do
+						if reason.tag == "reason" then
+							text = reason[1];
+							break;
+						end
+					end
+					break;
+				end 
+			end
+			break;
+		end
+	end
+	
+	if text ~= nil then	
+		text = html.day.reason:gsub("###REASON###", htmlEscape(text));
+	else
+		text = "";
+	end	
+	return html.day.kick:gsub("###TIME_STUFF###", timeStuff):gsub("###VICTIM###", nick):gsub("###REASON_STUFF###", text);
+end
+
 local function parsePresenceStanza(stanza, timeStuff, nick)
 	local ret = "";
-	-- module:log("debug", serialize(stanza));
-	if stanza[1].attr.type == nil then
+	if stanza.attr.type == nil then
 		local show, status = nil, "";
-		for _, tag in ipairs(stanza[1]) do
-			module:log("debug", serialize(tag));
-			if tag.tag == "show" then
+		local alreadyJoined = false;
+		for _, tag in ipairs(stanza) do
+			if tag.tag == "alreadyJoined" then
+				alreadyJoined = true;
+			elseif tag.tag == "show" then
 				show = tag[1];
 			elseif tag.tag == "status" then
 				status = tag[1];
 			end
 		end
-		if show ~= nil then
+		if alreadyJoined == true then
+			if show == nil then
+				show = "online";
+			end
 			ret = html.day.presence.statusChange:gsub("###TIME_STUFF###", timeStuff);
 			if status ~= "" then
 				status = html.day.presence.statusText:gsub("###STATUS###", htmlEscape(status));
@@ -262,7 +334,7 @@
 		else
 			ret = html.day.presence.join:gsub("###TIME_STUFF###", timeStuff):gsub("###NICK###", nick);
 		end
-	elseif stanza[1].attr.type ~= nil and stanza[1].attr.type == "unavailable" then
+	elseif stanza.attr.type ~= nil and stanza.attr.type == "unavailable" then
 		ret = html.day.presence.leave:gsub("###TIME_STUFF###", timeStuff):gsub("###NICK###", nick);
 	end
 	return ret;
@@ -271,7 +343,7 @@
 local function parseMessageStanza(stanza, timeStuff, nick)
 	local body, title, ret = nil, nil, "";
 	
-	for _,tag in ipairs(stanza[1]) do
+	for _,tag in ipairs(stanza) do
 		if tag.tag == "body" then
 			body = tag[1];
 			if nick ~= nil then
@@ -299,7 +371,7 @@
 	return ret;
 end
 
-local function parseDay(bareRoomJid, query)
+local function parseDay(bareRoomJid, roomSubject, query)
 	local ret = "";
 	local year;
 	local month;
@@ -321,14 +393,18 @@
 							local nick;
 							
 							-- grep nick from "from" resource
-							if stanza[1].attr.from ~= nil then
+							if stanza[1].attr.from ~= nil then -- presence and messages
 								nick = htmlEscape(stanza[1].attr.from:match("/(.+)$"));
+							elseif stanza[1].attr.to ~= nil then -- iq
+								nick = htmlEscape(stanza[1].attr.to:match("/(.+)$"));
 							end
 							
 							if stanza[1].tag == "presence" and nick ~= nil then
-								ret = ret .. parsePresenceStanza(stanza, timeStuff, nick);
+								ret = ret .. parsePresenceStanza(stanza[1], timeStuff, nick);
 							elseif stanza[1].tag == "message" then
-								ret = ret .. parseMessageStanza(stanza, timeStuff, nick);
+								ret = ret .. parseMessageStanza(stanza[1], timeStuff, nick);
+							elseif stanza[1].tag == "iq" then
+								ret = ret .. parseIqStanza(stanza[1], timeStuff, nick);
 							else
 								module:log("info", "unknown stanza subtag in log found. room: %s; day: %s", bareRoomJid, query.year .. "/" .. query.month .. "/" .. query.day);
 							end
@@ -339,10 +415,11 @@
 					module:log("warn", "could not parse room log. room: %s; day: %s", bareRoomJid, query.year .. "/" .. query.month .. "/" .. query.day);
 			end
 		else
-			ret = err;
+			return generateDayListSiteContentByRoom(bareRoomJid); -- fallback
 		end
 		tmp = html.day.body:gsub("###DAY_STUFF###", ret):gsub("###JID###", bareRoomJid);
 		tmp = tmp:gsub("###YEAR###", query.year):gsub("###MONTH###", query.month):gsub("###DAY###", query.day);
+		tmp = tmp:gsub("###TITLE_STUFF###", html.day.title:gsub("###TITLE###", roomSubject));
 		return tmp;
 	else
 		return generateDayListSiteContentByRoom(bareRoomJid); -- fallback
@@ -350,7 +427,6 @@
 end
 
 function handle_request(method, body, request)
-	module:log("debug", "got a request ...")
 	local query = splitQuery(request.url.query);
 	local node, host = grepRoomJid(request.url.path);
 	
@@ -364,10 +440,14 @@
 			if request.url.query == nil then
 				return createDoc(generateDayListSiteContentByRoom(bare));
 			else
-				return createDoc(parseDay(bare, query));
+				local subject = ""
+				if room._data ~= nil and room._data.subject ~= nil then
+					subject = room._data.subject;
+				end
+				return createDoc(parseDay(bare, subject, query));
 			end
 		else
-			module:log("warn", "room instance not found. bare room jid: %s", tostring(bare));
+			return createDoc(generateRoomListSiteContent());
 		end
 	else
 		return createDoc(generateRoomListSiteContent());
@@ -376,11 +456,12 @@
 end
 
 config = config_get(module:get_host(), "core", "muc_log");
-module:log("debug", serialize(config));
 
 httpserver.new_from_config({ config.http_port or true }, handle_request, { base = "muc_log" });
 
 module:hook("message/bare", logIfNeeded, 500);
 module:hook("pre-message/bare", logIfNeeded, 500);
+module:hook("iq/bare", logIfNeeded, 500);
+module:hook("pre-iq/bare", logIfNeeded, 500);
 module:hook("presence/full", logIfNeeded, 500);
 module:hook("pre-presence/full", logIfNeeded, 500);