Mercurial > prosody-modules
comparison mod_muc_log_http/muc_log_http/mod_muc_log_http.lua @ 353:8ef36af30181
merge with upstream
author | Phil Stewart <phil.stewart@lichp.co.uk> |
---|---|
date | Sun, 03 Apr 2011 22:49:36 +0100 |
parents | 03e1dc036a28 |
children | 5ef71af77ae2 |
comparison
equal
deleted
inserted
replaced
347:cd838419a85d | 353:8ef36af30181 |
---|---|
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("<", "<"); | 89 t = t:gsub("<", "<"); |
90 t = t:gsub(">", ">"); | 90 t = t:gsub(">", ">"); |
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###", ">") |
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###", "<"); |
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###", ">") | |
678 end | |
679 if previousDay then | |
680 previousDay = html.day.dayLink:gsub("###DAY###", previousDay):gsub("###TEXT###", "<"); | |
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); |