Mercurial > prosody-modules
comparison mod_muc_log_http/muc_log_http/mod_muc_log_http.lua @ 1032:b69e5d63a4fe
mod_muc_log, mod_muc_log_http: backport changes from Metronome.
author | Marco Cirillo <maranda@lightwitch.org> |
---|---|
date | Sat, 01 Jun 2013 23:37:39 +0200 |
parents | 043189eb41bc |
children | c6d4778bc0e8 |
comparison
equal
deleted
inserted
replaced
1031:6b34cc81e15d | 1032:b69e5d63a4fe |
---|---|
1 module:depends("http"); | 1 module:depends("http"); |
2 | 2 |
3 local prosody = prosody; | 3 local prosody = prosody; |
4 local hosts = prosody.hosts; | 4 local hosts = prosody.hosts; |
5 local my_host = module:get_host(); | 5 local my_host = module:get_host(); |
6 local tabSort = table.sort; | |
7 local strchar = string.char; | 6 local strchar = string.char; |
8 local strformat = string.format; | 7 local strformat = string.format; |
9 local splitJid = require "util.jid".split; | 8 local split_jid = require "util.jid".split; |
10 local config_get = require "core.configmanager".get; | 9 local config_get = require "core.configmanager".get; |
11 local urldecode = require "net.http".urldecode; | 10 local urldecode = require "net.http".urldecode; |
12 local http_event = require "net.http.server".fire_event; | 11 local http_event = require "net.http.server".fire_server_event; |
13 local data_load, data_getpath = datamanager.load, datamanager.getpath; | 12 local data_load, data_getpath = datamanager.load, datamanager.getpath; |
14 local datastore = "muc_log"; | 13 local datastore = "muc_log"; |
15 local urlBase = "muc_log"; | 14 local url_base = "muc_log"; |
16 local config = nil; | 15 local config = nil; |
17 local tostring, tonumber = tostring, tonumber; | 16 local table, tostring, tonumber = table, tostring, tonumber; |
18 local os_date, os_time = os.date, os.time; | 17 local os_date, os_time = os.date, os.time; |
19 local str_format = string.format; | 18 local str_format = string.format; |
20 local io_open = io.open; | 19 local io_open = io.open; |
21 local themesParent = (module.path and module.path:gsub("[/\\][^/\\]*$", "") or (prosody.paths.plugins or "./plugins") .. "/muc_log_http") .. "/themes"; | 20 local themes_parent = (module.path and module.path:gsub("[/\\][^/\\]*$", "") or (prosody.paths.plugins or "./plugins") .. "/muc_log_http") .. "/themes"; |
22 | 21 |
23 local lom = require "lxp.lom"; | 22 local lom = require "lxp.lom"; |
24 local lfs = require "lfs"; | 23 local lfs = require "lfs"; |
25 local html = {}; | 24 local html = {}; |
26 local theme; | 25 local theme; |
32 if lfs.attributes(data_getpath(node, host, datastore .. "/" .. today), "mode") then return true; else return false; end | 31 if lfs.attributes(data_getpath(node, host, datastore .. "/" .. today), "mode") then return true; else return false; end |
33 end | 32 end |
34 | 33 |
35 -- Module Definitions | 34 -- Module Definitions |
36 | 35 |
37 local function htmlEscape(t) | 36 local function html_escape(t) |
38 if t then | 37 if t then |
39 t = t:gsub("<", "<"); | 38 t = t:gsub("<", "<"); |
40 t = t:gsub(">", ">"); | 39 t = t:gsub(">", ">"); |
41 t = t:gsub("(http://[%a%d@%.:/&%?=%-_#%%~]+)", function(h) | 40 t = t:gsub("(http://[%a%d@%.:/&%?=%-_#%%~]+)", function(h) |
42 h = urlunescape(h) | 41 h = urlunescape(h) |
48 t = ""; | 47 t = ""; |
49 end | 48 end |
50 return t; | 49 return t; |
51 end | 50 end |
52 | 51 |
53 function createDoc(body, title) | 52 function create_doc(body, title) |
54 if not body then return "" end | 53 if not body then return "" end |
55 body = body:gsub("%%", "%%%%"); | 54 body = body:gsub("%%", "%%%%"); |
56 return html.doc:gsub("###BODY_STUFF###", body) | 55 return html.doc:gsub("###BODY_STUFF###", body) |
57 :gsub("<title>muc_log</title>", "<title>"..(title and htmlEscape(title) or "Chatroom logs").."</title>"); | 56 :gsub("<title>muc_log</title>", "<title>"..(title and html_escape(title) or "Chatroom logs").."</title>"); |
58 end | 57 end |
59 | 58 |
60 function urlunescape (escapedUrl) | 59 function urlunescape (url) |
61 escapedUrl = escapedUrl:gsub("+", " ") | 60 url = url:gsub("+", " ") |
62 escapedUrl = escapedUrl:gsub("%%(%x%x)", function(h) return strchar(tonumber(h,16)) end) | 61 url = url:gsub("%%(%x%x)", function(h) return strchar(tonumber(h,16)) end) |
63 escapedUrl = escapedUrl:gsub("\r\n", "\n") | 62 url = url:gsub("\r\n", "\n") |
64 return escapedUrl | 63 return url |
65 end | 64 end |
66 | 65 |
67 local function generateRoomListSiteContent(component) | 66 local function generate_room_list(component) |
68 local rooms = ""; | 67 local rooms = ""; |
69 local component_host = hosts[component]; | 68 local component_host = hosts[component]; |
70 if component_host and component_host.muc ~= nil then | 69 if component_host and component_host.muc ~= nil then |
71 for jid, room in pairs(component_host.muc.rooms) do | 70 for jid, room in pairs(component_host.muc.rooms) do |
72 local node = splitJid(jid); | 71 local node = split_jid(jid); |
73 if not room._data.hidden and node then | 72 if not room._data.hidden and room._data.logging and node then |
74 rooms = rooms .. html.rooms.bit:gsub("###ROOM###", node):gsub("###COMPONENT###", component); | 73 rooms = rooms .. html.rooms.bit:gsub("###ROOM###", node):gsub("###COMPONENT###", component); |
75 end | 74 end |
76 end | 75 end |
77 return html.rooms.body:gsub("###ROOMS_STUFF###", rooms):gsub("###COMPONENT###", component), "Chatroom logs for "..component; | 76 return html.rooms.body:gsub("###ROOMS_STUFF###", rooms):gsub("###COMPONENT###", component), "Chatroom logs for "..component; |
78 end | 77 end |
87 return 31; | 86 return 31; |
88 end | 87 end |
89 return 30; | 88 return 30; |
90 end | 89 end |
91 | 90 |
92 local function createMonth(month, year, dayCallback) | 91 local function create_month(month, year, callback) |
93 local htmlStr = html.month.header; | 92 local html_str = html.month.header; |
94 local days = get_days_for_month(month, year); | 93 local days = get_days_for_month(month, year); |
95 local time = os_time{year=year, month=month, day=1}; | 94 local time = os_time{year=year, month=month, day=1}; |
96 local dow = tostring(os_date("%a", time)) | 95 local dow = tostring(os_date("%a", time)) |
97 local title = tostring(os_date("%B", time)); | 96 local title = tostring(os_date("%B", time)); |
98 local weekDays = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"}; | 97 local week_days = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"}; |
99 local weekDay = 0; | 98 local week_day = 0; |
100 local weeks = 1; | 99 local weeks = 1; |
101 local logAvailableForMinimumOneDay = false; | 100 local _available_for_one_day = false; |
102 | 101 |
103 local weekDaysHtml = ""; | 102 local week_days_html = ""; |
104 for _, tmp in ipairs(weekDays) do | 103 for _, tmp in ipairs(week_days) do |
105 weekDaysHtml = weekDaysHtml .. html.month.weekDay:gsub("###DAY###", tmp) .. "\n"; | 104 week_days_html = week_days_html .. html.month.weekDay:gsub("###DAY###", tmp) .. "\n"; |
106 end | 105 end |
107 | 106 |
108 htmlStr = htmlStr:gsub("###TITLE###", title):gsub("###WEEKDAYS###", weekDaysHtml); | 107 html_str = html_str:gsub("###TITLE###", title):gsub("###WEEKDAYS###", week_days_html); |
109 | 108 |
110 for i = 1, 31 do | 109 for i = 1, 31 do |
111 weekDay = weekDay + 1; | 110 week_day = week_day + 1; |
112 if weekDay == 1 then htmlStr = htmlStr .. "<tr>\n"; end | 111 if week_day == 1 then html_str = html_str .. "<tr>\n"; end |
113 if i == 1 then | 112 if i == 1 then |
114 for _, tmp in ipairs(weekDays) do | 113 for _, tmp in ipairs(week_days) do |
115 if dow ~= tmp then | 114 if dow ~= tmp then |
116 htmlStr = htmlStr .. html.month.emptyDay .. "\n"; | 115 html_str = html_str .. html.month.emptyDay .. "\n"; |
117 weekDay = weekDay + 1; | 116 week_day = week_day + 1; |
118 else | 117 else |
119 break; | 118 break; |
120 end | 119 end |
121 end | 120 end |
122 end | 121 end |
123 if i < days + 1 then | 122 if i < days + 1 then |
124 local tmp = tostring(i); | 123 local tmp = tostring(i); |
125 if dayCallback ~= nil and dayCallback.callback ~= nil then | 124 if callback and callback.callback then |
126 tmp = dayCallback.callback(dayCallback.path, i, month, year, dayCallback.room, dayCallback.webPath); | 125 tmp = callback.callback(callback.path, i, month, year, callback.room, callback.webpath); |
127 end | 126 end |
128 if tmp == nil then | 127 if tmp == nil then |
129 tmp = tostring(i); | 128 tmp = tostring(i); |
130 else | 129 else |
131 logAvailableForMinimumOneDay = true; | 130 _available_for_one_day = true; |
132 end | 131 end |
133 htmlStr = htmlStr .. html.month.day:gsub("###DAY###", tmp) .. "\n"; | 132 html_str = html_str .. html.month.day:gsub("###DAY###", tmp) .. "\n"; |
134 end | 133 end |
135 | 134 |
136 if i >= days then | 135 if i >= days then |
137 break; | 136 break; |
138 end | 137 end |
139 | 138 |
140 if weekDay == 7 then | 139 if week_day == 7 then |
141 weekDay = 0; | 140 week_day = 0; |
142 weeks = weeks + 1; | 141 weeks = weeks + 1; |
143 htmlStr = htmlStr .. "</tr>\n"; | 142 html_str = html_str .. "</tr>\n"; |
144 end | 143 end |
145 end | 144 end |
146 | 145 |
147 if weekDay + 1 < 8 or weeks < 6 then | 146 if week_day + 1 < 8 or weeks < 6 then |
148 weekDay = weekDay + 1; | 147 week_day = week_day + 1; |
149 if weekDay > 7 then | 148 if week_day > 7 then |
150 weekDay = 1; | 149 week_day = 1; |
151 end | 150 end |
152 if weekDay == 1 then | 151 if week_day == 1 then |
153 weeks = weeks + 1; | 152 weeks = weeks + 1; |
154 end | 153 end |
155 for y = weeks, 6 do | 154 for y = weeks, 6 do |
156 if weekDay == 1 then | 155 if week_day == 1 then |
157 htmlStr = htmlStr .. "<tr>\n"; | 156 html_str = html_str .. "<tr>\n"; |
158 end | 157 end |
159 for i = weekDay, 7 do | 158 for i = week_day, 7 do |
160 htmlStr = htmlStr .. html.month.emptyDay .. "\n"; | 159 html_str = html_str .. html.month.emptyDay .. "\n"; |
161 end | 160 end |
162 weekDay = 1 | 161 week_day = 1 |
163 htmlStr = htmlStr .. "</tr>\n"; | 162 html_str = html_str .. "</tr>\n"; |
164 end | 163 end |
165 end | 164 end |
166 htmlStr = htmlStr .. html.month.footer; | 165 html_str = html_str .. html.month.footer; |
167 if logAvailableForMinimumOneDay then | 166 if _available_for_one_day then |
168 return htmlStr; | 167 return html_str; |
169 end | 168 end |
170 end | 169 end |
171 | 170 |
172 local function createYear(year, dayCallback) | 171 local function create_year(year, callback) |
173 local year = year; | 172 local year = year; |
174 local tmp; | 173 local tmp; |
175 if tonumber(year) <= 99 then | 174 if tonumber(year) <= 99 then |
176 year = year + 2000; | 175 year = year + 2000; |
177 end | 176 end |
178 local htmlStr = ""; | 177 local html_str = ""; |
179 for i=1, 12 do | 178 for i=1, 12 do |
180 tmp = createMonth(i, year, dayCallback); | 179 tmp = create_month(i, year, callback); |
181 if tmp then | 180 if tmp then |
182 htmlStr = htmlStr .. "<div style='float: left; padding: 5px;'>\n" .. tmp .. "</div>\n"; | 181 html_str = html_str .. "<div style='float: left; padding: 5px;'>\n" .. tmp .. "</div>\n"; |
183 end | 182 end |
184 end | 183 end |
185 if htmlStr ~= "" then | 184 if html_str ~= "" then |
186 return "<div name='yearDiv' style='padding: 40px; text-align: center;'>" .. html.year.title:gsub("###YEAR###", tostring(year)) .. htmlStr .. "</div><br style='clear:both;'/> \n"; | 185 return "<div name='yearDiv' style='padding: 40px; text-align: center;'>" .. html.year.title:gsub("###YEAR###", tostring(year)) .. html_str .. "</div><br style='clear:both;'/> \n"; |
187 end | 186 end |
188 return ""; | 187 return ""; |
189 end | 188 end |
190 | 189 |
191 local function perDayCallback(path, day, month, year, room, webPath) | 190 local function day_callback(path, day, month, year, room, webpath) |
192 local webPath = webPath or "" | 191 local webpath = webpath or "" |
193 local year = year; | 192 local year = year; |
194 if year > 2000 then | 193 if year > 2000 then |
195 year = year - 2000; | 194 year = year - 2000; |
196 end | 195 end |
197 local bareDay = str_format("20%.02d-%.02d-%.02d", year, month, day); | 196 local bare_day = str_format("20%.02d-%.02d-%.02d", year, month, day); |
198 room = p_encode(room); | 197 room = p_encode(room); |
199 local attributes, err = lfs.attributes(path.."/"..str_format("%.02d%.02d%.02d", year, month, day).."/"..room..".dat"); | 198 local attributes, err = lfs.attributes(path.."/"..str_format("%.02d%.02d%.02d", year, month, day).."/"..room..".dat"); |
200 if attributes ~= nil and attributes.mode == "file" then | 199 if attributes ~= nil and attributes.mode == "file" then |
201 local s = html.days.bit; | 200 local s = html.days.bit; |
202 s = s:gsub("###BARE_DAY###", webPath .. bareDay); | 201 s = s:gsub("###BARE_DAY###", webpath .. bare_day); |
203 s = s:gsub("###DAY###", day); | 202 s = s:gsub("###DAY###", day); |
204 return s; | 203 return s; |
205 end | 204 end |
206 return; | 205 return; |
207 end | 206 end |
208 | 207 |
209 local function generateDayListSiteContentByRoom(bareRoomJid) | 208 local function generate_day_room_content(bare_room_jid) |
210 local days = ""; | 209 local days = ""; |
211 local arrDays = {}; | 210 local days_array = {}; |
212 local tmp; | 211 local tmp; |
213 local node, host = splitJid(bareRoomJid); | 212 local node, host = split_jid(bare_room_jid); |
214 local path = data_getpath(node, host, datastore); | 213 local path = data_getpath(node, host, datastore); |
215 local room = nil; | 214 local room = nil; |
216 local nextRoom = ""; | 215 local next_room = ""; |
217 local previousRoom = ""; | 216 local previous_room = ""; |
218 local rooms = ""; | 217 local rooms = ""; |
219 local attributes = nil; | 218 local attributes = nil; |
220 local since = ""; | 219 local since = ""; |
221 local to = ""; | 220 local to = ""; |
222 local topic = ""; | 221 local topic = ""; |
223 local component = hosts[host]; | 222 local component = hosts[host]; |
224 | 223 |
225 if not(component and component.muc and component.muc.rooms[bareRoomJid]) then | 224 if not(component and component.muc and component.muc.rooms[bare_room_jid]) then |
226 return; | 225 return; |
227 end | 226 end |
228 | 227 |
229 path = path:gsub("/[^/]*$", ""); | 228 path = path:gsub("/[^/]*$", ""); |
230 attributes = lfs.attributes(path); | 229 attributes = lfs.attributes(path); |
231 do | 230 do |
232 local found = 0; | 231 local found = 0; |
233 for jid, room in pairs(component.muc.rooms) do | 232 for jid, room in pairs(component.muc.rooms) do |
234 local node = splitJid(jid) | 233 local node = split_jid(jid) |
235 if not room._data.hidden and node then | 234 if not room._data.hidden and room._data.logging and node then |
236 if found == 0 then | 235 if found == 0 then |
237 previousRoom = node | 236 previous_room = node |
238 elseif found == 1 then | 237 elseif found == 1 then |
239 nextRoom = node | 238 next_room = node |
240 found = -1 | 239 found = -1 |
241 end | 240 end |
242 if jid == bareRoomJid then | 241 if jid == bare_room_jid then |
243 found = 1 | 242 found = 1 |
244 end | 243 end |
245 | 244 |
246 rooms = rooms .. html.days.rooms.bit:gsub("###ROOM###", node); | 245 rooms = rooms .. html.days.rooms.bit:gsub("###ROOM###", node); |
247 end | 246 end |
248 end | 247 end |
249 | 248 |
250 room = component.muc.rooms[bareRoomJid]; | 249 room = component.muc.rooms[bare_room_jid]; |
251 if room._data.hidden then | 250 if room._data.hidden or not room._data.logging then |
252 room = nil; | 251 room = nil; |
253 end | 252 end |
254 end | 253 end |
255 if attributes ~= nil and room ~= nil then | 254 if attributes and room then |
256 local alreadyDoneYears = {}; | 255 local already_done_years = {}; |
257 topic = room._data.subject or "(no subject)" | 256 topic = room._data.subject or "(no subject)" |
258 if topic:len() > 135 then | 257 if topic:len() > 135 then |
259 topic = topic:sub(1, topic:find(" ", 120)) .. " ..." | 258 topic = topic:sub(1, topic:find(" ", 120)) .. " ..." |
260 end | 259 end |
261 local folders = {}; | 260 local folders = {}; |
264 for _, folder in ipairs(folders) do | 263 for _, folder in ipairs(folders) do |
265 local year, month, day = folder:match("^(%d%d)(%d%d)(%d%d)"); | 264 local year, month, day = folder:match("^(%d%d)(%d%d)(%d%d)"); |
266 if year then | 265 if year then |
267 to = tostring(os_date("%B %Y", os_time({ day=tonumber(day), month=tonumber(month), year=2000+tonumber(year) }))); | 266 to = tostring(os_date("%B %Y", os_time({ day=tonumber(day), month=tonumber(month), year=2000+tonumber(year) }))); |
268 if since == "" then since = to; end | 267 if since == "" then since = to; end |
269 if not alreadyDoneYears[year] then | 268 if not already_done_years[year] then |
270 module:log("debug", "creating overview for: %s", to); | 269 module:log("debug", "creating overview for: %s", to); |
271 days = createYear(year, {callback=perDayCallback, path=path, room=node}) .. days; | 270 days = create_year(year, {callback=day_callback, path=path, room=node}) .. days; |
272 alreadyDoneYears[year] = true; | 271 already_done_years[year] = true; |
273 end | 272 end |
274 end | 273 end |
275 end | 274 end |
276 end | 275 end |
277 | 276 |
278 tmp = html.days.body:gsub("###DAYS_STUFF###", days); | 277 tmp = html.days.body:gsub("###DAYS_STUFF###", days); |
279 tmp = tmp:gsub("###PREVIOUS_ROOM###", previousRoom == "" and node or previousRoom); | 278 tmp = tmp:gsub("###PREVIOUS_ROOM###", previous_room == "" and node or previous_room); |
280 tmp = tmp:gsub("###NEXT_ROOM###", nextRoom == "" and node or nextRoom); | 279 tmp = tmp:gsub("###NEXT_ROOM###", next_room == "" and node or next_room); |
281 tmp = tmp:gsub("###ROOMS###", rooms); | 280 tmp = tmp:gsub("###ROOMS###", rooms); |
282 tmp = tmp:gsub("###ROOMTOPIC###", topic); | 281 tmp = tmp:gsub("###ROOMTOPIC###", topic); |
283 tmp = tmp:gsub("###SINCE###", since); | 282 tmp = tmp:gsub("###SINCE###", since); |
284 tmp = tmp:gsub("###TO###", to); | 283 tmp = tmp:gsub("###TO###", to); |
285 return tmp:gsub("###JID###", bareRoomJid), "Chatroom logs for "..bareRoomJid; | 284 return tmp:gsub("###JID###", bare_room_jid), "Chatroom logs for "..bare_room_jid; |
286 end | 285 end |
287 | 286 |
288 local function parseIqStanza(stanza, timeStuff, nick) | 287 local function parse_iq(stanza, time, nick) |
289 local text = nil; | 288 local text = nil; |
290 local victim = nil; | 289 local victim = nil; |
291 if(stanza.attr.type == "set") then | 290 if(stanza.attr.type == "set") then |
292 for _,tag in ipairs(stanza) do | 291 for _,tag in ipairs(stanza) do |
293 if tag.tag == "query" then | 292 if tag.tag == "query" then |
304 end | 303 end |
305 end | 304 end |
306 break; | 305 break; |
307 end | 306 end |
308 end | 307 end |
309 if victim ~= nil then | 308 if victim then |
310 if text ~= nil then | 309 if text then |
311 text = html.day.reason:gsub("###REASON###", htmlEscape(text)); | 310 text = html.day.reason:gsub("###REASON###", html_escape(text)); |
312 else | 311 else |
313 text = ""; | 312 text = ""; |
314 end | 313 end |
315 return html.day.kick:gsub("###TIME_STUFF###", timeStuff):gsub("###VICTIM###", victim):gsub("###REASON_STUFF###", text); | 314 return html.day.kick:gsub("###TIME_STUFF###", time):gsub("###VICTIM###", victim):gsub("###REASON_STUFF###", text); |
316 end | 315 end |
317 end | 316 end |
318 return; | 317 return; |
319 end | 318 end |
320 | 319 |
321 local function parsePresenceStanza(stanza, timeStuff, nick) | 320 local function parse_presence(stanza, time, nick) |
322 local ret = ""; | 321 local ret = ""; |
323 local showJoin = "block" | 322 local show_join = "block" |
324 | 323 |
325 if config and not config.showJoin then | 324 if config and not config.show_join then |
326 showJoin = "none"; | 325 show_join = "none"; |
327 end | 326 end |
328 | 327 |
329 if stanza.attr.type == nil then | 328 if stanza.attr.type == nil then |
330 local showStatus = "block" | 329 local show_status = "block" |
331 if config and not config.showStatus then | 330 if config and not config.show_status then |
332 showStatus = "none"; | 331 show_status = "none"; |
333 end | 332 end |
334 local show, status = nil, ""; | 333 local show, status = nil, ""; |
335 local alreadyJoined = false; | 334 local already_joined = false; |
336 for _, tag in ipairs(stanza) do | 335 for _, tag in ipairs(stanza) do |
337 if tag.tag == "alreadyJoined" then | 336 if tag.tag == "alreadyJoined" then |
338 alreadyJoined = true; | 337 already_joined = true; |
339 elseif tag.tag == "show" then | 338 elseif tag.tag == "show" then |
340 show = tag[1]; | 339 show = tag[1]; |
341 elseif tag.tag == "status" and tag[1] ~= nil then | 340 elseif tag.tag == "status" and tag[1] ~= nil then |
342 status = tag[1]; | 341 status = tag[1]; |
343 end | 342 end |
344 end | 343 end |
345 if alreadyJoined == true then | 344 if already_joined == true then |
346 if show == nil then | 345 if show == nil then |
347 show = "online"; | 346 show = "online"; |
348 end | 347 end |
349 ret = html.day.presence.statusChange:gsub("###TIME_STUFF###", timeStuff); | 348 ret = html.day.presence.statusChange:gsub("###TIME_STUFF###", time); |
350 if status ~= "" then | 349 if status ~= "" then |
351 status = html.day.presence.statusText:gsub("###STATUS###", htmlEscape(status)); | 350 status = html.day.presence.statusText:gsub("###STATUS###", html_escape(status)); |
352 end | 351 end |
353 ret = ret:gsub("###SHOW###", show):gsub("###NICK###", nick):gsub("###SHOWHIDE###", showStatus):gsub("###STATUS_STUFF###", status); | 352 ret = ret:gsub("###SHOW###", show):gsub("###NICK###", nick):gsub("###SHOWHIDE###", show_status):gsub("###STATUS_STUFF###", status); |
354 else | 353 else |
355 ret = html.day.presence.join:gsub("###TIME_STUFF###", timeStuff):gsub("###SHOWHIDE###", showJoin):gsub("###NICK###", nick); | 354 ret = html.day.presence.join:gsub("###TIME_STUFF###", time):gsub("###SHOWHIDE###", show_join):gsub("###NICK###", nick); |
356 end | 355 end |
357 elseif stanza.attr.type ~= nil and stanza.attr.type == "unavailable" then | 356 elseif stanza.attr.type == "unavailable" then |
358 | 357 |
359 ret = html.day.presence.leave:gsub("###TIME_STUFF###", timeStuff):gsub("###SHOWHIDE###", showJoin):gsub("###NICK###", nick); | 358 ret = html.day.presence.leave:gsub("###TIME_STUFF###", time):gsub("###SHOWHIDE###", show_join):gsub("###NICK###", nick); |
360 end | 359 end |
361 return ret; | 360 return ret; |
362 end | 361 end |
363 | 362 |
364 local function parseMessageStanza(stanza, timeStuff, nick) | 363 local function parse_message(stanza, time, nick) |
365 local body, title, ret = nil, nil, ""; | 364 local body, title, ret = nil, nil, ""; |
366 | 365 |
367 for _,tag in ipairs(stanza) do | 366 for _,tag in ipairs(stanza) do |
368 if tag.tag == "body" then | 367 if tag.tag == "body" then |
369 body = tag[1]; | 368 body = tag[1]; |
370 if nick ~= nil then | 369 if nick then |
371 break; | 370 break; |
372 end | 371 end |
373 elseif tag.tag == "nick" and nick == nil then | 372 elseif tag.tag == "nick" and nick == nil then |
374 nick = htmlEscape(tag[1]); | 373 nick = html_escape(tag[1]); |
375 if body ~= nil or title ~= nil then | 374 if body or title then |
376 break; | 375 break; |
377 end | 376 end |
378 elseif tag.tag == "subject" then | 377 elseif tag.tag == "subject" then |
379 title = tag[1]; | 378 title = tag[1]; |
380 if nick ~= nil then | 379 if nick then |
381 break; | 380 break; |
382 end | 381 end |
383 end | 382 end |
384 end | 383 end |
385 if nick ~= nil and body ~= nil then | 384 if nick and body then |
386 body = htmlEscape(body); | 385 body = html_escape(body); |
387 local me = body:find("^/me"); | 386 local me = body:find("^/me"); |
388 local template = ""; | 387 local template = ""; |
389 if not me then | 388 if not me then |
390 template = html.day.message; | 389 template = html.day.message; |
391 else | 390 else |
392 template = html.day.messageMe; | 391 template = html.day.messageMe; |
393 body = body:gsub("^/me ", ""); | 392 body = body:gsub("^/me ", ""); |
394 end | 393 end |
395 ret = template:gsub("###TIME_STUFF###", timeStuff):gsub("###NICK###", nick):gsub("###MSG###", body); | 394 ret = template:gsub("###TIME_STUFF###", time):gsub("###NICK###", nick):gsub("###MSG###", body); |
396 elseif nick ~= nil and title ~= nil then | 395 elseif nick and title then |
397 title = htmlEscape(title); | 396 title = html_escape(title); |
398 ret = html.day.titleChange:gsub("###TIME_STUFF###", timeStuff):gsub("###NICK###", nick):gsub("###TITLE###", title); | 397 ret = html.day.titleChange:gsub("###TIME_STUFF###", time):gsub("###NICK###", nick):gsub("###TITLE###", title); |
399 end | 398 end |
400 return ret; | 399 return ret; |
401 end | 400 end |
402 | 401 |
403 local function incrementDay(bare_day) | 402 local function increment_day(bare_day) |
404 local year, month, day = bare_day:match("^20(%d%d)-(%d%d)-(%d%d)$"); | 403 local year, month, day = bare_day:match("^20(%d%d)-(%d%d)-(%d%d)$"); |
405 local leapyear = false; | 404 local leapyear = false; |
406 module:log("debug", tostring(day).."/"..tostring(month).."/"..tostring(year)) | 405 module:log("debug", tostring(day).."/"..tostring(month).."/"..tostring(year)) |
407 | 406 |
408 day = tonumber(day); | 407 day = tonumber(day); |
438 day = day + 1; | 437 day = day + 1; |
439 end | 438 end |
440 return strformat("20%.02d-%.02d-%.02d", year, month, day); | 439 return strformat("20%.02d-%.02d-%.02d", year, month, day); |
441 end | 440 end |
442 | 441 |
443 local function findNextDay(bareRoomJid, bare_day) | 442 local function find_next_day(bare_room_jid, bare_day) |
444 local node, host = splitJid(bareRoomJid); | 443 local node, host = split_jid(bare_room_jid); |
445 local day = incrementDay(bare_day); | 444 local day = increment_day(bare_day); |
446 local max_trys = 7; | 445 local max_trys = 7; |
447 | 446 |
448 module:log("debug", day); | 447 module:log("debug", day); |
449 while(not store_exists(node, host, day)) do | 448 while(not store_exists(node, host, day)) do |
450 max_trys = max_trys - 1; | 449 max_trys = max_trys - 1; |
451 if max_trys == 0 then | 450 if max_trys == 0 then |
452 break; | 451 break; |
453 end | 452 end |
454 day = incrementDay(day); | 453 day = increment_day(day); |
455 end | 454 end |
456 if max_trys == 0 then | 455 if max_trys == 0 then |
457 return nil; | 456 return nil; |
458 else | 457 else |
459 return day; | 458 return day; |
460 end | 459 end |
461 end | 460 end |
462 | 461 |
463 local function decrementDay(bare_day) | 462 local function decrement_day(bare_day) |
464 local year, month, day = bare_day:match("^20(%d%d)-(%d%d)-(%d%d)$"); | 463 local year, month, day = bare_day:match("^20(%d%d)-(%d%d)-(%d%d)$"); |
465 local leapyear = false; | 464 local leapyear = false; |
466 module:log("debug", tostring(day).."/"..tostring(month).."/"..tostring(year)) | 465 module:log("debug", tostring(day).."/"..tostring(month).."/"..tostring(year)) |
467 | 466 |
468 day = tonumber(day); | 467 day = tonumber(day); |
496 day = day - 1; | 495 day = day - 1; |
497 end | 496 end |
498 return strformat("20%.02d-%.02d-%.02d", year, month, day); | 497 return strformat("20%.02d-%.02d-%.02d", year, month, day); |
499 end | 498 end |
500 | 499 |
501 local function findPreviousDay(bareRoomJid, bare_day) | 500 local function find_previous_day(bare_room_jid, bare_day) |
502 local node, host = splitJid(bareRoomJid); | 501 local node, host = split_jid(bare_room_jid); |
503 local day = decrementDay(bare_day); | 502 local day = decrement_day(bare_day); |
504 local max_trys = 7; | 503 local max_trys = 7; |
505 module:log("debug", day); | 504 module:log("debug", day); |
506 while(not store_exists(node, host, day)) do | 505 while(not store_exists(node, host, day)) do |
507 max_trys = max_trys - 1; | 506 max_trys = max_trys - 1; |
508 if max_trys == 0 then | 507 if max_trys == 0 then |
509 break; | 508 break; |
510 end | 509 end |
511 day = decrementDay(day); | 510 day = decrement_day(day); |
512 end | 511 end |
513 if max_trys == 0 then | 512 if max_trys == 0 then |
514 return nil; | 513 return nil; |
515 else | 514 else |
516 return day; | 515 return day; |
517 end | 516 end |
518 end | 517 end |
519 | 518 |
520 local function parseDay(bareRoomJid, roomSubject, bare_day) | 519 local function parse_day(bare_room_jid, room_subject, bare_day) |
521 local ret = ""; | 520 local ret = ""; |
522 local year; | 521 local year; |
523 local month; | 522 local month; |
524 local day; | 523 local day; |
525 local tmp; | 524 local tmp; |
526 local node, host = splitJid(bareRoomJid); | 525 local node, host = split_jid(bare_room_jid); |
527 local year, month, day = bare_day:match("^20(%d%d)-(%d%d)-(%d%d)$"); | 526 local year, month, day = bare_day:match("^20(%d%d)-(%d%d)-(%d%d)$"); |
528 local previousDay = findPreviousDay(bareRoomJid, bare_day); | 527 local previous_day = find_previous_day(bare_room_jid, bare_day); |
529 local nextDay = findNextDay(bareRoomJid, bare_day); | 528 local next_day = find_next_day(bare_room_jid, bare_day); |
530 local temptime = {day=0, month=0, year=0}; | 529 local temptime = {day=0, month=0, year=0}; |
531 local path = data_getpath(node, host, datastore); | 530 local path = data_getpath(node, host, datastore); |
532 path = path:gsub("/[^/]*$", ""); | 531 path = path:gsub("/[^/]*$", ""); |
533 local calendar = "" | 532 local calendar = "" |
534 | 533 |
537 end | 536 end |
538 | 537 |
539 temptime.day = tonumber(day) | 538 temptime.day = tonumber(day) |
540 temptime.month = tonumber(month) | 539 temptime.month = tonumber(month) |
541 temptime.year = tonumber(year) | 540 temptime.year = tonumber(year) |
542 calendar = createMonth(temptime.month, temptime.year, {callback=perDayCallback, path=path, room=node, webPath="../"}) or "" | 541 calendar = create_month(temptime.month, temptime.year, {callback=day_callback, path=path, room=node, webpath="../"}) or "" |
543 | 542 |
544 if bare_day then | 543 if bare_day then |
545 local data = data_load(node, host, datastore .. "/" .. bare_day:match("^20(.*)"):gsub("-", "")); | 544 local data = data_load(node, host, datastore .. "/" .. bare_day:match("^20(.*)"):gsub("-", "")); |
546 if data then | 545 if data then |
547 for i=1, #data, 1 do | 546 for i=1, #data, 1 do |
552 local nick; | 551 local nick; |
553 local tmp; | 552 local tmp; |
554 | 553 |
555 -- grep nick from "from" resource | 554 -- grep nick from "from" resource |
556 if stanza[1].attr.from then -- presence and messages | 555 if stanza[1].attr.from then -- presence and messages |
557 nick = htmlEscape(stanza[1].attr.from:match("/(.+)$")); | 556 nick = html_escape(stanza[1].attr.from:match("/(.+)$")); |
558 elseif stanza[1].attr.to then -- iq | 557 elseif stanza[1].attr.to then -- iq |
559 nick = htmlEscape(stanza[1].attr.to:match("/(.+)$")); | 558 nick = html_escape(stanza[1].attr.to:match("/(.+)$")); |
560 end | 559 end |
561 | 560 |
562 if stanza[1].tag == "presence" and nick then | 561 if stanza[1].tag == "presence" and nick then |
563 tmp = parsePresenceStanza(stanza[1], timeStuff, nick); | 562 tmp = parse_presence(stanza[1], timeStuff, nick); |
564 elseif stanza[1].tag == "message" then | 563 elseif stanza[1].tag == "message" then |
565 tmp = parseMessageStanza(stanza[1], timeStuff, nick); | 564 tmp = parse_message(stanza[1], timeStuff, nick); |
566 elseif stanza[1].tag == "iq" then | 565 elseif stanza[1].tag == "iq" then |
567 tmp = parseIqStanza(stanza[1], timeStuff, nick); | 566 tmp = parse_iq(stanza[1], timeStuff, nick); |
568 else | 567 else |
569 module:log("info", "unknown stanza subtag in log found. room: %s; day: %s", bareRoomJid, year .. "/" .. month .. "/" .. day); | 568 module:log("info", "unknown stanza subtag in log found. room: %s; day: %s", bare_room_jid, year .. "/" .. month .. "/" .. day); |
570 end | 569 end |
571 if tmp then | 570 if tmp then |
572 ret = ret .. tmp | 571 ret = ret .. tmp |
573 tmp = nil; | 572 tmp = nil; |
574 end | 573 end |
575 end | 574 end |
576 end | 575 end |
577 end | 576 end |
578 end | 577 end |
579 if ret ~= "" then | 578 if ret ~= "" then |
580 if nextDay then | 579 if next_day then |
581 nextDay = html.day.dayLink:gsub("###DAY###", nextDay):gsub("###TEXT###", ">") | 580 next_day = html.day.dayLink:gsub("###DAY###", next_day):gsub("###TEXT###", ">") |
582 end | 581 end |
583 if previousDay then | 582 if previous_day then |
584 previousDay = html.day.dayLink:gsub("###DAY###", previousDay):gsub("###TEXT###", "<"); | 583 previous_day = html.day.dayLink:gsub("###DAY###", previous_day):gsub("###TEXT###", "<"); |
585 end | 584 end |
586 ret = ret:gsub("%%", "%%%%"); | 585 ret = ret:gsub("%%", "%%%%"); |
587 tmp = html.day.body:gsub("###DAY_STUFF###", ret):gsub("###JID###", bareRoomJid); | 586 if config.show_presences then |
587 tmp = html.day.body:gsub("###DAY_STUFF###", ret):gsub("###JID###", bare_room_jid); | |
588 else | |
589 tmp = html.day.bodynp:gsub("###DAY_STUFF###", ret):gsub("###JID###", bare_room_jid); | |
590 end | |
588 tmp = tmp:gsub("###CALENDAR###", calendar); | 591 tmp = tmp:gsub("###CALENDAR###", calendar); |
589 tmp = tmp:gsub("###DATE###", tostring(os_date("%A, %B %d, %Y", os_time(temptime)))); | 592 tmp = tmp:gsub("###DATE###", tostring(os_date("%A, %B %d, %Y", os_time(temptime)))); |
590 tmp = tmp:gsub("###TITLE_STUFF###", html.day.title:gsub("###TITLE###", roomSubject)); | 593 tmp = tmp:gsub("###TITLE_STUFF###", html.day.title:gsub("###TITLE###", room_subject)); |
591 tmp = tmp:gsub("###STATUS_CHECKED###", config.showStatus and "checked='checked'" or ""); | 594 tmp = tmp:gsub("###STATUS_CHECKED###", config.show_status and "checked='checked'" or ""); |
592 tmp = tmp:gsub("###JOIN_CHECKED###", config.showJoin and "checked='checked'" or ""); | 595 tmp = tmp:gsub("###JOIN_CHECKED###", config.show_join and "checked='checked'" or ""); |
593 tmp = tmp:gsub("###NEXT_LINK###", nextDay or ""); | 596 tmp = tmp:gsub("###NEXT_LINK###", next_day or ""); |
594 tmp = tmp:gsub("###PREVIOUS_LINK###", previousDay or ""); | 597 tmp = tmp:gsub("###PREVIOUS_LINK###", previous_day or ""); |
595 | 598 |
596 return tmp, "Chatroom logs for "..bareRoomJid.." ("..tostring(os_date("%A, %B %d, %Y", os_time(temptime)))..")"; | 599 return tmp, "Chatroom logs for "..bare_room_jid.." ("..tostring(os_date("%A, %B %d, %Y", os_time(temptime)))..")"; |
597 end | 600 end |
598 end | 601 end |
599 end | 602 end |
600 | 603 |
601 local function handle_error(code, err) return http_event("http-error", { code = code, message = err }); end | 604 local function handle_error(code, err) return http_event("http-error", { code = code, message = err }); end |
602 function handle_request(event) | 605 function handle_request(event) |
603 local response = event.response; | 606 local response = event.response; |
604 local request = event.request; | 607 local request = event.request; |
605 local room; | 608 local room; |
606 | 609 |
607 local node, day, more = request.url.path:match("^/"..urlBase.."/+([^/]*)/*([^/]*)/*(.*)$"); | 610 local node, day, more = request.url.path:match("^/"..url_base.."/+([^/]*)/*([^/]*)/*(.*)$"); |
608 if more ~= "" then | 611 if more ~= "" then |
609 response.status_code = 404; | 612 response.status_code = 404; |
610 return response:send(handle_error(response.status_code, "Unknown URL.")); | 613 return response:send(handle_error(response.status_code, "Unknown URL.")); |
611 end | 614 end |
612 if node == "" then node = nil; end | 615 if node == "" then node = nil; end |
623 if node then room = hosts[my_host].modules.muc.rooms[node.."@"..my_host]; end | 626 if node then room = hosts[my_host].modules.muc.rooms[node.."@"..my_host]; end |
624 if node and not room then | 627 if node and not room then |
625 response.status_code = 404; | 628 response.status_code = 404; |
626 return response:send(handle_error(response.status_code, "Room doesn't exist.")); | 629 return response:send(handle_error(response.status_code, "Room doesn't exist.")); |
627 end | 630 end |
628 if room and room._data.hidden then | 631 if room and (room._data.hidden or not room._data.logging) then |
629 response.status_code = 404; | 632 response.status_code = 404; |
630 return response:send(handle_error(response.status_code, "There're no logs for this room.")); | 633 return response:send(handle_error(response.status_code, "There're no logs for this room.")); |
631 end | 634 end |
632 | 635 |
633 | 636 |
634 if not node then -- room list for component | 637 if not node then -- room list for component |
635 return response:send(createDoc(generateRoomListSiteContent(my_host))); | 638 return response:send(create_doc(generate_room_list(my_host))); |
636 elseif not day then -- room's listing | 639 elseif not day then -- room's listing |
637 return response:send(createDoc(generateDayListSiteContentByRoom(node.."@"..my_host))); | 640 return response:send(create_doc(generate_day_room_content(node.."@"..my_host))); |
638 else | 641 else |
639 if not day:match("^20(%d%d)-(%d%d)-(%d%d)$") then | 642 if not day:match("^20(%d%d)-(%d%d)-(%d%d)$") then |
640 local y,m,d = day:match("^(%d%d)(%d%d)(%d%d)$"); | 643 local y,m,d = day:match("^(%d%d)(%d%d)(%d%d)$"); |
641 if not y then | 644 if not y then |
642 response.status_code = 404; | 645 response.status_code = 404; |
643 return response:send(handle_error(response.status_code, "No entries for that year.")); | 646 return response:send(handle_error(response.status_code, "No entries for that year.")); |
644 end | 647 end |
645 response.status_code = 301; | 648 response.status_code = 301; |
646 response.headers = { ["Location"] = request.url.path:match("^/"..urlBase.."/+[^/]*").."/20"..y.."-"..m.."-"..d.."/" }; | 649 response.headers = { ["Location"] = request.url.path:match("^/"..url_base.."/+[^/]*").."/20"..y.."-"..m.."-"..d.."/" }; |
647 return response:send(); | 650 return response:send(); |
648 end | 651 end |
649 | 652 |
650 local body = createDoc(parseDay(node.."@"..my_host, room._data.subject or "", day)); | 653 local body = create_doc(parse_day(node.."@"..my_host, room._data.subject or "", day)); |
651 if body == "" then | 654 if body == "" then |
652 response.status_code = 404; | 655 response.status_code = 404; |
653 return response:send(handle_error(response.status_code, "Day entry doesn't exist.")); | 656 return response:send(handle_error(response.status_code, "Day entry doesn't exist.")); |
654 end | 657 end |
655 return response:send(body); | 658 return response:send(body); |
656 end | 659 end |
657 end | 660 end |
658 | 661 |
659 local function readFile(filepath) | 662 local function read_file(filepath) |
660 local f,err = io_open(filepath, "r"); | 663 local f,err = io_open(filepath, "r"); |
661 if not f then return f,err; end | 664 if not f then return f,err; end |
662 local t = f:read("*all"); | 665 local t = f:read("*all"); |
663 f:close() | 666 f:close() |
664 return t; | 667 return t; |
665 end | 668 end |
666 | 669 |
667 local function loadTheme(path) | 670 local function load_theme(path) |
668 for file in lfs.dir(path) do | 671 for file in lfs.dir(path) do |
669 if file:match("%.html$") then | 672 if file:match("%.html$") then |
670 module:log("debug", "opening theme file: " .. file); | 673 module:log("debug", "opening theme file: " .. file); |
671 local content,err = readFile(path .. "/" .. file); | 674 local content,err = read_file(path .. "/" .. file); |
672 if not content then return content,err; end | 675 if not content then return content,err; end |
673 | 676 |
674 -- html.a.b.c = content of a_b_c.html | 677 -- html.a.b.c = content of a_b_c.html |
675 local tmp = html; | 678 local tmp = html; |
676 for idx in file:gmatch("([^_]*)_") do | 679 for idx in file:gmatch("([^_]*)_") do |
683 return true; | 686 return true; |
684 end | 687 end |
685 | 688 |
686 function module.load() | 689 function module.load() |
687 config = module:get_option("muc_log_http_config", {}); | 690 config = module:get_option("muc_log_http_config", {}); |
688 if config.showStatus == nil then config.showStatus = true; end | 691 if module:get_option_boolean("muc_log_presences", false) then config.show_presences = true end |
689 if config.showJoin == nil then config.showJoin = true; end | 692 if config.show_status == nil then config.show_status = true; end |
690 if config.urlBase and type(config.urlBase) == "string" then urlBase = config.urlBase; end | 693 if config.show_join == nil then config.show_join = true; end |
694 if config.url_base and type(config.url_base) == "string" then url_base = config.url_base; end | |
691 | 695 |
692 theme = config.theme or "prosody"; | 696 theme = config.theme or "prosody"; |
693 local themePath = themesParent .. "/" .. tostring(theme); | 697 local theme_path = themes_parent .. "/" .. tostring(theme); |
694 local attributes, err = lfs.attributes(themePath); | 698 local attributes, err = lfs.attributes(theme_path); |
695 if attributes == nil or attributes.mode ~= "directory" then | 699 if attributes == nil or attributes.mode ~= "directory" then |
696 module:log("error", "Theme folder of theme \"".. tostring(theme) .. "\" isn't existing. expected Path: " .. themePath); | 700 module:log("error", "Theme folder of theme \"".. tostring(theme) .. "\" isn't existing. expected Path: " .. theme_path); |
697 return false; | 701 return false; |
698 end | 702 end |
699 | 703 |
700 local themeLoaded,err = loadTheme(themePath); | 704 local themeLoaded,err = load_theme(theme_path); |
701 if not themeLoaded then | 705 if not themeLoaded then |
702 module:log("error", "Theme \"%s\" is missing something: %s", tostring(theme), err); | 706 module:log("error", "Theme \"%s\" is missing something: %s", tostring(theme), err); |
703 return false; | 707 return false; |
704 end | 708 end |
705 | 709 |
706 module:provides("http", { | 710 module:provides("http", { |
707 default_path = urlBase, | 711 default_path = url_base, |
708 route = { | 712 route = { |
709 ["GET /*"] = handle_request; | 713 ["GET /*"] = handle_request; |
710 } | 714 } |
711 }); | 715 }); |
712 end | 716 end |