comparison mod_muc_log_http/muc_log_http/mod_muc_log_http.lua @ 348:03e1dc036a28

mod_muc_log_http: HTML overhaul. Replacing deprecated elements and style-attributes.
author Florian Zeitz <florob@babelmonkeys.de>
date Sun, 27 Mar 2011 05:34:09 +0200
parents 2b0f2160fc61
children 5ef71af77ae2
comparison
equal deleted inserted replaced
346:2e6a74842c00 348:03e1dc036a28
1 -- Copyright (C) 2009 Thilo Cestonaro 1 -- Copyright (C) 2009 Thilo Cestonaro
2 -- 2 --
3 -- This project is MIT/X11 licensed. Please see the 3 -- This project is MIT/X11 licensed. Please see the
4 -- COPYING file in the source package for more information. 4 -- COPYING file in the source package for more information.
5 -- 5 --
6 6
7 module:set_global(); 7 module:set_global();
26 local tostring = _G.tostring; 26 local tostring = _G.tostring;
27 local tonumber = _G.tonumber; 27 local tonumber = _G.tonumber;
28 local os_date, os_time = os.date, os.time; 28 local os_date, os_time = os.date, os.time;
29 local str_format = string.format; 29 local str_format = string.format;
30 local io_open = io.open; 30 local io_open = io.open;
31 local themesParent = (CFG_PLUGINDIR or "./plugins/") .. "muc_log_http/themes"; 31 local themesParent = (module.path and module.path:gsub("[/\\][^/\\]*$", "") or (prosody.paths.plugins or "./plugins") .. "/muc_log_http") .. "/themes";
32 32
33 local lom = require "lxp.lom"; 33 local lom = require "lxp.lom";
34 34
35 --[[ LuaFileSystem 35 --[[ LuaFileSystem
36 * URL: http://www.keplerproject.org/luafilesystem/index.html 36 * URL: http://www.keplerproject.org/luafilesystem/index.html
37 * Install: luarocks install luafilesystem 37 * Install: luarocks install luafilesystem
38 * ]] 38 * ]]
39 local lfs = require "lfs"; 39 local lfs = require "lfs";
40 40
44 ]]-- 44 ]]--
45 local html = {}; 45 local html = {};
46 local theme; 46 local theme;
47 47
48 local function checkDatastorePathExists(node, host, today, create) 48 local function checkDatastorePathExists(node, host, today, create)
49 create = create or false; 49 create = create or false;
50 local path = data_getpath(node, host, datastore, "dat", true); 50 local path = data_getpath(node, host, datastore, "dat", true);
51 path = path:gsub("/[^/]*$", ""); 51 path = path:gsub("/[^/]*$", "");
52 52
53 -- check existance 53 -- check existance
54 local attributes, err = lfs.attributes(path); 54 local attributes, err = lfs.attributes(path);
55 if attributes == nil or attributes.mode ~= "directory" then 55 if attributes == nil or attributes.mode ~= "directory" then
56 module:log("warn", "muc_log folder isn't a folder: %s", path); 56 module:log("warn", "muc_log folder isn't a folder: %s", path);
57 return false; 57 return false;
58 end 58 end
59 59
60 attributes, err = lfs.attributes(path .. "/" .. today); 60 attributes, err = lfs.attributes(path .. "/" .. today);
61 if attributes == nil then 61 if attributes == nil then
62 if create then 62 if create then
63 return lfs.mkdir(path .. "/" .. today); 63 return lfs.mkdir(path .. "/" .. today);
64 else 64 else
65 return false; 65 return false;
66 end 66 end
67 elseif attributes.mode == "directory" then 67 elseif attributes.mode == "directory" then
68 return true; 68 return true;
69 end 69 end
70 return false; 70 return false;
71 end 71 end
72 72
73 function createDoc(body) 73 function createDoc(body)
74 if body then 74 if body then
75 body = body:gsub("%%", "%%%%"); 75 body = body:gsub("%%", "%%%%");
76 return html.doc:gsub("###BODY_STUFF###", body); 76 return html.doc:gsub("###BODY_STUFF###", body);
77 end 77 end
78 end 78 end
79 79
80 function urlunescape (escapedUrl) 80 function urlunescape (escapedUrl)
81 escapedUrl = escapedUrl:gsub("+", " ") 81 escapedUrl = escapedUrl:gsub("+", " ")
82 escapedUrl = escapedUrl:gsub("%%(%x%x)", function(h) return strchar(tonumber(h,16)) end) 82 escapedUrl = escapedUrl:gsub("%%(%x%x)", function(h) return strchar(tonumber(h,16)) end)
83 escapedUrl = escapedUrl:gsub("\r\n", "\n") 83 escapedUrl = escapedUrl:gsub("\r\n", "\n")
84 return escapedUrl 84 return escapedUrl
85 end 85 end
86 86
87 local function htmlEscape(t) 87 local function htmlEscape(t)
88 if t then 88 if t then
89 t = t:gsub("<", "&lt;"); 89 t = t:gsub("<", "&lt;");
90 t = t:gsub(">", "&gt;"); 90 t = t:gsub(">", "&gt;");
91 t = t:gsub("(http://[%a%d@%.:/&%?=%-_#%%~]+)", function(h) 91 t = t:gsub("(http://[%a%d@%.:/&%?=%-_#%%~]+)", function(h)
92 h = urlunescape(h) 92 h = urlunescape(h)
93 return "<a href='" .. h .. "'>" .. h .. "</a>"; 93 return "<a href='" .. h .. "'>" .. h .. "</a>";
94 end); 94 end);
95 t = t:gsub("\n", "<br />"); 95 t = t:gsub("\n", "<br />");
96 t = t:gsub("%%", "%%%%"); 96 t = t:gsub("%%", "%%%%");
97 else 97 else
98 t = ""; 98 t = "";
99 end 99 end
100 return t; 100 return t;
101 end 101 end
102 102
103 function splitUrl(url) 103 function splitUrl(url)
104 local tmp = url:sub(string.len("/muc_log/") + 1); 104 local tmp = url:sub(string.len("/muc_log/") + 1);
105 local day = nil; 105 local day = nil;
106 local room = nil; 106 local room = nil;
107 local component = nil; 107 local component = nil;
108 local at = nil; 108 local at = nil;
109 local slash = nil; 109 local slash = nil;
110 local slash2 = nil; 110 local slash2 = nil;
111 111
112 slash = tmp:find("/"); 112 slash = tmp:find("/");
113 if slash then 113 if slash then
114 component = tmp:sub(1, slash - 1); 114 component = tmp:sub(1, slash - 1);
115 if tmp:len() > slash then 115 if tmp:len() > slash then
116 room = tmp:sub(slash + 1); 116 room = tmp:sub(slash + 1);
117 slash = room:find("/"); 117 slash = room:find("/");
118 if slash then 118 if slash then
119 tmp = room; 119 tmp = room;
120 room = tmp:sub(1, slash - 1); 120 room = tmp:sub(1, slash - 1);
121 if tmp:len() > slash then 121 if tmp:len() > slash then
122 day = tmp:sub(slash + 1); 122 day = tmp:sub(slash + 1);
123 slash = day:find("/"); 123 slash = day:find("/");
124 if slash then 124 if slash then
125 day = day:sub(1, slash - 1); 125 day = day:sub(1, slash - 1);
126 end 126 end
127 end 127 end
128 end 128 end
129 end 129 end
130 end 130 end
131 131
132 return room, component, day; 132 return room, component, day;
133 end 133 end
134 134
135 local function generateComponentListSiteContent() 135 local function generateComponentListSiteContent()
136 local components = ""; 136 local components = "";
137 for component,muc_host in pairs(muc_hosts or {}) do 137 for component,muc_host in pairs(muc_hosts or {}) do
138 components = components .. html.components.bit:gsub("###COMPONENT###", component); 138 components = components .. html.components.bit:gsub("###COMPONENT###", component);
139 end 139 end
140 if components ~= "" then 140 if components ~= "" then
141 return html.components.body:gsub("###COMPONENTS_STUFF###", components); 141 return html.components.body:gsub("###COMPONENTS_STUFF###", components);
142 end 142 end
143 end 143 end
144 144
145 local function generateRoomListSiteContent(component) 145 local function generateRoomListSiteContent(component)
146 local rooms = ""; 146 local rooms = "";
147 if prosody.hosts[component] and prosody.hosts[component].muc ~= nil then 147 if prosody.hosts[component] and prosody.hosts[component].muc ~= nil then
148 for jid, room in pairs(prosody.hosts[component].muc.rooms) do 148 for jid, room in pairs(prosody.hosts[component].muc.rooms) do
149 local node = splitJid(jid); 149 local node = splitJid(jid);
150 if not room._data.hidden and node then 150 if not room._data.hidden and node then
151 rooms = rooms .. html.rooms.bit:gsub("###ROOM###", node):gsub("###COMPONENT###", component); 151 rooms = rooms .. html.rooms.bit:gsub("###ROOM###", node):gsub("###COMPONENT###", component);
152 end 152 end
153 end 153 end
154 if rooms ~= "" then 154 if rooms ~= "" then
155 return html.rooms.body:gsub("###ROOMS_STUFF###", rooms):gsub("###COMPONENT###", component); 155 return html.rooms.body:gsub("###ROOMS_STUFF###", rooms):gsub("###COMPONENT###", component);
156 end 156 end
157 end 157 end
158 end 158 end
159 159
160 -- Calendar stuff 160 -- Calendar stuff
161 local function getDaysForMonth(month, year) 161 local function getDaysForMonth(month, year)
162 local daysCount = 30; 162 local daysCount = 30;
175 if month == 2 and leapyear then 175 if month == 2 and leapyear then
176 daysCount = 29; 176 daysCount = 29;
177 elseif month == 2 and not leapyear then 177 elseif month == 2 and not leapyear then
178 daysCount = 28; 178 daysCount = 28;
179 elseif month < 8 and month%2 == 1 or 179 elseif month < 8 and month%2 == 1 or
180 month >= 8 and month%2 == 0 180 month >= 8 and month%2 == 0
181 then 181 then
182 daysCount = 31; 182 daysCount = 31;
183 end 183 end
184 return daysCount; 184 return daysCount;
185 end 185 end
186 186
187 local function createMonth(month, year, dayCallback) 187 local function createMonth(month, year, dayCallback)
188 local htmlStr = html.month.header; 188 local htmlStr = html.month.header;
189 local days = getDaysForMonth(month, year); 189 local days = getDaysForMonth(month, year);
190 local time = os_time{year=year, month=month, day=1}; 190 local time = os_time{year=year, month=month, day=1};
191 local dow = tostring(os_date("%a", time)) 191 local dow = tostring(os_date("%a", time))
192 local title = tostring(os_date("%B", time)); 192 local title = tostring(os_date("%B", time));
193 local weekDays = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"}; 193 local weekDays = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};
194 local weekDay = 0; 194 local weekDay = 0;
195 local weeks = 1; 195 local weeks = 1;
196 local logAvailableForMinimumOneDay = false; 196 local logAvailableForMinimumOneDay = false;
197 197
198 local weekDaysHtml = ""; 198 local weekDaysHtml = "";
199 for _, tmp in ipairs(weekDays) do 199 for _, tmp in ipairs(weekDays) do
200 weekDaysHtml = weekDaysHtml .. html.month.weekDay:gsub("###DAY###", tmp) .. "\n"; 200 weekDaysHtml = weekDaysHtml .. html.month.weekDay:gsub("###DAY###", tmp) .. "\n";
201 end 201 end
202 202
203 htmlStr = htmlStr:gsub("###TITLE###", title):gsub("###WEEKDAYS###", weekDaysHtml); 203 htmlStr = htmlStr:gsub("###TITLE###", title):gsub("###WEEKDAYS###", weekDaysHtml);
204 204
205 for i = 1, 31 do 205 for i = 1, 31 do
206 weekDay = weekDay + 1; 206 weekDay = weekDay + 1;
207 if weekDay == 1 then htmlStr = htmlStr .. "<tr>\n"; end 207 if weekDay == 1 then htmlStr = htmlStr .. "<tr>\n"; end
208 if i == 1 then 208 if i == 1 then
209 for _, tmp in ipairs(weekDays) do 209 for _, tmp in ipairs(weekDays) do
210 if dow ~= tmp then 210 if dow ~= tmp then
211 htmlStr = htmlStr .. html.month.emptyDay .. "\n";
212 weekDay = weekDay + 1;
213 else
214 break;
215 end
216 end
217 end
218 if i < days + 1 then
219 local tmp = tostring(i);
220 if dayCallback ~= nil and dayCallback.callback ~= nil then
221 tmp = dayCallback.callback(dayCallback.path, i, month, year, dayCallback.room, dayCallback.webPath);
222 end
223 if tmp == nil then
224 tmp = tostring(i);
225 else
226 logAvailableForMinimumOneDay = true;
227 end
228 htmlStr = htmlStr .. html.month.day:gsub("###DAY###", tmp) .. "\n";
229 end
230
231 if i >= days then
232 break;
233 end
234
235 if weekDay == 7 then
236 weekDay = 0;
237 weeks = weeks + 1;
238 htmlStr = htmlStr .. "</tr>\n";
239 end
240 end
241
242 if weekDay + 1 < 8 or weeks < 6 then
243 weekDay = weekDay + 1;
244 if weekDay > 7 then
245 weekDay = 1;
246 end
247 if weekDay == 1 then
248 weeks = weeks + 1;
249 end
250 for y = weeks, 6 do
251 if weekDay == 1 then
252 htmlStr = htmlStr .. "<tr>\n";
253 end
254 for i = weekDay, 7 do
211 htmlStr = htmlStr .. html.month.emptyDay .. "\n"; 255 htmlStr = htmlStr .. html.month.emptyDay .. "\n";
212 weekDay = weekDay + 1; 256 end
257 weekDay = 1
258 htmlStr = htmlStr .. "</tr>\n";
259 end
260 end
261 htmlStr = htmlStr .. html.month.footer;
262 if logAvailableForMinimumOneDay then
263 return htmlStr;
264 end
265 end
266
267 local function createYear(year, dayCallback)
268 local year = year;
269 local tmp;
270 if tonumber(year) <= 99 then
271 year = year + 2000;
272 end
273 local htmlStr = "";
274 for i=1, 12 do
275 tmp = createMonth(i, year, dayCallback);
276 if tmp then
277 htmlStr = htmlStr .. "<div style='float: left; padding: 5px;'>\n" .. tmp .. "</div>\n";
278 end
279 end
280 if htmlStr ~= "" then
281 return "<div name='yearDiv' style='padding: 40px; text-align: center;'>" .. html.year.title:gsub("###YEAR###", tostring(year)) .. htmlStr .. "</div><br style='clear:both;'/> \n";
282 end
283 return "";
284 end
285
286 local function perDayCallback(path, day, month, year, room, webPath)
287 local webPath = webPath or ""
288 local year = year;
289 if year > 2000 then
290 year = year - 2000;
291 end
292 local bareDay = str_format("%.02d%.02d%.02d", year, month, day);
293 room = urlencode(room);
294 local attributes, err = lfs.attributes(path.."/"..bareDay.."/"..room..".dat")
295 if attributes ~= nil and attributes.mode == "file" then
296 local s = html.days.bit;
297 s = s:gsub("###BARE_DAY###", webPath .. bareDay);
298 s = s:gsub("###DAY###", day);
299 return s;
300 end
301 return;
302 end
303
304 local function generateDayListSiteContentByRoom(bareRoomJid)
305 local days = "";
306 local arrDays = {};
307 local tmp;
308 local node, host, resource = splitJid(bareRoomJid);
309 local path = data_getpath(node, host, datastore);
310 local room = nil;
311 local nextRoom = "";
312 local previousRoom = "";
313 local rooms = "";
314 local attributes = nil;
315 local since = "";
316 local to = "";
317 local topic = "";
318
319 path = path:gsub("/[^/]*$", "");
320 attributes = lfs.attributes(path);
321 if muc_hosts ~= nil and muc_hosts[host] and prosody.hosts[host] ~= nil and prosody.hosts[host].muc ~= nil and prosody.hosts[host].muc.rooms[bareRoomJid] ~= nil then
322 local found = 0;
323 for jid, room in pairs(prosody.hosts[host].muc.rooms) do
324 local node = splitJid(jid)
325 if not room._data.hidden and node then
326 if found == 0 then
327 previousRoom = node
328 elseif found == 1 then
329 nextRoom = node
330 found = -1
331 end
332 if jid == bareRoomJid then
333 found = 1
334 end
335
336 rooms = rooms .. html.days.rooms.bit:gsub("###ROOM###", node);
337 end
338 end
339
340 room = prosody.hosts[host].muc.rooms[bareRoomJid];
341 if room._data.hidden then
342 room = nil
343 end
344 end
345 if attributes ~= nil and room ~= nil then
346 local first = 1;
347 local alreadyDoneYears = {};
348 local temptime = {day=0, month=0, year=0};
349 topic = room._data.subject or "(no subject)"
350 if topic:len() > 135 then
351 topic = topic:sub(1, topic:find(" ", 120)) .. " ..."
352 end
353 for folder in lfs.dir(path) do
354 local year, month, day = folder:match("^(%d%d)(%d%d)(%d%d)");
355 if year ~= nil and alreadyDoneYears[year] == nil then
356 temptime.day = tonumber(day)
357 temptime.month = tonumber(month)
358 temptime.year = 2000 + tonumber(year)
359 if first == 1 then
360 to = tostring(os_date("%B %Y", os_time(temptime)))
361 first = 0
362 end
363
364 since = tostring(os_date("%B %Y", os_time(temptime)))
365 module:log("debug", "creating overview for: " .. tostring(since))
366 days = createYear(year, {callback=perDayCallback, path=path, room=node}) .. days;
367 alreadyDoneYears[year] = true;
368 end
369 end
370 end
371
372 if days ~= "" then
373 tmp = html.days.body:gsub("###DAYS_STUFF###", days);
374 tmp = tmp:gsub("###PREVIOUS_ROOM###", previousRoom == "" and node or previousRoom);
375 tmp = tmp:gsub("###NEXT_ROOM###", nextRoom == "" and node or nextRoom);
376 tmp = tmp:gsub("###ROOMS###", rooms);
377 tmp = tmp:gsub("###ROOMTOPIC###", topic);
378 tmp = tmp:gsub("###SINCE###", since);
379 tmp = tmp:gsub("###TO###", to);
380 return tmp:gsub("###JID###", bareRoomJid);
381 end
382 end
383
384 local function parseIqStanza(stanza, timeStuff, nick)
385 local text = nil;
386 local victim = nil;
387 if(stanza.attr.type == "set") then
388 for _,tag in ipairs(stanza) do
389 if tag.tag == "query" then
390 for _,item in ipairs(tag) do
391 if item.tag == "item" and item.attr.nick ~= nil and item.attr.role == 'none' then
392 victim = item.attr.nick;
393 for _,reason in ipairs(item) do
394 if reason.tag == "reason" then
395 text = reason[1];
396 break;
397 end
398 end
399 break;
400 end
401 end
402 break;
403 end
404 end
405 if victim ~= nil then
406 if text ~= nil then
407 text = html.day.reason:gsub("###REASON###", htmlEscape(text));
213 else 408 else
409 text = "";
410 end
411 return html.day.kick:gsub("###TIME_STUFF###", timeStuff):gsub("###VICTIM###", victim):gsub("###REASON_STUFF###", text);
412 end
413 end
414 return;
415 end
416
417 local function parsePresenceStanza(stanza, timeStuff, nick)
418 local ret = "";
419 local showJoin = "block"
420
421 if config and not config.showJoin then
422 showJoin = "none";
423 end
424
425 if stanza.attr.type == nil then
426 local showStatus = "block"
427 if config and not config.showStatus then
428 showStatus = "none";
429 end
430 local show, status = nil, "";
431 local alreadyJoined = false;
432 for _, tag in ipairs(stanza) do
433 if tag.tag == "alreadyJoined" then
434 alreadyJoined = true;
435 elseif tag.tag == "show" then
436 show = tag[1];
437 elseif tag.tag == "status" and tag[1] ~= nil then
438 status = tag[1];
439 end
440 end
441 if alreadyJoined == true then
442 if show == nil then
443 show = "online";
444 end
445 ret = html.day.presence.statusChange:gsub("###TIME_STUFF###", timeStuff);
446 if status ~= "" then
447 status = html.day.presence.statusText:gsub("###STATUS###", htmlEscape(status));
448 end
449 ret = ret:gsub("###SHOW###", show):gsub("###NICK###", nick):gsub("###SHOWHIDE###", showStatus):gsub("###STATUS_STUFF###", status);
450 else
451 ret = html.day.presence.join:gsub("###TIME_STUFF###", timeStuff):gsub("###SHOWHIDE###", showJoin):gsub("###NICK###", nick);
452 end
453 elseif stanza.attr.type ~= nil and stanza.attr.type == "unavailable" then
454
455 ret = html.day.presence.leave:gsub("###TIME_STUFF###", timeStuff):gsub("###SHOWHIDE###", showJoin):gsub("###NICK###", nick);
456 end
457 return ret;
458 end
459
460 local function parseMessageStanza(stanza, timeStuff, nick)
461 local body, title, ret = nil, nil, "";
462
463 for _,tag in ipairs(stanza) do
464 if tag.tag == "body" then
465 body = tag[1];
466 if nick ~= nil then
214 break; 467 break;
215 end 468 end
216 end 469 elseif tag.tag == "nick" and nick == nil then
217 end 470 nick = htmlEscape(tag[1]);
218 if i < days + 1 then 471 if body ~= nil or title ~= nil then
219 local tmp = tostring("<span style='color:#DDDDDD'>"..tostring(i).."</span>"); 472 break;
220 if dayCallback ~= nil and dayCallback.callback ~= nil then 473 end
221 tmp = dayCallback.callback(dayCallback.path, i, month, year, dayCallback.room, dayCallback.webPath); 474 elseif tag.tag == "subject" then
222 end 475 title = tag[1];
223 if tmp == nil then 476 if nick ~= nil then
224 tmp = tostring("<span style='color:#DDDDDD'>"..tostring(i).."</span>"); 477 break;
225 else 478 end
226 logAvailableForMinimumOneDay = true; 479 end
227 end 480 end
228 htmlStr = htmlStr .. html.month.day:gsub("###DAY###", tmp) .. "\n"; 481 if nick ~= nil and body ~= nil then
229 end 482 body = htmlEscape(body);
230 483 local me = body:find("^/me");
231 if i >= days then 484 local template = "";
232 break; 485 if not me then
233 end 486 template = html.day.message;
234 487 else
235 if weekDay == 7 then 488 template = html.day.messageMe;
236 weekDay = 0; 489 body = body:gsub("^/me ", "");
237 weeks = weeks + 1; 490 end
238 htmlStr = htmlStr .. "</tr>\n"; 491 ret = template:gsub("###TIME_STUFF###", timeStuff):gsub("###NICK###", nick):gsub("###MSG###", body);
239 end 492 elseif nick ~= nil and title ~= nil then
240 end 493 title = htmlEscape(title);
241 494 ret = html.day.titleChange:gsub("###TIME_STUFF###", timeStuff):gsub("###NICK###", nick):gsub("###TITLE###", title);
242 if weekDay + 1 < 8 or weeks < 6 then 495 end
243 weekDay = weekDay + 1; 496 return ret;
244 if weekDay > 7 then 497 end
245 weekDay = 1; 498
246 end 499 local function incrementDay(bare_day)
247 if weekDay == 1 then 500 local year, month, day = bare_day:match("^(%d%d)(%d%d)(%d%d)");
248 weeks = weeks + 1; 501 local leapyear = false;
249 end 502 module:log("debug", tostring(day).."/"..tostring(month).."/"..tostring(year))
250 for y = weeks, 6 do 503
251 if weekDay == 1 then 504 day = tonumber(day);
252 htmlStr = htmlStr .. "<tr>\n"; 505 month = tonumber(month);
253 end 506 year = tonumber(year);
254 for i = weekDay, 7 do 507
255 htmlStr = htmlStr .. html.month.emptyDay .. "\n"; 508 if year%4 == 0 and year%100 == 0 then
256 end 509 if year%400 == 0 then
257 weekDay = 1 510 leapyear = true;
258 htmlStr = htmlStr .. "</tr>\n"; 511 else
259 end 512 leapyear = false; -- turn of the century but not a leapyear
260 end 513 end
261 htmlStr = htmlStr .. html.month.footer; 514 elseif year%4 == 0 then
262 if logAvailableForMinimumOneDay then 515 leapyear = true;
263 return htmlStr; 516 end
264 end 517
265 end 518 if (month == 2 and leapyear and day + 1 > 29) or
266 519 (month == 2 and not leapyear and day + 1 > 28) or
267 local function createYear(year, dayCallback) 520 (month < 8 and month%2 == 1 and day + 1 > 31) or
268 local year = year; 521 (month < 8 and month%2 == 0 and day + 1 > 30) or
269 local tmp; 522 (month >= 8 and month%2 == 0 and day + 1 > 31) or
270 if tonumber(year) <= 99 then 523 (month >= 8 and month%2 == 1 and day + 1 > 30)
271 year = year + 2000; 524 then
272 end 525 if month + 1 > 12 then
273 local htmlStr = ""; 526 year = year + 1;
274 for i=1, 12 do 527 month = 1;
275 tmp = createMonth(i, year, dayCallback); 528 day = 1;
276 if tmp then 529 else
277 htmlStr = htmlStr .. "<div style='float: left; padding: 5px;'>\n" .. tmp .. "</div>\n"; 530 month = month + 1;
278 end 531 day = 1;
279 end 532 end
280 if htmlStr ~= "" then 533 else
281 return "<div name='yearDiv' style='padding: 40px; text-align: center;'>" .. html.year.title:gsub("###YEAR###", tostring(year)) .. htmlStr .. "</div><br style='clear:both;'/> \n"; 534 day = day + 1;
282 end 535 end
283 return ""; 536 return strformat("%.02d%.02d%.02d", year, month, day);
284 end 537 end
285 538
286 local function perDayCallback(path, day, month, year, room, webPath) 539 local function findNextDay(bareRoomJid, bare_day)
287 local webPath = webPath or "" 540 local node, host, resource = splitJid(bareRoomJid);
288 local year = year; 541 local day = incrementDay(bare_day);
289 if year > 2000 then 542 local max_trys = 7;
290 year = year - 2000; 543
291 end 544 module:log("debug", day);
292 local bareDay = str_format("%.02d%.02d%.02d", year, month, day); 545 while(not checkDatastorePathExists(node, host, day, false)) do
293 room = urlencode(room); 546 max_trys = max_trys - 1;
294 local attributes, err = lfs.attributes(path.."/"..bareDay.."/"..room..".dat") 547 if max_trys == 0 then
295 if attributes ~= nil and attributes.mode == "file" then 548 break;
296 local s = html.days.bit; 549 end
297 s = s:gsub("###BARE_DAY###", webPath .. bareDay); 550 day = incrementDay(day);
298 s = s:gsub("###DAY###", day); 551 end
299 return s; 552 if max_trys == 0 then
300 end 553 return nil;
301 return; 554 else
302 end 555 return day;
303 556 end
304 local function generateDayListSiteContentByRoom(bareRoomJid) 557 end
305 local days = ""; 558
306 local arrDays = {}; 559 local function decrementDay(bare_day)
307 local tmp; 560 local year, month, day = bare_day:match("^(%d%d)(%d%d)(%d%d)");
308 local node, host, resource = splitJid(bareRoomJid); 561 local leapyear = false;
309 local path = data_getpath(node, host, datastore); 562 module:log("debug", tostring(day).."/"..tostring(month).."/"..tostring(year))
310 local room = nil; 563
311 local nextRoom = ""; 564 day = tonumber(day);
312 local previousRoom = ""; 565 month = tonumber(month);
313 local rooms = ""; 566 year = tonumber(year);
314 local attributes = nil; 567
315 local since = ""; 568 if year%4 == 0 and year%100 == 0 then
316 local to = ""; 569 if year%400 == 0 then
317 local topic = ""; 570 leapyear = true;
318 571 else
319 path = path:gsub("/[^/]*$", ""); 572 leapyear = false; -- turn of the century but not a leapyear
320 attributes = lfs.attributes(path); 573 end
321 if muc_hosts ~= nil and muc_hosts[host] and prosody.hosts[host] ~= nil and prosody.hosts[host].muc ~= nil and prosody.hosts[host].muc.rooms[bareRoomJid] ~= nil then 574 elseif year%4 == 0 then
322 local found = 0; 575 leapyear = true;
323 for jid, room in pairs(prosody.hosts[host].muc.rooms) do 576 end
324 local node = splitJid(jid) 577
325 if not room._data.hidden and node then 578 if day - 1 == 0 then
326 if found == 0 then 579 if month - 1 == 0 then
327 previousRoom = node 580 year = year - 1;
328 elseif found == 1 then 581 month = 12;
329 nextRoom = node 582 day = 31;
330 found = -1 583 else
331 end 584 month = month - 1;
332 if jid == bareRoomJid then 585 if (month == 2 and leapyear) then day = 29
333 found = 1 586 elseif (month == 2 and not leapyear) then day = 28
334 end 587 elseif (month < 8 and month%2 == 1) or (month >= 8 and month%2 == 0) then day = 31
335 588 else day = 30
336 rooms = rooms .. html.days.rooms.bit:gsub("###ROOM###", node); 589 end
337 end 590 end
338 end 591 else
339 592 day = day - 1;
340 room = prosody.hosts[host].muc.rooms[bareRoomJid]; 593 end
341 if room._data.hidden then 594 return strformat("%.02d%.02d%.02d", year, month, day);
342 room = nil 595 end
343 end 596
344 end 597 local function findPreviousDay(bareRoomJid, bare_day)
345 if attributes ~= nil and room ~= nil then 598 local node, host, resource = splitJid(bareRoomJid);
346 local first = 1; 599 local day = decrementDay(bare_day);
347 local alreadyDoneYears = {}; 600 local max_trys = 7;
348 local temptime = {day=0, month=0, year=0}; 601 module:log("debug", day);
349 topic = room._data.subject or "(no subject)" 602 while(not checkDatastorePathExists(node, host, day, false)) do
350 if topic:len() > 135 then 603 max_trys = max_trys - 1;
351 topic = topic:sub(1, topic:find(" ", 120)) .. " ..." 604 if max_trys == 0 then
352 end 605 break;
353 for folder in lfs.dir(path) do 606 end
354 local year, month, day = folder:match("^(%d%d)(%d%d)(%d%d)"); 607 day = decrementDay(day);
355 if year ~= nil and alreadyDoneYears[year] == nil then 608 end
356 temptime.day = tonumber(day) 609 if max_trys == 0 then
357 temptime.month = tonumber(month) 610 return nil;
358 temptime.year = 2000 + tonumber(year) 611 else
359 if first == 1 then 612 return day;
360 to = tostring(os_date("%B %Y", os_time(temptime))) 613 end
361 first = 0 614 end
362 end 615
363 616 local function parseDay(bareRoomJid, roomSubject, bare_day)
364 since = tostring(os_date("%B %Y", os_time(temptime))) 617 local ret = "";
365 module:log("debug", "creating overview for: " .. tostring(since)) 618 local year;
366 days = createYear(year, {callback=perDayCallback, path=path, room=node}) .. days; 619 local month;
367 alreadyDoneYears[year] = true; 620 local day;
368 end 621 local tmp;
369 end 622 local node, host, resource = splitJid(bareRoomJid);
370 end 623 local year, month, day = bare_day:match("^(%d%d)(%d%d)(%d%d)");
371 624 local previousDay = findPreviousDay(bareRoomJid, bare_day);
372 if days ~= "" then 625 local nextDay = findNextDay(bareRoomJid, bare_day);
373 tmp = html.days.body:gsub("###DAYS_STUFF###", days); 626 local temptime = {day=0, month=0, year=0};
374 tmp = tmp:gsub("###PREVIOUS_ROOM###", previousRoom == "" and node or previousRoom); 627 local path = data_getpath(node, host, datastore);
375 tmp = tmp:gsub("###NEXT_ROOM###", nextRoom == "" and node or nextRoom); 628 path = path:gsub("/[^/]*$", "");
376 tmp = tmp:gsub("###ROOMS###", rooms); 629 local calendar = ""
377 tmp = tmp:gsub("###ROOMTOPIC###", topic); 630
378 tmp = tmp:gsub("###SINCE###", since); 631 if tonumber(year) <= 99 then
379 tmp = tmp:gsub("###TO###", to); 632 year = year + 2000;
380 return tmp:gsub("###JID###", bareRoomJid); 633 end
381 end 634
382 end 635 temptime.day = tonumber(day)
383 636 temptime.month = tonumber(month)
384 local function parseIqStanza(stanza, timeStuff, nick) 637 temptime.year = tonumber(year)
385 local text = nil; 638 calendar = createMonth(temptime.month, temptime.year, {callback=perDayCallback, path=path, room=node, webPath="../"}) or ""
386 local victim = nil; 639
387 if(stanza.attr.type == "set") then 640 if bare_day ~= nil then
388 for _,tag in ipairs(stanza) do 641 local data = data_load(node, host, datastore .. "/" .. bare_day);
389 if tag.tag == "query" then 642 if data ~= nil then
390 for _,item in ipairs(tag) do 643 for i=1, #data, 1 do
391 if item.tag == "item" and item.attr.nick ~= nil and tostring(item.attr.role) == 'none' then 644 local stanza = lom.parse(data[i]);
392 victim = item.attr.nick; 645 if stanza ~= nil and stanza.attr ~= nil and stanza.attr.time ~= nil then
393 for _,reason in ipairs(item) do 646 local timeStuff = html.day.time:gsub("###TIME###", stanza.attr.time):gsub("###UTC###", stanza.attr.utc or stanza.attr.time);
394 if reason.tag == "reason" then 647 if stanza[1] ~= nil then
395 text = reason[1]; 648 local nick;
396 break; 649 local tmp;
397 end 650
398 end 651 -- grep nick from "from" resource
399 break; 652 if stanza[1].attr.from ~= nil then -- presence and messages
400 end 653 nick = htmlEscape(stanza[1].attr.from:match("/(.+)$"));
401 end 654 elseif stanza[1].attr.to ~= nil then -- iq
402 break; 655 nick = htmlEscape(stanza[1].attr.to:match("/(.+)$"));
403 end 656 end
404 end 657
405 if victim ~= nil then 658 if stanza[1].tag == "presence" and nick ~= nil then
406 if text ~= nil then 659 tmp = parsePresenceStanza(stanza[1], timeStuff, nick);
407 text = html.day.reason:gsub("###REASON###", htmlEscape(text)); 660 elseif stanza[1].tag == "message" then
408 else 661 tmp = parseMessageStanza(stanza[1], timeStuff, nick);
409 text = ""; 662 elseif stanza[1].tag == "iq" then
410 end 663 tmp = parseIqStanza(stanza[1], timeStuff, nick);
411 return html.day.kick:gsub("###TIME_STUFF###", timeStuff):gsub("###VICTIM###", victim):gsub("###REASON_STUFF###", text); 664 else
412 end 665 module:log("info", "unknown stanza subtag in log found. room: %s; day: %s", bareRoomJid, year .. "/" .. month .. "/" .. day);
413 end 666 end
414 return; 667 if tmp ~= nil then
415 end 668 ret = ret .. tmp
416 669 tmp = nil;
417 local function parsePresenceStanza(stanza, timeStuff, nick) 670 end
418 local ret = ""; 671 end
419 local showJoin = "block" 672 end
420 673 end
421 if config and not config.showJoin then 674 end
422 showJoin = "none"; 675 if ret ~= "" then
423 end 676 if nextDay then
424 677 nextDay = html.day.dayLink:gsub("###DAY###", nextDay):gsub("###TEXT###", "&gt;")
425 if stanza.attr.type == nil then 678 end
426 local showStatus = "block" 679 if previousDay then
427 if config and not config.showStatus then 680 previousDay = html.day.dayLink:gsub("###DAY###", previousDay):gsub("###TEXT###", "&lt;");
428 showStatus = "none"; 681 end
429 end 682 ret = ret:gsub("%%", "%%%%");
430 local show, status = nil, ""; 683 tmp = html.day.body:gsub("###DAY_STUFF###", ret):gsub("###JID###", bareRoomJid);
431 local alreadyJoined = false; 684 tmp = tmp:gsub("###CALENDAR###", calendar);
432 for _, tag in ipairs(stanza) do 685 tmp = tmp:gsub("###DATE###", tostring(os_date("%A, %B %d, %Y", os_time(temptime))));
433 if tag.tag == "alreadyJoined" then 686 tmp = tmp:gsub("###TITLE_STUFF###", html.day.title:gsub("###TITLE###", roomSubject));
434 alreadyJoined = true; 687 tmp = tmp:gsub("###STATUS_CHECKED###", config.showStatus and "checked='checked'" or "");
435 elseif tag.tag == "show" then 688 tmp = tmp:gsub("###JOIN_CHECKED###", config.showJoin and "checked='checked'" or "");
436 show = tag[1]; 689 tmp = tmp:gsub("###NEXT_LINK###", nextDay or "");
437 elseif tag.tag == "status" and tag[1] ~= nil then 690 tmp = tmp:gsub("###PREVIOUS_LINK###", previousDay or "");
438 status = tag[1]; 691
439 end 692 return tmp;
440 end 693 end
441 if alreadyJoined == true then 694 end
442 if show == nil then 695 end
443 show = "online"; 696
444 end 697 function handle_request(method, body, request)
445 ret = html.day.presence.statusChange:gsub("###TIME_STUFF###", timeStuff); 698 local node, host, day = splitUrl(request.url.path);
446 if status ~= "" then 699
447 status = html.day.presence.statusText:gsub("###STATUS###", htmlEscape(status)); 700 node = urldecode(node);
448 end 701
449 ret = ret:gsub("###SHOW###", show):gsub("###NICK###", nick):gsub("###SHOWHIDE###", showStatus):gsub("###STATUS_STUFF###", status); 702 if muc_hosts ~= nil and html.doc ~= nil then
450 else 703 if node ~= nil and host ~= nil then
451 ret = html.day.presence.join:gsub("###TIME_STUFF###", timeStuff):gsub("###SHOWHIDE###", showJoin):gsub("###NICK###", nick); 704 local bare = node .. "@" .. host;
452 end 705 if prosody.hosts[host] ~= nil and prosody.hosts[host].muc ~= nil then
453 elseif stanza.attr.type ~= nil and stanza.attr.type == "unavailable" then 706 if prosody.hosts[host].muc.rooms[bare] ~= nil then
454 707 local room = prosody.hosts[host].muc.rooms[bare];
455 ret = html.day.presence.leave:gsub("###TIME_STUFF###", timeStuff):gsub("###SHOWHIDE###", showJoin):gsub("###NICK###", nick); 708 if day == nil then
456 end 709 return createDoc(generateDayListSiteContentByRoom(bare));
457 return ret; 710 else
458 end 711 local subject = ""
459 712 if room._data ~= nil and room._data.subject ~= nil then
460 local function parseMessageStanza(stanza, timeStuff, nick) 713 subject = room._data.subject;
461 local body, title, ret = nil, nil, ""; 714 end
462 715 return createDoc(parseDay(bare, subject, day));
463 for _,tag in ipairs(stanza) do 716 end
464 if tag.tag == "body" then 717 else
465 body = tag[1]; 718 return createDoc(generateRoomListSiteContent(host));
466 if nick ~= nil then 719 end
467 break; 720 else
468 end 721 return createDoc(generateComponentListSiteContent());
469 elseif tag.tag == "nick" and nick == nil then 722 end
470 nick = htmlEscape(tag[1]); 723 elseif host ~= nil then
471 if body ~= nil or title ~= nil then 724 return createDoc(generateRoomListSiteContent(host));
472 break; 725 else
473 end 726 return createDoc(generateComponentListSiteContent());
474 elseif tag.tag == "subject" then 727 end
475 title = tag[1]; 728 end
476 if nick ~= nil then 729 return;
477 break; 730 end
478 end 731
479 end 732 -- Compatibility: Lua-5.1
480 end 733 function split(str, pat)
481 if nick ~= nil and body ~= nil then 734 local t = {} -- NOTE: use {n = 0} in Lua-5.0
482 body = htmlEscape(body); 735 local fpat = "(.-)" .. pat
483 local me = body:find("^/me"); 736 local last_end = 1
484 local template = ""; 737 local s, e, cap = str:find(fpat, 1)
485 if not me then 738 while s do
486 template = html.day.message; 739 if s ~= 1 or cap ~= "" then
487 else 740 table.insert(t,cap)
488 template = html.day.messageMe; 741 end
489 body = body:gsub("^/me ", ""); 742 last_end = e+1
490 end 743 s, e, cap = str:find(fpat, last_end)
491 ret = template:gsub("###TIME_STUFF###", timeStuff):gsub("###NICK###", nick):gsub("###MSG###", body); 744 end
492 elseif nick ~= nil and title ~= nil then 745 if last_end <= #str then
493 title = htmlEscape(title); 746 cap = str:sub(last_end)
494 ret = html.day.titleChange:gsub("###TIME_STUFF###", timeStuff):gsub("###NICK###", nick):gsub("###TITLE###", title); 747 table.insert(t, cap)
495 end 748 end
496 return ret; 749 return t
497 end 750 end
498 751
499 local function incrementDay(bare_day) 752 local function assign(arr, content)
500 local year, month, day = bare_day:match("^(%d%d)(%d%d)(%d%d)"); 753 local tmp = html;
501 local leapyear = false; 754 local idx = nil;
502 module:log("debug", tostring(day).."/"..tostring(month).."/"..tostring(year)) 755 for _,i in ipairs(arr) do
503 756 if idx ~= nil then
504 day = tonumber(day); 757 if tmp[idx] == nil then
505 month = tonumber(month); 758 tmp[idx] = {};
506 year = tonumber(year); 759 end
507 760 tmp = tmp[idx];
508 if year%4 == 0 and year%100 == 0 then 761 end
509 if year%400 == 0 then 762 idx = i;
510 leapyear = true; 763 end
511 else 764 tmp[idx] = content;
512 leapyear = false; -- turn of the century but not a leapyear 765 end
513 end 766
514 elseif year%4 == 0 then 767 local function readFile(filepath)
515 leapyear = true; 768 local f = assert(io_open(filepath, "r"));
516 end 769 local t = f:read("*all");
517 770 f:close()
518 if (month == 2 and leapyear and day + 1 > 29) or 771 return t;
519 (month == 2 and not leapyear and day + 1 > 28) or 772 end
520 (month < 8 and month%2 == 1 and day + 1 > 31) or 773
521 (month < 8 and month%2 == 0 and day + 1 > 30) or 774 local function loadTheme(path)
522 (month >= 8 and month%2 == 0 and day + 1 > 31) or 775 for file in lfs.dir(path) do
523 (month >= 8 and month%2 == 1 and day + 1 > 30) 776 if file ~= "." and file ~= ".." then
524 then 777 module:log("debug", "opening theme file: " .. file);
525 if month + 1 > 12 then 778 local tmp = split(file:gsub("\.html$", ""), "_");
526 year = year + 1; 779 local content = readFile(path .. "/" .. file);
527 month = 1; 780 assign(tmp, content);
528 day = 1; 781 end
529 else 782 end
530 month = month + 1; 783 return true;
531 day = 1; 784 end
532 end 785
533 else 786 function module.load()
534 day = day + 1; 787 config = config_get("*", "core", "muc_log_http") or {};
535 end 788 if config.showStatus == nil then
536 return strformat("%.02d%.02d%.02d", year, month, day); 789 config.showStatus = true;
537 end 790 end
538 791 if config.showJoin == nil then
539 local function findNextDay(bareRoomJid, bare_day) 792 config.showJoin = true;
540 local node, host, resource = splitJid(bareRoomJid); 793 end
541 local day = incrementDay(bare_day); 794
542 local max_trys = 7; 795 theme = config.theme or "prosody";
543 796 local themePath = themesParent .. "/" .. tostring(theme);
544 module:log("debug", day); 797 local attributes, err = lfs.attributes(themePath);
545 while(not checkDatastorePathExists(node, host, day, false)) do 798 if attributes == nil or attributes.mode ~= "directory" then
546 max_trys = max_trys - 1; 799 module:log("error", "Theme folder of theme \"".. tostring(theme) .. "\" isn't existing. expected Path: " .. themePath);
547 if max_trys == 0 then 800 return false;
548 break; 801 end
549 end 802
550 day = incrementDay(day); 803 -- module:log("debug", (require "util.serialization").serialize(html));
551 end 804 if(not loadTheme(themePath)) then
552 if max_trys == 0 then 805 module:log("error", "Theme \"".. tostring(theme) .. "\" is missing something.");
553 return nil; 806 return false;
554 else 807 end
555 return day; 808 -- module:log("debug", (require "util.serialization").serialize(html));
556 end 809
557 end 810 httpserver.new_from_config({ config.http_port or true }, handle_request, { base = urlBase, ssl = false, port = 5290 });
558 811
559 local function decrementDay(bare_day) 812 for jid, host in pairs(prosody.hosts) do
560 local year, month, day = bare_day:match("^(%d%d)(%d%d)(%d%d)"); 813 if host.muc then
561 local leapyear = false; 814 local enabledModules = config_get(jid, "core", "modules_enabled");
562 module:log("debug", tostring(day).."/"..tostring(month).."/"..tostring(year)) 815 if enabledModules then
563 816 for _,mod in ipairs(enabledModules) do
564 day = tonumber(day); 817 if(mod == "muc_log") then
565 month = tonumber(month); 818 module:log("debug", "component: %s", tostring(jid));
566 year = tonumber(year); 819 muc_hosts[jid] = true;
567 820 break;
568 if year%4 == 0 and year%100 == 0 then 821 end
569 if year%400 == 0 then 822 end
570 leapyear = true; 823 end
571 else 824 end
572 leapyear = false; -- turn of the century but not a leapyear 825 end
573 end 826 module:log("debug", "loaded mod_muc_log_http");
574 elseif year%4 == 0 then 827 end
575 leapyear = true; 828
576 end 829 function module.unload()
577 830 muc_hosts = nil;
578 if day - 1 == 0 then 831 module:log("debug", "unloaded mod_muc_log_http");
579 if month - 1 == 0 then 832 end
580 year = year - 1; 833
581 month = 12; 834 module:hook("component-activated", function(component, config)
582 day = 31; 835 if config.core and config.core.modules_enabled then
583 else 836 for _,mod in ipairs(config.core.modules_enabled) do
584 month = month - 1; 837 if(mod == "muc_log") then
585 if (month == 2 and leapyear) then day = 29 838 module:log("debug", "component: %s", tostring(component));
586 elseif (month == 2 and not leapyear) then day = 28 839 muc_hosts[component] = true;
587 elseif (month < 8 and month%2 == 1) or (month >= 8 and month%2 == 0) then day = 31 840 break;
588 else day = 30 841 end
589 end 842 end
590 end 843 end
591 else 844 end);
592 day = day - 1;
593 end
594 return strformat("%.02d%.02d%.02d", year, month, day);
595 end
596
597 local function findPreviousDay(bareRoomJid, bare_day)
598 local node, host, resource = splitJid(bareRoomJid);
599 local day = decrementDay(bare_day);
600 local max_trys = 7;
601 module:log("debug", day);
602 while(not checkDatastorePathExists(node, host, day, false)) do
603 max_trys = max_trys - 1;
604 if max_trys == 0 then
605 break;
606 end
607 day = decrementDay(day);
608 end
609 if max_trys == 0 then
610 return nil;
611 else
612 return day;
613 end
614 end
615
616 local function parseDay(bareRoomJid, roomSubject, bare_day)
617 local ret = "";
618 local year;
619 local month;
620 local day;
621 local tmp;
622 local node, host, resource = splitJid(bareRoomJid);
623 local year, month, day = bare_day:match("^(%d%d)(%d%d)(%d%d)");
624 local previousDay = findPreviousDay(bareRoomJid, bare_day);
625 local nextDay = findNextDay(bareRoomJid, bare_day);
626 local temptime = {day=0, month=0, year=0};
627 local path = data_getpath(node, host, datastore);
628 path = path:gsub("/[^/]*$", "");
629 local calendar = ""
630
631 if tonumber(year) <= 99 then
632 year = year + 2000;
633 end
634
635 temptime.day = tonumber(day)
636 temptime.month = tonumber(month)
637 temptime.year = tonumber(year)
638 calendar = createMonth(temptime.month, temptime.year, {callback=perDayCallback, path=path, room=node, webPath="../"}) or ""
639
640 if bare_day ~= nil then
641 local data = data_load(node, host, datastore .. "/" .. bare_day);
642 if data ~= nil then
643 for i=1, #data, 1 do
644 local stanza = lom.parse(data[i]);
645 if stanza ~= nil and stanza.attr ~= nil and stanza.attr.time ~= nil then
646 local timeStuff = html.day.time:gsub("###TIME###", stanza.attr.time):gsub("###UTC###", stanza.attr.utc or stanza.attr.time);
647 if stanza[1] ~= nil then
648 local nick;
649 local tmp;
650
651 -- grep nick from "from" resource
652 if stanza[1].attr.from ~= nil then -- presence and messages
653 nick = htmlEscape(stanza[1].attr.from:match("/(.+)$"));
654 elseif stanza[1].attr.to ~= nil then -- iq
655 nick = htmlEscape(stanza[1].attr.to:match("/(.+)$"));
656 end
657
658 if stanza[1].tag == "presence" and nick ~= nil then
659 tmp = parsePresenceStanza(stanza[1], timeStuff, nick);
660 elseif stanza[1].tag == "message" then
661 tmp = parseMessageStanza(stanza[1], timeStuff, nick);
662 elseif stanza[1].tag == "iq" then
663 tmp = parseIqStanza(stanza[1], timeStuff, nick);
664 else
665 module:log("info", "unknown stanza subtag in log found. room: %s; day: %s", bareRoomJid, year .. "/" .. month .. "/" .. day);
666 end
667 if tmp ~= nil then
668 ret = ret .. tmp
669 tmp = nil;
670 end
671 end
672 end
673 end
674 end
675 if ret ~= "" then
676 if nextDay then
677 nextDay = html.day.dayLink:gsub("###DAY###", nextDay):gsub("###TEXT###", "&gt;")
678 end
679 if previousDay then
680 previousDay = html.day.dayLink:gsub("###DAY###", previousDay):gsub("###TEXT###", "&lt;");
681 end
682 ret = ret:gsub("%%", "%%%%");
683 tmp = html.day.body:gsub("###DAY_STUFF###", ret):gsub("###JID###", bareRoomJid);
684 tmp = tmp:gsub("###CALENDAR###", calendar);
685 tmp = tmp:gsub("###DATE###", tostring(os_date("%A, %B %d, %Y", os_time(temptime))));
686 tmp = tmp:gsub("###TITLE_STUFF###", html.day.title:gsub("###TITLE###", roomSubject));
687 tmp = tmp:gsub("###STATUS_CHECKED###", config.showStatus and "checked='checked'" or "");
688 tmp = tmp:gsub("###JOIN_CHECKED###", config.showJoin and "checked='checked'" or "");
689 tmp = tmp:gsub("###NEXT_LINK###", nextDay or "");
690 tmp = tmp:gsub("###PREVIOUS_LINK###", previousDay or "");
691
692 return tmp;
693 end
694 end
695 end
696
697 function handle_request(method, body, request)
698 local node, host, day = splitUrl(request.url.path);
699
700 node = urldecode(node);
701
702 if muc_hosts ~= nil and html.doc ~= nil then
703 if node ~= nil and host ~= nil then
704 local bare = node .. "@" .. host;
705 if prosody.hosts[host] ~= nil and prosody.hosts[host].muc ~= nil then
706 if prosody.hosts[host].muc.rooms[bare] ~= nil then
707 local room = prosody.hosts[host].muc.rooms[bare];
708 if day == nil then
709 return createDoc(generateDayListSiteContentByRoom(bare));
710 else
711 local subject = ""
712 if room._data ~= nil and room._data.subject ~= nil then
713 subject = room._data.subject;
714 end
715 return createDoc(parseDay(bare, subject, day));
716 end
717 else
718 return createDoc(generateRoomListSiteContent(host));
719 end
720 else
721 return createDoc(generateComponentListSiteContent());
722 end
723 elseif host ~= nil then
724 return createDoc(generateRoomListSiteContent(host));
725 else
726 return createDoc(generateComponentListSiteContent());
727 end
728 end
729 return;
730 end
731
732 -- Compatibility: Lua-5.1
733 function split(str, pat)
734 local t = {} -- NOTE: use {n = 0} in Lua-5.0
735 local fpat = "(.-)" .. pat
736 local last_end = 1
737 local s, e, cap = str:find(fpat, 1)
738 while s do
739 if s ~= 1 or cap ~= "" then
740 table.insert(t,cap)
741 end
742 last_end = e+1
743 s, e, cap = str:find(fpat, last_end)
744 end
745 if last_end <= #str then
746 cap = str:sub(last_end)
747 table.insert(t, cap)
748 end
749 return t
750 end
751
752 local function assign(arr, content)
753 local tmp = html;
754 local idx = nil;
755 for _,i in ipairs(arr) do
756 if idx ~= nil then
757 if tmp[idx] == nil then
758 tmp[idx] = {};
759 end
760 tmp = tmp[idx];
761 end
762 idx = i;
763 end
764 tmp[idx] = content;
765 end
766
767 local function readFile(filepath)
768 local f = assert(io_open(filepath, "r"));
769 local t = f:read("*all");
770 f:close()
771 return t;
772 end
773
774 local function loadTheme(path)
775 for file in lfs.dir(path) do
776 if file ~= "." and file ~= ".." then
777 module:log("debug", "opening theme file: " .. file);
778 local tmp = split(file:gsub("\.html$", ""), "_");
779 local content = readFile(path .. "/" .. file);
780 assign(tmp, content);
781 end
782 end
783 return true;
784 end
785
786 function module.load()
787 config = config_get("*", "core", "muc_log_http") or {};
788 if config.showStatus == nil then
789 config.showStatus = true;
790 end
791 if config.showJoin == nil then
792 config.showJoin = true;
793 end
794
795 theme = config.theme or "prosody";
796 local themePath = themesParent .. "/" .. tostring(theme);
797 local attributes, err = lfs.attributes(themePath);
798 if attributes == nil or attributes.mode ~= "directory" then
799 module:log("error", "Theme folder of theme \"".. tostring(theme) .. "\" isn't existing. expected Path: " .. themePath);
800 return false;
801 end
802
803 -- module:log("debug", (require "util.serialization").serialize(html));
804 if(not loadTheme(themePath)) then
805 module:log("error", "Theme \"".. tostring(theme) .. "\" is missing something.");
806 return false;
807 end
808 -- module:log("debug", (require "util.serialization").serialize(html));
809
810 httpserver.new_from_config({ config.http_port or true }, handle_request, { base = urlBase, ssl = false, port = 5290 });
811
812 for jid, host in pairs(prosody.hosts) do
813 if host.muc then
814 local enabledModules = config_get(jid, "core", "modules_enabled");
815 if enabledModules then
816 for _,mod in ipairs(enabledModules) do
817 if(mod == "muc_log") then
818 module:log("debug", "component: %s", tostring(jid));
819 muc_hosts[jid] = true;
820 break;
821 end
822 end
823 end
824 end
825 end
826 module:log("debug", "loaded mod_muc_log_http");
827 end
828
829 function module.unload()
830 muc_hosts = nil;
831 module:log("debug", "unloaded mod_muc_log_http");
832 end
833
834 module:hook("component-activated", function(component, config)
835 if config.core and config.core.modules_enabled then
836 for _,mod in ipairs(config.core.modules_enabled) do
837 if(mod == "muc_log") then
838 module:log("debug", "component: %s", tostring(component));
839 muc_hosts[component] = true;
840 break;
841 end
842 end
843 end
844 end);