comparison mod_muc_log/mod_muc_log.lua @ 55:d9749ed44f6e

mod_muc_log: make it recognize s2s messages/presences
author Thilo Cestonaro <thilo@cestona.ro>
date Mon, 19 Oct 2009 16:06:48 +0200
parents f15108153710
children e9de45beaf5e
comparison
equal deleted inserted replaced
54:f15108153710 55:d9749ed44f6e
18 local lfs = require "lfs"; 18 local lfs = require "lfs";
19 19
20 local lom = require "lxp.lom"; 20 local lom = require "lxp.lom";
21 21
22 function validateLogFolder() 22 function validateLogFolder()
23 module:log("debug", "validateLogFolder; Folder: %s", tostring(config.folder));
24 if config.folder == nil then 23 if config.folder == nil then
25 module:log("warn", "muc_log folder isn't configured. configure it please!"); 24 module:log("warn", "muc_log folder isn't configured. configure it please!");
26 return false; 25 return false;
27 end 26 end
28 27
34 elseif attributes.mode ~= "directory" then 33 elseif attributes.mode ~= "directory" then
35 module:log("warn", "muc_log folder isn't a folder, it's a %s. change this please!", attributes.mode); 34 module:log("warn", "muc_log folder isn't a folder, it's a %s. change this please!", attributes.mode);
36 return false; 35 return false;
37 end --TODO: check for write rights! 36 end --TODO: check for write rights!
38 37
39 module:log("debug", "Folder is validated and correct.")
40 return true; 38 return true;
41 end 39 end
42 40
43 function logIfNeeded(e) 41 function logIfNeeded(e)
44 local stanza, origin = e.stanza, e.origin; 42 local stanza, origin = e.stanza, e.origin;
45 if validateLogFolder() == false then 43 if validateLogFolder() == false then
46 return; 44 return;
47 end 45 end
48 46
49 if (stanza.name == "presence") or 47 if (stanza.name == "presence") or
50 (stanza.name == "message" and tostring(stanza.attr.type) == "groupchat") 48 (stanza.name == "message" and tostring(stanza.attr.type) == "groupchat")
51 then 49 then
52 local node, host, resource = splitJid(stanza.attr.to); 50 local node, host, resource = splitJid(stanza.attr.to);
53 if node ~= nil and host ~= nil then 51 if node ~= nil and host ~= nil then
54 local bare = node .. "@" .. host; 52 local bare = node .. "@" .. host;
55 if prosody.hosts[host] ~= nil and prosody.hosts[host].muc ~= nil and prosody.hosts[host].muc.rooms[bare] ~= nil then 53 if prosody.hosts[host] ~= nil and prosody.hosts[host].muc ~= nil and prosody.hosts[host].muc.rooms[bare] ~= nil then
56 local room = prosody.hosts[host].muc.rooms[bare] 54 local room = prosody.hosts[host].muc.rooms[bare]
57 local logging = config_get(host, "core", "logging"); 55 local today = os.date("%y%m%d");
58 if logging == true then 56 local now = os.date("%X")
59 local today = os.date("%y%m%d"); 57 local fn = config.folder .. "/" .. today .. "_" .. bare .. ".log";
60 local now = os.date("%X") 58 local mucFrom = nil;
61 local fn = config.folder .. "/" .. today .. "_" .. bare .. ".log"; 59
62 local mucFrom = nil; 60 if stanza.name == "presence" and stanza.attr.type == nil then
63 61 mucFrom = stanza.attr.to;
64 if stanza.name == "presence" and stanza.attr.type == nil then 62 else
65 mucFrom = stanza.attr.to; 63 for jid, nick in pairs(room._jid_nick) do
66 else 64 if jid == stanza.attr.from then
67 for jid, nick in pairs(room._jid_nick) do 65 mucFrom = nick;
68 if jid == stanza.attr.from then
69 mucFrom = nick;
70 end
71 end 66 end
72 end 67 end
73 68 end
74 if mucFrom ~= nil then 69
75 module:log("debug", "try to open room log: %s", fn); 70 if mucFrom ~= nil then
76 local f = assert(io.open(fn, "a")); 71 module:log("debug", "try to open room log: %s", fn);
77 local realFrom = stanza.attr.from; 72 local f = assert(io.open(fn, "a"));
78 local realTo = stanza.attr.to; 73 local realFrom = stanza.attr.from;
79 stanza.attr.from = mucFrom; 74 local realTo = stanza.attr.to;
80 stanza.attr.to = nil; 75 stanza.attr.from = mucFrom;
81 f:write("<stanza time=\"".. now .. "\">" .. tostring(stanza) .. "</stanza>\n"); 76 stanza.attr.to = nil;
82 stanza.attr.from = realFrom; 77 f:write("<stanza time=\"".. now .. "\">" .. tostring(stanza) .. "</stanza>\n");
83 stanza.attr.to = realTo; 78 stanza.attr.from = realFrom;
84 f:close() 79 stanza.attr.to = realTo;
85 end 80 f:close()
86 end 81 end
87 end 82 end
88 end 83 end
89 end 84 end
90 return; 85 return;
147 142
148 local function generateRoomListSiteContent() 143 local function generateRoomListSiteContent()
149 local ret = "<h2>Rooms hosted on this server:</h2><hr /><p>"; 144 local ret = "<h2>Rooms hosted on this server:</h2><hr /><p>";
150 for host, config in pairs(prosody.hosts) do 145 for host, config in pairs(prosody.hosts) do
151 if prosody.hosts[host].muc ~= nil then 146 if prosody.hosts[host].muc ~= nil then
152 local logging = config_get(host, "core", "logging"); 147 for jid, room in pairs(prosody.hosts[host].muc.rooms) do
153 if logging then 148 ret = ret .. "<a href=\"/muc_log/" .. jid .. "/\">" .. jid .."</a><br />\n";
154 for jid, room in pairs(prosody.hosts[host].muc.rooms) do
155 ret = ret .. "<a href=\"/muc_log/" .. jid .. "/\">" .. jid .."</a><br />\n";
156 end
157 else
158 module:log("debug", "logging not enabled for muc component: %s", tostring(host));
159 end 149 end
160 end 150 end
161 end 151 end
162 return ret .. "</p><hr />"; 152 return ret .. "</p><hr />";
163 end 153 end
165 local function generateDayListSiteContentByRoom(bareRoomJid) 155 local function generateDayListSiteContentByRoom(bareRoomJid)
166 local ret = ""; 156 local ret = "";
167 157
168 for file in lfs.dir(config.folder) do 158 for file in lfs.dir(config.folder) do
169 local year, month, day = file:match("^(%d%d)(%d%d)(%d%d)_" .. bareRoomJid .. ".log"); 159 local year, month, day = file:match("^(%d%d)(%d%d)(%d%d)_" .. bareRoomJid .. ".log");
170 module:log("debug", "year: %s, month: %s, day: %s", year, month, day);
171 if year ~= nil and month ~= nil and day ~= nil and 160 if year ~= nil and month ~= nil and day ~= nil and
172 year ~= "" and month ~= "" and day ~= "" 161 year ~= "" and month ~= "" and day ~= ""
173 then 162 then
174 ret = "<a href=\"/muc_log/" .. bareRoomJid .. "/?year=" .. year .. "&month=" .. month .. "&day=" .. day .. "\">20" .. year .. "/" .. month .. "/" .. day .. "</a><br />\n" .. ret; 163 ret = "<a href=\"/muc_log/" .. bareRoomJid .. "/?year=" .. year .. "&month=" .. month .. "&day=" .. day .. "\">20" .. year .. "/" .. month .. "/" .. day .. "</a><br />\n" .. ret;
175 end 164 end
207 if f ~= nil then 196 if f ~= nil then
208 local content = f:read("*a"); 197 local content = f:read("*a");
209 local parsed = lom.parse("<xml>" .. content .. "</xml>"); 198 local parsed = lom.parse("<xml>" .. content .. "</xml>");
210 if parsed ~= nil then 199 if parsed ~= nil then
211 for _,stanza in ipairs(parsed) do 200 for _,stanza in ipairs(parsed) do
212 -- module:log("debug", "dump of stanza: \n%s", dump(stanza))
213 if stanza.attr ~= nil and stanza.attr.time ~= nil then 201 if stanza.attr ~= nil and stanza.attr.time ~= nil then
214 ret = ret .. "<a name=\"" .. stanza.attr.time .. "\" href=\"#" .. stanza.attr.time .. "\" class=\"timestuff\">[" .. stanza.attr.time .. "]</a> "; 202 local tmp = "<a name=\"" .. stanza.attr.time .. "\" href=\"#" .. stanza.attr.time .. "\" class=\"timestuff\">[" .. stanza.attr.time .. "]</a> ";
215 if stanza[1] ~= nil then 203 if stanza[1] ~= nil then
216 local nick; 204 local nick;
217 if stanza[1].attr.from ~= nil then 205 if stanza[1].attr.from ~= nil then
218 nick = stanza[1].attr.from:match("/(.+)$"); 206 nick = stanza[1].attr.from:match("/(.+)$");
219 end 207 end
220 if stanza[1].tag == "presence" and nick ~= nil then 208 if stanza[1].tag == "presence" and nick ~= nil then
221 if stanza[1].attr.type == nil then 209 if stanza[1].attr.type == nil then
222 ret = ret .. "<font class=\"muc_join\"> *** " .. nick .. " joins the room</font><br />\n"; 210 ret = ret .. tmp .. "<font class=\"muc_join\"> *** " .. nick .. " joins the room</font><br />\n";
223 elseif stanza[1].attr.type ~= nil and stanza[1].attr.type == "unavailable" then 211 elseif stanza[1].attr.type ~= nil and stanza[1].attr.type == "unavailable" then
224 ret = ret .. "<font class=\"muc_leave\"> *** " .. nick .. " leaves the room</font><br />\n"; 212 ret = ret .. tmp .. "<font class=\"muc_leave\"> *** " .. nick .. " leaves the room</font><br />\n";
225 else 213 else
226 ret = ret .. "<font class=\"muc_leave\"> *** " .. nick .. " changed his/her status to: " .. stanza[1].attr.type .. "</font><br />\n"; 214 ret = ret .. tmp .. "<font class=\"muc_leave\"> *** " .. nick .. " changed his/her status to: " .. stanza[1].attr.type .. "</font><br />\n";
227 end 215 end
228 elseif stanza[1].tag == "message" then 216 elseif stanza[1].tag == "message" then
229 local body; 217 local body;
230 for _,tag in ipairs(stanza[1]) do 218 for _,tag in ipairs(stanza[1]) do
231 if tag.tag == "body" then 219 if tag.tag == "body" then
239 break; 227 break;
240 end 228 end
241 end 229 end
242 end 230 end
243 if nick ~= nil and body ~= nil then 231 if nick ~= nil and body ~= nil then
244 ret = ret .. "<font class=\"muc_name\">&lt;" .. nick .. "&gt;</font> " .. body .. "<br />\n"; 232 ret = ret .. tmp .. "<font class=\"muc_name\">&lt;" .. nick .. "&gt;</font> " .. body .. "<br />\n";
245 end 233 end
246 else 234 else
247 module:log("info", "unknown stanza subtag in log found. room: %s; day: %s", bareRoomJid, year .. "/" .. month .. "/" .. day); 235 module:log("info", "unknown stanza subtag in log found. room: %s; day: %s", bareRoomJid, year .. "/" .. month .. "/" .. day);
248 end 236 end
249 end 237 end
261 return generateDayListSiteContentByRoom(bareRoomJid); -- fallback 249 return generateDayListSiteContentByRoom(bareRoomJid); -- fallback
262 end 250 end
263 end 251 end
264 252
265 function handle_request(method, body, request) 253 function handle_request(method, body, request)
266 module:log("debug", "method: %s, body: %s, request: %s", tostring(method), tostring(body), tostring(request));
267 -- module:log("debug", "dump of request:\n%s\n", dump(request));
268 local query = splitQuery(request.url.query); 254 local query = splitQuery(request.url.query);
269 local node, host = grepRoomJid(request.url.path); 255 local node, host = grepRoomJid(request.url.path);
270 256
271 if validateLogFolder() == false then 257 if validateLogFolder() == false then
272 return createDoc([[ 258 return createDoc([[
281 end 267 end
282 if node ~= nil and host ~= nil then 268 if node ~= nil and host ~= nil then
283 local bare = node .. "@" .. host; 269 local bare = node .. "@" .. host;
284 if prosody.hosts[host] ~= nil and prosody.hosts[host].muc ~= nil and prosody.hosts[host].muc.rooms[bare] ~= nil then 270 if prosody.hosts[host] ~= nil and prosody.hosts[host].muc ~= nil and prosody.hosts[host].muc.rooms[bare] ~= nil then
285 local room = prosody.hosts[host].muc.rooms[bare]; 271 local room = prosody.hosts[host].muc.rooms[bare];
286 local logging = config_get(host, "core", "logging"); 272 if request.url.query == nil then
287 if logging == true then 273 return createDoc(generateDayListSiteContentByRoom(bare));
288 if request.url.query == nil then
289 return createDoc(generateDayListSiteContentByRoom(bare));
290 else
291 return createDoc(parseDay(bare, query));
292 end
293 else 274 else
294 module:log("debug", "logging not enabled for this room: %s", bare); 275 return createDoc(parseDay(bare, query));
295 end 276 end
296 else 277 else
297 module:log("debug", "room instance not found. bare room jid: %s", tostring(bare)); 278 module:log("warn", "room instance not found. bare room jid: %s", tostring(bare));
298 end 279 end
299 else 280 else
300 return createDoc(generateRoomListSiteContent()); 281 return createDoc(generateRoomListSiteContent());
301 end 282 end
302 return; 283 return;
303 end 284 end
304 285
305 function module.load() 286 config = config_get(module:get_host(), "core", "muc_log");
306 config = config_get("*", "core", "muc_log"); 287
307 -- module:log("debug", "muc_log config: \n%s", dump(config)); 288 httpserver.new_from_config({ config.http_port or true }, handle_request, { base = "muc_log" });
308 289
309 httpserver.new_from_config({ config.http_port or true }, handle_request, { base = "muc_log" }); 290 module:hook("message/bare", logIfNeeded, 500);
310 return validateLogFolder();
311 end
312
313 module:hook("pre-message/bare", logIfNeeded, 500); 291 module:hook("pre-message/bare", logIfNeeded, 500);
292 module:hook("presence/full", logIfNeeded, 500);
314 module:hook("pre-presence/full", logIfNeeded, 500); 293 module:hook("pre-presence/full", logIfNeeded, 500);