Mercurial > prosody-modules
changeset 353:8ef36af30181
merge with upstream
author | Phil Stewart <phil.stewart@lichp.co.uk> |
---|---|
date | Sun, 03 Apr 2011 22:49:36 +0100 (2011-04-03) |
parents | cd838419a85d (current diff) 0b4fe47e648d (diff) |
children | f24998ec7f8d |
files | |
diffstat | 16 files changed, 1024 insertions(+), 788 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mod_json_streams/mod_json_streams.lua Sun Apr 03 22:49:36 2011 +0100 @@ -0,0 +1,154 @@ +-- +-- XEP-0295: JSON Encodings for XMPP +-- + +module.host = "*" + +local httpserver = require "net.httpserver"; +local filters = require "util.filters" +local json = require "util.json" + +local json_escapes = { + ["\""] = "\\\"", ["\\"] = "\\\\", ["\b"] = "\\b", ["\f"] = "\\f", + ["\n"] = "\\n", ["\r"] = "\\r", ["\t"] = "\\t"}; + +local s_char = string.char; +for i=0,31 do + local ch = s_char(i); + if not json_escapes[ch] then json_escapes[ch] = ("\\u%.4X"):format(i); end +end + +local state_out = 0; +local state_key_before = 1; +local state_key_in = 2; +local state_key_escape = 3; +local state_key_after = 4; +local state_val_before = 5; +local state_val_in = 6; +local state_val_escape = 7; +local state_val_after = 8; + +local whitespace = { [" "] = true, ["\n"] = true, ["\r"] = true, ["\t"] = true }; +function json_decoder() + local state = state_out; + local quote; + local output = ""; + local buffer = ""; + return function(input) + for ch in input:gmatch(".") do + module:log("debug", "%s | %d", ch, state) + local final = false; + if state == state_out then + if whitespace[ch] then + elseif ch ~= "{" then return nil, "{ expected"; + else state = state_key_before end + elseif state == state_key_before then + if whitespace[ch] then + elseif ch ~= "'" and ch ~= "\"" then return nil, "\" expected"; + else quote = ch; state = state_key_in; end + elseif state == state_key_in then + if ch == quote then state = state_key_after; + elseif ch ~= "s" then return nil, "invalid key, 's' expected"; -- only s as key allowed + else end -- ignore key + elseif state == state_key_after then + if whitespace[ch] then + elseif ch ~= ":" then return nil, ": expected"; + else state = state_val_before; end + elseif state == state_val_before then + if whitespace[ch] then + elseif ch ~= "'" and ch ~= "\"" then return nil, "\" expected"; + else quote = ch; state = state_val_in; end + elseif state == state_val_in then + if ch == quote then state = state_val_after; + elseif ch == "\\" then state = state_val_escape; + else end + elseif state == state_val_after then + if whitespace[ch] then + elseif ch ~= "}" then return nil, "} expected"; + else state = state_out; + final = true; + end + elseif state == state_val_escape then + state = state_val_in; + else + module:log("error", "Unhandled state: "..state); + return nil, "Unhandled state in parser" + end + buffer = buffer..ch; + if final then + module:log("debug", "%s", buffer) + local tmp; + pcall(function() tmp = json.decode(buffer); end); + if not tmp then return nil, "Invalid JSON"; end + output, buffer = output..tmp.s, ""; + end + end + local _ = output; output = ""; + return _; + end; +end + +function filter_hook(session) + local determined = false; + local is_json = false; + local function in_filter(t) + if not determined then + is_json = (t:sub(1,1) == "{") and json_decoder(); + determined = true; + end + if is_json then + local s, err = is_json(t); + if not err then return s; end + session:close("not-well-formed"); + return; + end + return t; + end + local function out_filter(t) + if is_json then + return '{"s":"' .. t:gsub(".", json_escapes) .. '"}'; -- encode + end + return t; + end + filters.add_filter(session, "bytes/in", in_filter, 100); + filters.add_filter(session, "bytes/out", out_filter, 100); +end + +function module.load() + filters.add_filter_hook(filter_hook); +end +function module.unload() + filters.remove_filter_hook(filter_hook); +end + +function encode(data) + if type(data) == "string" then + data = json.encode({ s = data }); + elseif type(data) == "table" and data.body then + data.body = json.encode({ s = data.body }); + data.headers["Content-Type"] = "application/json"; + end + return data; +end +function handle_request(method, body, request) + local mod_bosh = modulemanager.get_module("*", "bosh") + if mod_bosh then + if body and method == "POST" then + pcall(function() body = json.decode(body).s; end); + end + local _send = request.send; + function request:send(data) return _send(self, encode(data)); end + return encode(mod_bosh.handle_request(method, body, request)); + end + return "<html><body>mod_bosh not loaded</body></html>"; +end + +local function setup() + local ports = module:get_option("jsonstreams_ports") or { 5280 }; + httpserver.new_from_config(ports, handle_request, { base = "jsonstreams" }); +end +if prosody.start_time then -- already started + setup(); +else + prosody.events.add_handler("server-started", setup); +end
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mod_json_streams/strophe.jsonstreams.js Sun Apr 03 22:49:36 2011 +0100 @@ -0,0 +1,73 @@ + +/* jsonstreams plugin +** +** This plugin upgrades Strophe to support XEP-0295: JSON Encodings for XMPP +** +*/ + +Strophe.addConnectionPlugin('jsonstreams', { + init: function (conn) { + + var parseXMLString = function(xmlStr) { + var xmlDoc = null; + if (window.ActiveXObject) { + xmlDoc = new ActiveXObject("Microsoft.XMLDOM"); + xmlDoc.async=false; + xmlDoc.loadXML(xmlStr); + } else { + var parser = new DOMParser(); + xmlDoc = parser.parseFromString(xmlStr, "text/xml"); + } + return xmlDoc; + } + + // replace Strophe.Request._newXHR with new jsonstreams version + // if JSON is detected + if (window.JSON) { + var _newXHR = Strophe.Request.prototype._newXHR; + Strophe.Request.prototype._newXHR = function () { + var _xhr = _newXHR.apply(this, arguments); + var xhr = { + readyState: 0, + responseText: null, + responseXML: null, + status: null, + open: function(a, b, c) { return _xhr.open(a, b, c) }, + abort: function() { _xhr.abort(); }, + send: function(data) { + data = JSON.stringify({"s":data}); + return _xhr.send(data); + } + }; + var req = this; + xhr.onreadystatechange = this.func.bind(null, this); + _xhr.onreadystatechange = function() { + xhr.readyState = _xhr.readyState; + if (xhr.readyState != 4) { + xhr.status = 0; + xhr.responseText = ""; + xhr.responseXML = null; + } else { + xhr.status = _xhr.status; + xhr.responseText = _xhr.responseText; + xhr.responseXML = _xhr.responseXML; + if (_xhr.responseText && !(_xhr.responseXML + && _xhr.responseXML.documentElement + && _xhr.responseXML.documentElement.tagName != "parsererror")) { + var data = JSON.parse(_xhr.responseText); + if (data && data.s) { + xhr.responseText = data.s; + xhr.responseXML = parseXMLString(data.s); + } + } + } + if ("function" == typeof xhr.onreadystatechange) { xhr.onreadystatechange(req); } + } + return xhr; + }; + } else { + Strophe.error("jsonstreams plugin loaded, but JSON not found." + + " Falling back to native XHR implementation."); + } + } +});
--- a/mod_muc_log_http/muc_log_http/mod_muc_log_http.lua Sun Apr 03 22:47:06 2011 +0100 +++ b/mod_muc_log_http/muc_log_http/mod_muc_log_http.lua Sun Apr 03 22:49:36 2011 +0100 @@ -1,5 +1,5 @@ -- Copyright (C) 2009 Thilo Cestonaro --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- @@ -28,11 +28,11 @@ local os_date, os_time = os.date, os.time; local str_format = string.format; local io_open = io.open; -local themesParent = (CFG_PLUGINDIR or "./plugins/") .. "muc_log_http/themes"; +local themesParent = (module.path and module.path:gsub("[/\\][^/\\]*$", "") or (prosody.paths.plugins or "./plugins") .. "/muc_log_http") .. "/themes"; local lom = require "lxp.lom"; ---[[ LuaFileSystem +--[[ LuaFileSystem * URL: http://www.keplerproject.org/luafilesystem/index.html * Install: luarocks install luafilesystem * ]] @@ -46,115 +46,115 @@ local theme; local function checkDatastorePathExists(node, host, today, create) - create = create or false; - local path = data_getpath(node, host, datastore, "dat", true); - path = path:gsub("/[^/]*$", ""); + create = create or false; + local path = data_getpath(node, host, datastore, "dat", true); + path = path:gsub("/[^/]*$", ""); + + -- check existance + local attributes, err = lfs.attributes(path); + if attributes == nil or attributes.mode ~= "directory" then + module:log("warn", "muc_log folder isn't a folder: %s", path); + return false; + end - -- check existance - local attributes, err = lfs.attributes(path); - if attributes == nil or attributes.mode ~= "directory" then - module:log("warn", "muc_log folder isn't a folder: %s", path); - return false; - end - - attributes, err = lfs.attributes(path .. "/" .. today); - if attributes == nil then - if create then - return lfs.mkdir(path .. "/" .. today); - else - return false; - end - elseif attributes.mode == "directory" then - return true; - end - return false; + attributes, err = lfs.attributes(path .. "/" .. today); + if attributes == nil then + if create then + return lfs.mkdir(path .. "/" .. today); + else + return false; + end + elseif attributes.mode == "directory" then + return true; + end + return false; end function createDoc(body) - if body then - body = body:gsub("%%", "%%%%"); - return html.doc:gsub("###BODY_STUFF###", body); - end + if body then + body = body:gsub("%%", "%%%%"); + return html.doc:gsub("###BODY_STUFF###", body); + end end function urlunescape (escapedUrl) - escapedUrl = escapedUrl:gsub("+", " ") - escapedUrl = escapedUrl:gsub("%%(%x%x)", function(h) return strchar(tonumber(h,16)) end) - escapedUrl = escapedUrl:gsub("\r\n", "\n") - return escapedUrl + escapedUrl = escapedUrl:gsub("+", " ") + escapedUrl = escapedUrl:gsub("%%(%x%x)", function(h) return strchar(tonumber(h,16)) end) + escapedUrl = escapedUrl:gsub("\r\n", "\n") + return escapedUrl end local function htmlEscape(t) - if t then - t = t:gsub("<", "<"); - t = t:gsub(">", ">"); - t = t:gsub("(http://[%a%d@%.:/&%?=%-_#%%~]+)", function(h) - h = urlunescape(h) - return "<a href='" .. h .. "'>" .. h .. "</a>"; - end); - t = t:gsub("\n", "<br />"); - t = t:gsub("%%", "%%%%"); - else - t = ""; - end - return t; + if t then + t = t:gsub("<", "<"); + t = t:gsub(">", ">"); + t = t:gsub("(http://[%a%d@%.:/&%?=%-_#%%~]+)", function(h) + h = urlunescape(h) + return "<a href='" .. h .. "'>" .. h .. "</a>"; + end); + t = t:gsub("\n", "<br />"); + t = t:gsub("%%", "%%%%"); + else + t = ""; + end + return t; end function splitUrl(url) - local tmp = url:sub(string.len("/muc_log/") + 1); - local day = nil; - local room = nil; - local component = nil; - local at = nil; - local slash = nil; - local slash2 = nil; - - slash = tmp:find("/"); - if slash then - component = tmp:sub(1, slash - 1); - if tmp:len() > slash then - room = tmp:sub(slash + 1); - slash = room:find("/"); - if slash then - tmp = room; - room = tmp:sub(1, slash - 1); - if tmp:len() > slash then - day = tmp:sub(slash + 1); - slash = day:find("/"); - if slash then - day = day:sub(1, slash - 1); - end - end - end - end - end - - return room, component, day; + local tmp = url:sub(string.len("/muc_log/") + 1); + local day = nil; + local room = nil; + local component = nil; + local at = nil; + local slash = nil; + local slash2 = nil; + + slash = tmp:find("/"); + if slash then + component = tmp:sub(1, slash - 1); + if tmp:len() > slash then + room = tmp:sub(slash + 1); + slash = room:find("/"); + if slash then + tmp = room; + room = tmp:sub(1, slash - 1); + if tmp:len() > slash then + day = tmp:sub(slash + 1); + slash = day:find("/"); + if slash then + day = day:sub(1, slash - 1); + end + end + end + end + end + + return room, component, day; end local function generateComponentListSiteContent() - local components = ""; - for component,muc_host in pairs(muc_hosts or {}) do - components = components .. html.components.bit:gsub("###COMPONENT###", component); - end - if components ~= "" then - return html.components.body:gsub("###COMPONENTS_STUFF###", components); - end + local components = ""; + for component,muc_host in pairs(muc_hosts or {}) do + components = components .. html.components.bit:gsub("###COMPONENT###", component); + end + if components ~= "" then + return html.components.body:gsub("###COMPONENTS_STUFF###", components); + end end local function generateRoomListSiteContent(component) - local rooms = ""; - if prosody.hosts[component] and prosody.hosts[component].muc ~= nil then - for jid, room in pairs(prosody.hosts[component].muc.rooms) do - local node = splitJid(jid); - if not room._data.hidden and node then - rooms = rooms .. html.rooms.bit:gsub("###ROOM###", node):gsub("###COMPONENT###", component); - end - end - if rooms ~= "" then - return html.rooms.body:gsub("###ROOMS_STUFF###", rooms):gsub("###COMPONENT###", component); - end - end + local rooms = ""; + if prosody.hosts[component] and prosody.hosts[component].muc ~= nil then + for jid, room in pairs(prosody.hosts[component].muc.rooms) do + local node = splitJid(jid); + if not room._data.hidden and node then + rooms = rooms .. html.rooms.bit:gsub("###ROOM###", node):gsub("###COMPONENT###", component); + end + end + if rooms ~= "" then + return html.rooms.body:gsub("###ROOMS_STUFF###", rooms):gsub("###COMPONENT###", component); + end + end end -- Calendar stuff @@ -177,668 +177,668 @@ elseif month == 2 and not leapyear then daysCount = 28; elseif month < 8 and month%2 == 1 or - month >= 8 and month%2 == 0 - then - daysCount = 31; + month >= 8 and month%2 == 0 + then + daysCount = 31; + end + return daysCount; end - return daysCount; -end + + local function createMonth(month, year, dayCallback) + local htmlStr = html.month.header; + local days = getDaysForMonth(month, year); + local time = os_time{year=year, month=month, day=1}; + local dow = tostring(os_date("%a", time)) + local title = tostring(os_date("%B", time)); + local weekDays = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"}; + local weekDay = 0; + local weeks = 1; + local logAvailableForMinimumOneDay = false; + + local weekDaysHtml = ""; + for _, tmp in ipairs(weekDays) do + weekDaysHtml = weekDaysHtml .. html.month.weekDay:gsub("###DAY###", tmp) .. "\n"; + end + + htmlStr = htmlStr:gsub("###TITLE###", title):gsub("###WEEKDAYS###", weekDaysHtml); + + for i = 1, 31 do + weekDay = weekDay + 1; + if weekDay == 1 then htmlStr = htmlStr .. "<tr>\n"; end + if i == 1 then + for _, tmp in ipairs(weekDays) do + if dow ~= tmp then + htmlStr = htmlStr .. html.month.emptyDay .. "\n"; + weekDay = weekDay + 1; + else + break; + end + end + end + if i < days + 1 then + local tmp = tostring(i); + if dayCallback ~= nil and dayCallback.callback ~= nil then + tmp = dayCallback.callback(dayCallback.path, i, month, year, dayCallback.room, dayCallback.webPath); + end + if tmp == nil then + tmp = tostring(i); + else + logAvailableForMinimumOneDay = true; + end + htmlStr = htmlStr .. html.month.day:gsub("###DAY###", tmp) .. "\n"; + end + + if i >= days then + break; + end -local function createMonth(month, year, dayCallback) - local htmlStr = html.month.header; - local days = getDaysForMonth(month, year); - local time = os_time{year=year, month=month, day=1}; - local dow = tostring(os_date("%a", time)) - local title = tostring(os_date("%B", time)); - local weekDays = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"}; - local weekDay = 0; - local weeks = 1; - local logAvailableForMinimumOneDay = false; + if weekDay == 7 then + weekDay = 0; + weeks = weeks + 1; + htmlStr = htmlStr .. "</tr>\n"; + end + end + + if weekDay + 1 < 8 or weeks < 6 then + weekDay = weekDay + 1; + if weekDay > 7 then + weekDay = 1; + end + if weekDay == 1 then + weeks = weeks + 1; + end + for y = weeks, 6 do + if weekDay == 1 then + htmlStr = htmlStr .. "<tr>\n"; + end + for i = weekDay, 7 do + htmlStr = htmlStr .. html.month.emptyDay .. "\n"; + end + weekDay = 1 + htmlStr = htmlStr .. "</tr>\n"; + end + end + htmlStr = htmlStr .. html.month.footer; + if logAvailableForMinimumOneDay then + return htmlStr; + end + end - local weekDaysHtml = ""; - for _, tmp in ipairs(weekDays) do - weekDaysHtml = weekDaysHtml .. html.month.weekDay:gsub("###DAY###", tmp) .. "\n"; + local function createYear(year, dayCallback) + local year = year; + local tmp; + if tonumber(year) <= 99 then + year = year + 2000; + end + local htmlStr = ""; + for i=1, 12 do + tmp = createMonth(i, year, dayCallback); + if tmp then + htmlStr = htmlStr .. "<div style='float: left; padding: 5px;'>\n" .. tmp .. "</div>\n"; + end + end + if htmlStr ~= "" then + return "<div name='yearDiv' style='padding: 40px; text-align: center;'>" .. html.year.title:gsub("###YEAR###", tostring(year)) .. htmlStr .. "</div><br style='clear:both;'/> \n"; + end + return ""; + end + + local function perDayCallback(path, day, month, year, room, webPath) + local webPath = webPath or "" + local year = year; + if year > 2000 then + year = year - 2000; + end + local bareDay = str_format("%.02d%.02d%.02d", year, month, day); + room = urlencode(room); + local attributes, err = lfs.attributes(path.."/"..bareDay.."/"..room..".dat") + if attributes ~= nil and attributes.mode == "file" then + local s = html.days.bit; + s = s:gsub("###BARE_DAY###", webPath .. bareDay); + s = s:gsub("###DAY###", day); + return s; + end + return; end - htmlStr = htmlStr:gsub("###TITLE###", title):gsub("###WEEKDAYS###", weekDaysHtml); + local function generateDayListSiteContentByRoom(bareRoomJid) + local days = ""; + local arrDays = {}; + local tmp; + local node, host, resource = splitJid(bareRoomJid); + local path = data_getpath(node, host, datastore); + local room = nil; + local nextRoom = ""; + local previousRoom = ""; + local rooms = ""; + local attributes = nil; + local since = ""; + local to = ""; + local topic = ""; + + path = path:gsub("/[^/]*$", ""); + attributes = lfs.attributes(path); + 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 + local found = 0; + for jid, room in pairs(prosody.hosts[host].muc.rooms) do + local node = splitJid(jid) + if not room._data.hidden and node then + if found == 0 then + previousRoom = node + elseif found == 1 then + nextRoom = node + found = -1 + end + if jid == bareRoomJid then + found = 1 + end + + rooms = rooms .. html.days.rooms.bit:gsub("###ROOM###", node); + end + end + + room = prosody.hosts[host].muc.rooms[bareRoomJid]; + if room._data.hidden then + room = nil + end + end + if attributes ~= nil and room ~= nil then + local first = 1; + local alreadyDoneYears = {}; + local temptime = {day=0, month=0, year=0}; + topic = room._data.subject or "(no subject)" + if topic:len() > 135 then + topic = topic:sub(1, topic:find(" ", 120)) .. " ..." + end + for folder in lfs.dir(path) do + local year, month, day = folder:match("^(%d%d)(%d%d)(%d%d)"); + if year ~= nil and alreadyDoneYears[year] == nil then + temptime.day = tonumber(day) + temptime.month = tonumber(month) + temptime.year = 2000 + tonumber(year) + if first == 1 then + to = tostring(os_date("%B %Y", os_time(temptime))) + first = 0 + end + + since = tostring(os_date("%B %Y", os_time(temptime))) + module:log("debug", "creating overview for: " .. tostring(since)) + days = createYear(year, {callback=perDayCallback, path=path, room=node}) .. days; + alreadyDoneYears[year] = true; + end + end + end + + if days ~= "" then + tmp = html.days.body:gsub("###DAYS_STUFF###", days); + tmp = tmp:gsub("###PREVIOUS_ROOM###", previousRoom == "" and node or previousRoom); + tmp = tmp:gsub("###NEXT_ROOM###", nextRoom == "" and node or nextRoom); + tmp = tmp:gsub("###ROOMS###", rooms); + tmp = tmp:gsub("###ROOMTOPIC###", topic); + tmp = tmp:gsub("###SINCE###", since); + tmp = tmp:gsub("###TO###", to); + return tmp:gsub("###JID###", bareRoomJid); + end + end - for i = 1, 31 do - weekDay = weekDay + 1; - if weekDay == 1 then htmlStr = htmlStr .. "<tr>\n"; end - if i == 1 then - for _, tmp in ipairs(weekDays) do - if dow ~= tmp then - htmlStr = htmlStr .. html.month.emptyDay .. "\n"; - weekDay = weekDay + 1; + local function parseIqStanza(stanza, timeStuff, nick) + local text = nil; + local victim = nil; + if(stanza.attr.type == "set") then + for _,tag in ipairs(stanza) do + if tag.tag == "query" then + for _,item in ipairs(tag) do + if item.tag == "item" and item.attr.nick ~= nil and item.attr.role == 'none' then + victim = item.attr.nick; + for _,reason in ipairs(item) do + if reason.tag == "reason" then + text = reason[1]; + break; + end + end + break; + end + end + break; + end + end + if victim ~= nil then + if text ~= nil then + text = html.day.reason:gsub("###REASON###", htmlEscape(text)); else + text = ""; + end + return html.day.kick:gsub("###TIME_STUFF###", timeStuff):gsub("###VICTIM###", victim):gsub("###REASON_STUFF###", text); + end + end + return; + end + + local function parsePresenceStanza(stanza, timeStuff, nick) + local ret = ""; + local showJoin = "block" + + if config and not config.showJoin then + showJoin = "none"; + end + + if stanza.attr.type == nil then + local showStatus = "block" + if config and not config.showStatus then + showStatus = "none"; + end + local show, status = nil, ""; + local alreadyJoined = false; + for _, tag in ipairs(stanza) do + if tag.tag == "alreadyJoined" then + alreadyJoined = true; + elseif tag.tag == "show" then + show = tag[1]; + elseif tag.tag == "status" and tag[1] ~= nil then + status = tag[1]; + end + end + if alreadyJoined == true then + if show == nil then + show = "online"; + end + ret = html.day.presence.statusChange:gsub("###TIME_STUFF###", timeStuff); + if status ~= "" then + status = html.day.presence.statusText:gsub("###STATUS###", htmlEscape(status)); + end + ret = ret:gsub("###SHOW###", show):gsub("###NICK###", nick):gsub("###SHOWHIDE###", showStatus):gsub("###STATUS_STUFF###", status); + else + ret = html.day.presence.join:gsub("###TIME_STUFF###", timeStuff):gsub("###SHOWHIDE###", showJoin):gsub("###NICK###", nick); + end + elseif stanza.attr.type ~= nil and stanza.attr.type == "unavailable" then + + ret = html.day.presence.leave:gsub("###TIME_STUFF###", timeStuff):gsub("###SHOWHIDE###", showJoin):gsub("###NICK###", nick); + end + return ret; + end + + local function parseMessageStanza(stanza, timeStuff, nick) + local body, title, ret = nil, nil, ""; + + for _,tag in ipairs(stanza) do + if tag.tag == "body" then + body = tag[1]; + if nick ~= nil then + break; + end + elseif tag.tag == "nick" and nick == nil then + nick = htmlEscape(tag[1]); + if body ~= nil or title ~= nil then + break; + end + elseif tag.tag == "subject" then + title = tag[1]; + if nick ~= nil then break; end end end - if i < days + 1 then - local tmp = tostring("<span style='color:#DDDDDD'>"..tostring(i).."</span>"); - if dayCallback ~= nil and dayCallback.callback ~= nil then - tmp = dayCallback.callback(dayCallback.path, i, month, year, dayCallback.room, dayCallback.webPath); + if nick ~= nil and body ~= nil then + body = htmlEscape(body); + local me = body:find("^/me"); + local template = ""; + if not me then + template = html.day.message; + else + template = html.day.messageMe; + body = body:gsub("^/me ", ""); end - if tmp == nil then - tmp = tostring("<span style='color:#DDDDDD'>"..tostring(i).."</span>"); - else - logAvailableForMinimumOneDay = true; - end - htmlStr = htmlStr .. html.month.day:gsub("###DAY###", tmp) .. "\n"; + ret = template:gsub("###TIME_STUFF###", timeStuff):gsub("###NICK###", nick):gsub("###MSG###", body); + elseif nick ~= nil and title ~= nil then + title = htmlEscape(title); + ret = html.day.titleChange:gsub("###TIME_STUFF###", timeStuff):gsub("###NICK###", nick):gsub("###TITLE###", title); end - - if i >= days then - break; - end - - if weekDay == 7 then - weekDay = 0; - weeks = weeks + 1; - htmlStr = htmlStr .. "</tr>\n"; - end + return ret; end - if weekDay + 1 < 8 or weeks < 6 then - weekDay = weekDay + 1; - if weekDay > 7 then - weekDay = 1; - end - if weekDay == 1 then - weeks = weeks + 1; - end - for y = weeks, 6 do - if weekDay == 1 then - htmlStr = htmlStr .. "<tr>\n"; - end - for i = weekDay, 7 do - htmlStr = htmlStr .. html.month.emptyDay .. "\n"; - end - weekDay = 1 - htmlStr = htmlStr .. "</tr>\n"; - end - end - htmlStr = htmlStr .. html.month.footer; - if logAvailableForMinimumOneDay then - return htmlStr; - end -end + local function incrementDay(bare_day) + local year, month, day = bare_day:match("^(%d%d)(%d%d)(%d%d)"); + local leapyear = false; + module:log("debug", tostring(day).."/"..tostring(month).."/"..tostring(year)) + + day = tonumber(day); + month = tonumber(month); + year = tonumber(year); -local function createYear(year, dayCallback) - local year = year; - local tmp; - if tonumber(year) <= 99 then - year = year + 2000; - end - local htmlStr = ""; - for i=1, 12 do - tmp = createMonth(i, year, dayCallback); - if tmp then - htmlStr = htmlStr .. "<div style='float: left; padding: 5px;'>\n" .. tmp .. "</div>\n"; - end - end - if htmlStr ~= "" then - return "<div name='yearDiv' style='padding: 40px; text-align: center;'>" .. html.year.title:gsub("###YEAR###", tostring(year)) .. htmlStr .. "</div><br style='clear:both;'/> \n"; - end - return ""; -end - -local function perDayCallback(path, day, month, year, room, webPath) - local webPath = webPath or "" - local year = year; - if year > 2000 then - year = year - 2000; - end - local bareDay = str_format("%.02d%.02d%.02d", year, month, day); - room = urlencode(room); - local attributes, err = lfs.attributes(path.."/"..bareDay.."/"..room..".dat") - if attributes ~= nil and attributes.mode == "file" then - local s = html.days.bit; - s = s:gsub("###BARE_DAY###", webPath .. bareDay); - s = s:gsub("###DAY###", day); - return s; - end - return; -end + if year%4 == 0 and year%100 == 0 then + if year%400 == 0 then + leapyear = true; + else + leapyear = false; -- turn of the century but not a leapyear + end + elseif year%4 == 0 then + leapyear = true; + end -local function generateDayListSiteContentByRoom(bareRoomJid) - local days = ""; - local arrDays = {}; - local tmp; - local node, host, resource = splitJid(bareRoomJid); - local path = data_getpath(node, host, datastore); - local room = nil; - local nextRoom = ""; - local previousRoom = ""; - local rooms = ""; - local attributes = nil; - local since = ""; - local to = ""; - local topic = ""; - - path = path:gsub("/[^/]*$", ""); - attributes = lfs.attributes(path); - 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 - local found = 0; - for jid, room in pairs(prosody.hosts[host].muc.rooms) do - local node = splitJid(jid) - if not room._data.hidden and node then - if found == 0 then - previousRoom = node - elseif found == 1 then - nextRoom = node - found = -1 - end - if jid == bareRoomJid then - found = 1 - end + if (month == 2 and leapyear and day + 1 > 29) or + (month == 2 and not leapyear and day + 1 > 28) or + (month < 8 and month%2 == 1 and day + 1 > 31) or + (month < 8 and month%2 == 0 and day + 1 > 30) or + (month >= 8 and month%2 == 0 and day + 1 > 31) or + (month >= 8 and month%2 == 1 and day + 1 > 30) + then + if month + 1 > 12 then + year = year + 1; + month = 1; + day = 1; + else + month = month + 1; + day = 1; + end + else + day = day + 1; + end + return strformat("%.02d%.02d%.02d", year, month, day); + end - rooms = rooms .. html.days.rooms.bit:gsub("###ROOM###", node); - end - end + local function findNextDay(bareRoomJid, bare_day) + local node, host, resource = splitJid(bareRoomJid); + local day = incrementDay(bare_day); + local max_trys = 7; - room = prosody.hosts[host].muc.rooms[bareRoomJid]; - if room._data.hidden then - room = nil - end - end - if attributes ~= nil and room ~= nil then - local first = 1; - local alreadyDoneYears = {}; - local temptime = {day=0, month=0, year=0}; - topic = room._data.subject or "(no subject)" - if topic:len() > 135 then - topic = topic:sub(1, topic:find(" ", 120)) .. " ..." - end - for folder in lfs.dir(path) do - local year, month, day = folder:match("^(%d%d)(%d%d)(%d%d)"); - if year ~= nil and alreadyDoneYears[year] == nil then - temptime.day = tonumber(day) - temptime.month = tonumber(month) - temptime.year = 2000 + tonumber(year) - if first == 1 then - to = tostring(os_date("%B %Y", os_time(temptime))) - first = 0 - end + module:log("debug", day); + while(not checkDatastorePathExists(node, host, day, false)) do + max_trys = max_trys - 1; + if max_trys == 0 then + break; + end + day = incrementDay(day); + end + if max_trys == 0 then + return nil; + else + return day; + end + end - since = tostring(os_date("%B %Y", os_time(temptime))) - module:log("debug", "creating overview for: " .. tostring(since)) - days = createYear(year, {callback=perDayCallback, path=path, room=node}) .. days; - alreadyDoneYears[year] = true; - end - end - end - - if days ~= "" then - tmp = html.days.body:gsub("###DAYS_STUFF###", days); - tmp = tmp:gsub("###PREVIOUS_ROOM###", previousRoom == "" and node or previousRoom); - tmp = tmp:gsub("###NEXT_ROOM###", nextRoom == "" and node or nextRoom); - tmp = tmp:gsub("###ROOMS###", rooms); - tmp = tmp:gsub("###ROOMTOPIC###", topic); - tmp = tmp:gsub("###SINCE###", since); - tmp = tmp:gsub("###TO###", to); - return tmp:gsub("###JID###", bareRoomJid); - end -end + local function decrementDay(bare_day) + local year, month, day = bare_day:match("^(%d%d)(%d%d)(%d%d)"); + local leapyear = false; + module:log("debug", tostring(day).."/"..tostring(month).."/"..tostring(year)) + + day = tonumber(day); + month = tonumber(month); + year = tonumber(year); + + if year%4 == 0 and year%100 == 0 then + if year%400 == 0 then + leapyear = true; + else + leapyear = false; -- turn of the century but not a leapyear + end + elseif year%4 == 0 then + leapyear = true; + end -local function parseIqStanza(stanza, timeStuff, nick) - local text = nil; - local victim = nil; - if(stanza.attr.type == "set") then - for _,tag in ipairs(stanza) do - if tag.tag == "query" then - for _,item in ipairs(tag) do - if item.tag == "item" and item.attr.nick ~= nil and tostring(item.attr.role) == 'none' then - victim = item.attr.nick; - for _,reason in ipairs(item) do - if reason.tag == "reason" then - text = reason[1]; - break; - end - end - break; - end - end - break; - end - end - if victim ~= nil then - if text ~= nil then - text = html.day.reason:gsub("###REASON###", htmlEscape(text)); - else - text = ""; - end - return html.day.kick:gsub("###TIME_STUFF###", timeStuff):gsub("###VICTIM###", victim):gsub("###REASON_STUFF###", text); - end - end - return; -end + if day - 1 == 0 then + if month - 1 == 0 then + year = year - 1; + month = 12; + day = 31; + else + month = month - 1; + if (month == 2 and leapyear) then day = 29 + elseif (month == 2 and not leapyear) then day = 28 + elseif (month < 8 and month%2 == 1) or (month >= 8 and month%2 == 0) then day = 31 + else day = 30 + end + end + else + day = day - 1; + end + return strformat("%.02d%.02d%.02d", year, month, day); + end -local function parsePresenceStanza(stanza, timeStuff, nick) - local ret = ""; - local showJoin = "block" - - if config and not config.showJoin then - showJoin = "none"; - end - - if stanza.attr.type == nil then - local showStatus = "block" - if config and not config.showStatus then - showStatus = "none"; - end - local show, status = nil, ""; - local alreadyJoined = false; - for _, tag in ipairs(stanza) do - if tag.tag == "alreadyJoined" then - alreadyJoined = true; - elseif tag.tag == "show" then - show = tag[1]; - elseif tag.tag == "status" and tag[1] ~= nil then - status = tag[1]; - end - end - if alreadyJoined == true then - if show == nil then - show = "online"; - end - ret = html.day.presence.statusChange:gsub("###TIME_STUFF###", timeStuff); - if status ~= "" then - status = html.day.presence.statusText:gsub("###STATUS###", htmlEscape(status)); - end - ret = ret:gsub("###SHOW###", show):gsub("###NICK###", nick):gsub("###SHOWHIDE###", showStatus):gsub("###STATUS_STUFF###", status); - else - ret = html.day.presence.join:gsub("###TIME_STUFF###", timeStuff):gsub("###SHOWHIDE###", showJoin):gsub("###NICK###", nick); - end - elseif stanza.attr.type ~= nil and stanza.attr.type == "unavailable" then - - ret = html.day.presence.leave:gsub("###TIME_STUFF###", timeStuff):gsub("###SHOWHIDE###", showJoin):gsub("###NICK###", nick); - end - return ret; -end + local function findPreviousDay(bareRoomJid, bare_day) + local node, host, resource = splitJid(bareRoomJid); + local day = decrementDay(bare_day); + local max_trys = 7; + module:log("debug", day); + while(not checkDatastorePathExists(node, host, day, false)) do + max_trys = max_trys - 1; + if max_trys == 0 then + break; + end + day = decrementDay(day); + end + if max_trys == 0 then + return nil; + else + return day; + end + end -local function parseMessageStanza(stanza, timeStuff, nick) - local body, title, ret = nil, nil, ""; - - for _,tag in ipairs(stanza) do - if tag.tag == "body" then - body = tag[1]; - if nick ~= nil then - break; - end - elseif tag.tag == "nick" and nick == nil then - nick = htmlEscape(tag[1]); - if body ~= nil or title ~= nil then - break; - end - elseif tag.tag == "subject" then - title = tag[1]; - if nick ~= nil then - break; - end - end - end - if nick ~= nil and body ~= nil then - body = htmlEscape(body); - local me = body:find("^/me"); - local template = ""; - if not me then - template = html.day.message; - else - template = html.day.messageMe; - body = body:gsub("^/me ", ""); - end - ret = template:gsub("###TIME_STUFF###", timeStuff):gsub("###NICK###", nick):gsub("###MSG###", body); - elseif nick ~= nil and title ~= nil then - title = htmlEscape(title); - ret = html.day.titleChange:gsub("###TIME_STUFF###", timeStuff):gsub("###NICK###", nick):gsub("###TITLE###", title); - end - return ret; -end + local function parseDay(bareRoomJid, roomSubject, bare_day) + local ret = ""; + local year; + local month; + local day; + local tmp; + local node, host, resource = splitJid(bareRoomJid); + local year, month, day = bare_day:match("^(%d%d)(%d%d)(%d%d)"); + local previousDay = findPreviousDay(bareRoomJid, bare_day); + local nextDay = findNextDay(bareRoomJid, bare_day); + local temptime = {day=0, month=0, year=0}; + local path = data_getpath(node, host, datastore); + path = path:gsub("/[^/]*$", ""); + local calendar = "" + + if tonumber(year) <= 99 then + year = year + 2000; + end -local function incrementDay(bare_day) - local year, month, day = bare_day:match("^(%d%d)(%d%d)(%d%d)"); - local leapyear = false; - module:log("debug", tostring(day).."/"..tostring(month).."/"..tostring(year)) - - day = tonumber(day); - month = tonumber(month); - year = tonumber(year); - - if year%4 == 0 and year%100 == 0 then - if year%400 == 0 then - leapyear = true; - else - leapyear = false; -- turn of the century but not a leapyear - end - elseif year%4 == 0 then - leapyear = true; - end - - if (month == 2 and leapyear and day + 1 > 29) or - (month == 2 and not leapyear and day + 1 > 28) or - (month < 8 and month%2 == 1 and day + 1 > 31) or - (month < 8 and month%2 == 0 and day + 1 > 30) or - (month >= 8 and month%2 == 0 and day + 1 > 31) or - (month >= 8 and month%2 == 1 and day + 1 > 30) - then - if month + 1 > 12 then - year = year + 1; - month = 1; - day = 1; - else - month = month + 1; - day = 1; - end - else - day = day + 1; - end - return strformat("%.02d%.02d%.02d", year, month, day); -end + temptime.day = tonumber(day) + temptime.month = tonumber(month) + temptime.year = tonumber(year) + calendar = createMonth(temptime.month, temptime.year, {callback=perDayCallback, path=path, room=node, webPath="../"}) or "" + + if bare_day ~= nil then + local data = data_load(node, host, datastore .. "/" .. bare_day); + if data ~= nil then + for i=1, #data, 1 do + local stanza = lom.parse(data[i]); + if stanza ~= nil and stanza.attr ~= nil and stanza.attr.time ~= nil then + local timeStuff = html.day.time:gsub("###TIME###", stanza.attr.time):gsub("###UTC###", stanza.attr.utc or stanza.attr.time); + if stanza[1] ~= nil then + local nick; + local tmp; + + -- grep nick from "from" resource + if stanza[1].attr.from ~= nil then -- presence and messages + nick = htmlEscape(stanza[1].attr.from:match("/(.+)$")); + elseif stanza[1].attr.to ~= nil then -- iq + nick = htmlEscape(stanza[1].attr.to:match("/(.+)$")); + end -local function findNextDay(bareRoomJid, bare_day) - local node, host, resource = splitJid(bareRoomJid); - local day = incrementDay(bare_day); - local max_trys = 7; - - module:log("debug", day); - while(not checkDatastorePathExists(node, host, day, false)) do - max_trys = max_trys - 1; - if max_trys == 0 then - break; - end - day = incrementDay(day); - end - if max_trys == 0 then - return nil; - else - return day; - end -end + if stanza[1].tag == "presence" and nick ~= nil then + tmp = parsePresenceStanza(stanza[1], timeStuff, nick); + elseif stanza[1].tag == "message" then + tmp = parseMessageStanza(stanza[1], timeStuff, nick); + elseif stanza[1].tag == "iq" then + tmp = parseIqStanza(stanza[1], timeStuff, nick); + else + module:log("info", "unknown stanza subtag in log found. room: %s; day: %s", bareRoomJid, year .. "/" .. month .. "/" .. day); + end + if tmp ~= nil then + ret = ret .. tmp + tmp = nil; + end + end + end + end + end + if ret ~= "" then + if nextDay then + nextDay = html.day.dayLink:gsub("###DAY###", nextDay):gsub("###TEXT###", ">") + end + if previousDay then + previousDay = html.day.dayLink:gsub("###DAY###", previousDay):gsub("###TEXT###", "<"); + end + ret = ret:gsub("%%", "%%%%"); + tmp = html.day.body:gsub("###DAY_STUFF###", ret):gsub("###JID###", bareRoomJid); + tmp = tmp:gsub("###CALENDAR###", calendar); + tmp = tmp:gsub("###DATE###", tostring(os_date("%A, %B %d, %Y", os_time(temptime)))); + tmp = tmp:gsub("###TITLE_STUFF###", html.day.title:gsub("###TITLE###", roomSubject)); + tmp = tmp:gsub("###STATUS_CHECKED###", config.showStatus and "checked='checked'" or ""); + tmp = tmp:gsub("###JOIN_CHECKED###", config.showJoin and "checked='checked'" or ""); + tmp = tmp:gsub("###NEXT_LINK###", nextDay or ""); + tmp = tmp:gsub("###PREVIOUS_LINK###", previousDay or ""); -local function decrementDay(bare_day) - local year, month, day = bare_day:match("^(%d%d)(%d%d)(%d%d)"); - local leapyear = false; - module:log("debug", tostring(day).."/"..tostring(month).."/"..tostring(year)) + return tmp; + end + end + end - day = tonumber(day); - month = tonumber(month); - year = tonumber(year); + function handle_request(method, body, request) + local node, host, day = splitUrl(request.url.path); + + node = urldecode(node); - if year%4 == 0 and year%100 == 0 then - if year%400 == 0 then - leapyear = true; - else - leapyear = false; -- turn of the century but not a leapyear - end - elseif year%4 == 0 then - leapyear = true; - end - - if day - 1 == 0 then - if month - 1 == 0 then - year = year - 1; - month = 12; - day = 31; - else - month = month - 1; - if (month == 2 and leapyear) then day = 29 - elseif (month == 2 and not leapyear) then day = 28 - elseif (month < 8 and month%2 == 1) or (month >= 8 and month%2 == 0) then day = 31 - else day = 30 - end - end - else - day = day - 1; - end - return strformat("%.02d%.02d%.02d", year, month, day); -end + if muc_hosts ~= nil and html.doc ~= nil then + if node ~= nil and host ~= nil then + local bare = node .. "@" .. host; + if prosody.hosts[host] ~= nil and prosody.hosts[host].muc ~= nil then + if prosody.hosts[host].muc.rooms[bare] ~= nil then + local room = prosody.hosts[host].muc.rooms[bare]; + if day == nil then + return createDoc(generateDayListSiteContentByRoom(bare)); + else + local subject = "" + if room._data ~= nil and room._data.subject ~= nil then + subject = room._data.subject; + end + return createDoc(parseDay(bare, subject, day)); + end + else + return createDoc(generateRoomListSiteContent(host)); + end + else + return createDoc(generateComponentListSiteContent()); + end + elseif host ~= nil then + return createDoc(generateRoomListSiteContent(host)); + else + return createDoc(generateComponentListSiteContent()); + end + end + return; + end -local function findPreviousDay(bareRoomJid, bare_day) - local node, host, resource = splitJid(bareRoomJid); - local day = decrementDay(bare_day); - local max_trys = 7; - module:log("debug", day); - while(not checkDatastorePathExists(node, host, day, false)) do - max_trys = max_trys - 1; - if max_trys == 0 then - break; - end - day = decrementDay(day); - end - if max_trys == 0 then - return nil; - else - return day; - end -end - -local function parseDay(bareRoomJid, roomSubject, bare_day) - local ret = ""; - local year; - local month; - local day; - local tmp; - local node, host, resource = splitJid(bareRoomJid); - local year, month, day = bare_day:match("^(%d%d)(%d%d)(%d%d)"); - local previousDay = findPreviousDay(bareRoomJid, bare_day); - local nextDay = findNextDay(bareRoomJid, bare_day); - local temptime = {day=0, month=0, year=0}; - local path = data_getpath(node, host, datastore); - path = path:gsub("/[^/]*$", ""); - local calendar = "" - - if tonumber(year) <= 99 then - year = year + 2000; - end + -- Compatibility: Lua-5.1 + function split(str, pat) + local t = {} -- NOTE: use {n = 0} in Lua-5.0 + local fpat = "(.-)" .. pat + local last_end = 1 + local s, e, cap = str:find(fpat, 1) + while s do + if s ~= 1 or cap ~= "" then + table.insert(t,cap) + end + last_end = e+1 + s, e, cap = str:find(fpat, last_end) + end + if last_end <= #str then + cap = str:sub(last_end) + table.insert(t, cap) + end + return t + end - temptime.day = tonumber(day) - temptime.month = tonumber(month) - temptime.year = tonumber(year) - calendar = createMonth(temptime.month, temptime.year, {callback=perDayCallback, path=path, room=node, webPath="../"}) or "" - - if bare_day ~= nil then - local data = data_load(node, host, datastore .. "/" .. bare_day); - if data ~= nil then - for i=1, #data, 1 do - local stanza = lom.parse(data[i]); - if stanza ~= nil and stanza.attr ~= nil and stanza.attr.time ~= nil then - local timeStuff = html.day.time:gsub("###TIME###", stanza.attr.time):gsub("###UTC###", stanza.attr.utc or stanza.attr.time); - if stanza[1] ~= nil then - local nick; - local tmp; - - -- grep nick from "from" resource - if stanza[1].attr.from ~= nil then -- presence and messages - nick = htmlEscape(stanza[1].attr.from:match("/(.+)$")); - elseif stanza[1].attr.to ~= nil then -- iq - nick = htmlEscape(stanza[1].attr.to:match("/(.+)$")); - end - - if stanza[1].tag == "presence" and nick ~= nil then - tmp = parsePresenceStanza(stanza[1], timeStuff, nick); - elseif stanza[1].tag == "message" then - tmp = parseMessageStanza(stanza[1], timeStuff, nick); - elseif stanza[1].tag == "iq" then - tmp = parseIqStanza(stanza[1], timeStuff, nick); - else - module:log("info", "unknown stanza subtag in log found. room: %s; day: %s", bareRoomJid, year .. "/" .. month .. "/" .. day); - end - if tmp ~= nil then - ret = ret .. tmp - tmp = nil; - end - end - end - end - end - if ret ~= "" then - if nextDay then - nextDay = html.day.dayLink:gsub("###DAY###", nextDay):gsub("###TEXT###", ">") - end - if previousDay then - previousDay = html.day.dayLink:gsub("###DAY###", previousDay):gsub("###TEXT###", "<"); - end - ret = ret:gsub("%%", "%%%%"); - tmp = html.day.body:gsub("###DAY_STUFF###", ret):gsub("###JID###", bareRoomJid); - tmp = tmp:gsub("###CALENDAR###", calendar); - tmp = tmp:gsub("###DATE###", tostring(os_date("%A, %B %d, %Y", os_time(temptime)))); - tmp = tmp:gsub("###TITLE_STUFF###", html.day.title:gsub("###TITLE###", roomSubject)); - tmp = tmp:gsub("###STATUS_CHECKED###", config.showStatus and "checked='checked'" or ""); - tmp = tmp:gsub("###JOIN_CHECKED###", config.showJoin and "checked='checked'" or ""); - tmp = tmp:gsub("###NEXT_LINK###", nextDay or ""); - tmp = tmp:gsub("###PREVIOUS_LINK###", previousDay or ""); - - return tmp; - end - end -end + local function assign(arr, content) + local tmp = html; + local idx = nil; + for _,i in ipairs(arr) do + if idx ~= nil then + if tmp[idx] == nil then + tmp[idx] = {}; + end + tmp = tmp[idx]; + end + idx = i; + end + tmp[idx] = content; + end -function handle_request(method, body, request) - local node, host, day = splitUrl(request.url.path); - - node = urldecode(node); + local function readFile(filepath) + local f = assert(io_open(filepath, "r")); + local t = f:read("*all"); + f:close() + return t; + end - if muc_hosts ~= nil and html.doc ~= nil then - if node ~= nil and host ~= nil then - local bare = node .. "@" .. host; - if prosody.hosts[host] ~= nil and prosody.hosts[host].muc ~= nil then - if prosody.hosts[host].muc.rooms[bare] ~= nil then - local room = prosody.hosts[host].muc.rooms[bare]; - if day == nil then - return createDoc(generateDayListSiteContentByRoom(bare)); - else - local subject = "" - if room._data ~= nil and room._data.subject ~= nil then - subject = room._data.subject; - end - return createDoc(parseDay(bare, subject, day)); - end - else - return createDoc(generateRoomListSiteContent(host)); - end - else - return createDoc(generateComponentListSiteContent()); - end - elseif host ~= nil then - return createDoc(generateRoomListSiteContent(host)); - else - return createDoc(generateComponentListSiteContent()); - end - end - return; -end + local function loadTheme(path) + for file in lfs.dir(path) do + if file ~= "." and file ~= ".." then + module:log("debug", "opening theme file: " .. file); + local tmp = split(file:gsub("\.html$", ""), "_"); + local content = readFile(path .. "/" .. file); + assign(tmp, content); + end + end + return true; + end + + function module.load() + config = config_get("*", "core", "muc_log_http") or {}; + if config.showStatus == nil then + config.showStatus = true; + end + if config.showJoin == nil then + config.showJoin = true; + end --- Compatibility: Lua-5.1 -function split(str, pat) - local t = {} -- NOTE: use {n = 0} in Lua-5.0 - local fpat = "(.-)" .. pat - local last_end = 1 - local s, e, cap = str:find(fpat, 1) - while s do - if s ~= 1 or cap ~= "" then - table.insert(t,cap) - end - last_end = e+1 - s, e, cap = str:find(fpat, last_end) - end - if last_end <= #str then - cap = str:sub(last_end) - table.insert(t, cap) - end - return t -end + theme = config.theme or "prosody"; + local themePath = themesParent .. "/" .. tostring(theme); + local attributes, err = lfs.attributes(themePath); + if attributes == nil or attributes.mode ~= "directory" then + module:log("error", "Theme folder of theme \"".. tostring(theme) .. "\" isn't existing. expected Path: " .. themePath); + return false; + end -local function assign(arr, content) - local tmp = html; - local idx = nil; - for _,i in ipairs(arr) do - if idx ~= nil then - if tmp[idx] == nil then - tmp[idx] = {}; - end - tmp = tmp[idx]; - end - idx = i; - end - tmp[idx] = content; -end + -- module:log("debug", (require "util.serialization").serialize(html)); + if(not loadTheme(themePath)) then + module:log("error", "Theme \"".. tostring(theme) .. "\" is missing something."); + return false; + end + -- module:log("debug", (require "util.serialization").serialize(html)); -local function readFile(filepath) - local f = assert(io_open(filepath, "r")); - local t = f:read("*all"); - f:close() - return t; -end - -local function loadTheme(path) - for file in lfs.dir(path) do - if file ~= "." and file ~= ".." then - module:log("debug", "opening theme file: " .. file); - local tmp = split(file:gsub("\.html$", ""), "_"); - local content = readFile(path .. "/" .. file); - assign(tmp, content); - end - end - return true; -end + httpserver.new_from_config({ config.http_port or true }, handle_request, { base = urlBase, ssl = false, port = 5290 }); -function module.load() - config = config_get("*", "core", "muc_log_http") or {}; - if config.showStatus == nil then - config.showStatus = true; - end - if config.showJoin == nil then - config.showJoin = true; - end - - theme = config.theme or "prosody"; - local themePath = themesParent .. "/" .. tostring(theme); - local attributes, err = lfs.attributes(themePath); - if attributes == nil or attributes.mode ~= "directory" then - module:log("error", "Theme folder of theme \"".. tostring(theme) .. "\" isn't existing. expected Path: " .. themePath); - return false; - end - - -- module:log("debug", (require "util.serialization").serialize(html)); - if(not loadTheme(themePath)) then - module:log("error", "Theme \"".. tostring(theme) .. "\" is missing something."); - return false; - end - -- module:log("debug", (require "util.serialization").serialize(html)); + for jid, host in pairs(prosody.hosts) do + if host.muc then + local enabledModules = config_get(jid, "core", "modules_enabled"); + if enabledModules then + for _,mod in ipairs(enabledModules) do + if(mod == "muc_log") then + module:log("debug", "component: %s", tostring(jid)); + muc_hosts[jid] = true; + break; + end + end + end + end + end + module:log("debug", "loaded mod_muc_log_http"); + end - httpserver.new_from_config({ config.http_port or true }, handle_request, { base = urlBase, ssl = false, port = 5290 }); - - for jid, host in pairs(prosody.hosts) do - if host.muc then - local enabledModules = config_get(jid, "core", "modules_enabled"); - if enabledModules then - for _,mod in ipairs(enabledModules) do - if(mod == "muc_log") then - module:log("debug", "component: %s", tostring(jid)); - muc_hosts[jid] = true; - break; - end - end - end - end - end - module:log("debug", "loaded mod_muc_log_http"); -end + function module.unload() + muc_hosts = nil; + module:log("debug", "unloaded mod_muc_log_http"); + end -function module.unload() - muc_hosts = nil; - module:log("debug", "unloaded mod_muc_log_http"); -end - -module:hook("component-activated", function(component, config) - if config.core and config.core.modules_enabled then - for _,mod in ipairs(config.core.modules_enabled) do - if(mod == "muc_log") then - module:log("debug", "component: %s", tostring(component)); - muc_hosts[component] = true; - break; - end - end - end -end); + module:hook("component-activated", function(component, config) + if config.core and config.core.modules_enabled then + for _,mod in ipairs(config.core.modules_enabled) do + if(mod == "muc_log") then + module:log("debug", "component: %s", tostring(component)); + muc_hosts[component] = true; + break; + end + end + end + end);
--- a/mod_muc_log_http/muc_log_http/themes/prosody/day_bann.html Sun Apr 03 22:47:06 2011 +0100 +++ b/mod_muc_log_http/muc_log_http/themes/prosody/day_bann.html Sun Apr 03 22:49:36 2011 +0100 @@ -1,1 +1,1 @@ -###TIME_STUFF###<font class="muc_bann"> *** ###VICTIM### got banned###REASON_STUFF###</font><br /> \ No newline at end of file +###TIME_STUFF###<span class="muc_bann"> *** ###VICTIM### got banned###REASON_STUFF###</span><br /> \ No newline at end of file
--- a/mod_muc_log_http/muc_log_http/themes/prosody/day_body.html Sun Apr 03 22:47:06 2011 +0100 +++ b/mod_muc_log_http/muc_log_http/themes/prosody/day_body.html Sun Apr 03 22:49:36 2011 +0100 @@ -1,17 +1,17 @@ -<div class="title"> - <div class="date">###DATE###</div> - <div class="roomjid">###JID###</div> - <div class="links">(join via <a class="component" href="xmpp:###JID###?join">client</a> / <a class="component" href="http://speeqe.com/room/###JID###/">speeqe</a>)</div> +<div id="title"> + <div id="date">###DATE###</div> + <div id="roomjid">###JID###</div> + <div id="links">(join via <a class="component" href="xmpp:###JID###?join">client</a> / <a class="component" href="http://speeqe.com/room/###JID###/">speeqe</a>)</div> </div> -<div class="calendar"> - <div style="text-align: center"> +<div id="calendar"> + <div id="navigation"> ###PREVIOUS_LINK### <a class="nav" href="../">^</a>###NEXT_LINK### </div> ###CALENDAR### </div> -<div class="topic">###TITLE_STUFF###</div> +<div id="topic">###TITLE_STUFF###</div> <br /> -<input type="checkbox" onclick="showHide('joinLeave')" ###JOIN_CHECKED###/>show/hide joins and leaves</input> -<input type="checkbox" onclick="showHide('status')" ###STATUS_CHECKED###/>show/hide status changes</input> -<input type="checkbox" onclick="javascript:changeTimeDisplay()" />show time in local time, rather than in UTC</input> -<div id="main" style="overflow: auto; border: 2px solid gray; padding: 3px;">###DAY_STUFF###</div> +<input id="toggleJoinLeave" type="checkbox" onclick="showHide('muc_joinLeave_container')" ###JOIN_CHECKED###/><label for="toggleJoinLeave">show/hide joins and leaves</label> +<input id="toggleStatus" type="checkbox" onclick="showHide('muc_statusChange_container')" ###STATUS_CHECKED###/><label for="toggleStatus">show/hide status changes</label> +<input id="toggleUTC" type="checkbox" onclick="changeTimeDisplay()" /><label for="toggleUTC">show time in local time, rather than in UTC</label> +<div id="main">###DAY_STUFF###</div>
--- a/mod_muc_log_http/muc_log_http/themes/prosody/day_kick.html Sun Apr 03 22:47:06 2011 +0100 +++ b/mod_muc_log_http/muc_log_http/themes/prosody/day_kick.html Sun Apr 03 22:49:36 2011 +0100 @@ -1,1 +1,1 @@ -###TIME_STUFF###<font class="muc_kick"> *** ###VICTIM### got kicked###REASON_STUFF###</font><br /> \ No newline at end of file +###TIME_STUFF###<span class="muc_kick"> *** ###VICTIM### got kicked###REASON_STUFF###</span><br /> \ No newline at end of file
--- a/mod_muc_log_http/muc_log_http/themes/prosody/day_message.html Sun Apr 03 22:47:06 2011 +0100 +++ b/mod_muc_log_http/muc_log_http/themes/prosody/day_message.html Sun Apr 03 22:49:36 2011 +0100 @@ -1,1 +1,1 @@ -###TIME_STUFF###<font class="muc_msg_nick"><###NICK###></font> ###MSG###<br /> \ No newline at end of file +###TIME_STUFF###<span class="muc_msg_nick"><###NICK###></span> ###MSG###<br /> \ No newline at end of file
--- a/mod_muc_log_http/muc_log_http/themes/prosody/day_messageMe.html Sun Apr 03 22:47:06 2011 +0100 +++ b/mod_muc_log_http/muc_log_http/themes/prosody/day_messageMe.html Sun Apr 03 22:49:36 2011 +0100 @@ -1,1 +1,1 @@ -###TIME_STUFF###<font class="muc_msg_me">*###NICK### ###MSG###</font><br /> \ No newline at end of file +###TIME_STUFF###<span class="muc_msg_me">*###NICK### ###MSG###</span><br /> \ No newline at end of file
--- a/mod_muc_log_http/muc_log_http/themes/prosody/day_presence_join.html Sun Apr 03 22:47:06 2011 +0100 +++ b/mod_muc_log_http/muc_log_http/themes/prosody/day_presence_join.html Sun Apr 03 22:49:36 2011 +0100 @@ -1,1 +1,1 @@ -<div name="joinLeave" style="display: ###SHOWHIDE###;">###TIME_STUFF###<font class="muc_join"> *** ###NICK### has joined the room</font><br /></div> \ No newline at end of file +<div class="muc_joinLeave_container">###TIME_STUFF###<span class="muc_join"> *** ###NICK### has joined the room</span><br /></div>
--- a/mod_muc_log_http/muc_log_http/themes/prosody/day_presence_leave.html Sun Apr 03 22:47:06 2011 +0100 +++ b/mod_muc_log_http/muc_log_http/themes/prosody/day_presence_leave.html Sun Apr 03 22:49:36 2011 +0100 @@ -1,1 +1,1 @@ -<div name="joinLeave" style="display: ###SHOWHIDE###;">###TIME_STUFF###<font class="muc_leave"> *** ###NICK### has left the room</font><br /></div> \ No newline at end of file +<div class="muc_joinLeave_container">###TIME_STUFF###<span class="muc_leave"> *** ###NICK### has left the room</span><br /></div>
--- a/mod_muc_log_http/muc_log_http/themes/prosody/day_presence_statusChange.html Sun Apr 03 22:47:06 2011 +0100 +++ b/mod_muc_log_http/muc_log_http/themes/prosody/day_presence_statusChange.html Sun Apr 03 22:49:36 2011 +0100 @@ -1,1 +1,1 @@ -<div name="status" style="display: ###SHOWHIDE###;">###TIME_STUFF###<font class="muc_statusChange"> *** ###NICK### shows as "###SHOW###"###STATUS_STUFF###</font><br /></div> \ No newline at end of file +<div class="muc_statusChange_container">###TIME_STUFF###<span class="muc_statusChange"> *** ###NICK### shows as "###SHOW###"###STATUS_STUFF###</span><br /></div>
--- a/mod_muc_log_http/muc_log_http/themes/prosody/day_titleChange.html Sun Apr 03 22:47:06 2011 +0100 +++ b/mod_muc_log_http/muc_log_http/themes/prosody/day_titleChange.html Sun Apr 03 22:49:36 2011 +0100 @@ -1,1 +1,1 @@ -###TIME_STUFF###<font class="muc_titleChange"> *** ###NICK### changed the title to "###TITLE###"</font><br /> \ No newline at end of file +###TIME_STUFF###<span class="muc_titleChange"> *** ###NICK### changed the title to "###TITLE###"</span><br /> \ No newline at end of file
--- a/mod_muc_log_http/muc_log_http/themes/prosody/days_body.html Sun Apr 03 22:47:06 2011 +0100 +++ b/mod_muc_log_http/muc_log_http/themes/prosody/days_body.html Sun Apr 03 22:49:36 2011 +0100 @@ -1,18 +1,18 @@ -<div class="title"> - <div class="date">###SINCE### - ###TO###</div> - <div class="roomjid">###JID###</div> - <div class="links">(join via <a class="component" href="xmpp:###JID###?join">client</a> / <a class="component" href="http://speeqe.com/room/###JID###/">speeqe</a>)</div> +<div id="title"> + <div id="date">###SINCE### - ###TO###</div> + <div id="roomjid">###JID###</div> + <div id="links">(join via <a class="component" href="xmpp:###JID###?join">client</a> / <a class="component" href="http://speeqe.com/room/###JID###/">speeqe</a>)</div> </div> -<div class="calendar"> - <div style="text-align: center"> - <a class="nav" href="../###PREVIOUS_ROOM###"><</a> - <a class="nav" href="..">^</a> - <a class="nav" href="../###NEXT_ROOM###">></a> +<div id="calendar"> + <div id="navigation"> + <a class="nav" href="../###PREVIOUS_ROOM###/"><</a> + <a class="nav" href="../">^</a> + <a class="nav" href="../###NEXT_ROOM###/">></a> </div> - <div class="weekday" style="margin-top: 50px; padding-left: 5px; padding-right: 5px; padding-top: 3px; text-align: center;">List of rooms for this component</div> - <div style="padding-left: 5px; padding-right: 5px; border: 1px solid black;">###ROOMS###</div> + <div class="weekday">List of rooms for this component</div> + <div id="roomList">###ROOMS###</div> </div> <div class="topic">###ROOMTOPIC###</div> -<div id="calender" style="overflow: auto;"> +<div id="main"> ###DAYS_STUFF### </div>
--- a/mod_muc_log_http/muc_log_http/themes/prosody/doc.html Sun Apr 03 22:47:06 2011 +0100 +++ b/mod_muc_log_http/muc_log_http/themes/prosody/doc.html Sun Apr 03 22:49:36 2011 +0100 @@ -30,36 +30,62 @@ } function showHide(name) { - var eles = document.getElementsByName(name); + var eles = document.getElementsByClassName(name); for (var i = 0; i < eles.length; i++) { eles[i].style.display = eles[i].style.display != "none" ? "none" : ""; } } + +/* IE compat: */ +onload=function(){ + if (document.getElementsByClassName == undefined) { + document.getElementsByClassName = function(className) + { + var hasClassName = new RegExp("(?:^|\\s)" + className + "(?:$|\\s)"); + var allElements = document.getElementsByTagName("*"); + var results = []; + + var element; + for (var i = 0; (element = allElements[i]) != null; i++) { + var elementClass = element.className; + if (elementClass && elementClass.indexOf(className) != -1 && hasClassName.test(elementClass)) + results.push(element); + } + + return results; + } + } +} --></script> <style type="text/css"> -<!-- -.title { +#title { border-bottom: #f29b00 solid 3pt; padding-bottom: 3px; width: 100%; color: #000000; font-size: 24px; font-weight: bold; font-family: sans-serif; letter-spacing: 3px; text-decoration: none; margin-bottom: 3pt; } -.title .date { +#date { float: right; } -.title .links { +#links { font-size: 9px; font-family: Verdana; letter-spacing: 1px; } -.topic { +#topic { color: #000000; font-size: 18px; font-family: sans-serif; } -.calendar {float: right; margin-left: 10pt;} +#calendar {float: right; margin-left: 10pt;} +#navigation {text-align: center} +#roomList {padding-left: 5px; padding-right: 5px; border: 1px solid black;} + +#main {overflow: auto; border: 2px solid gray; padding: 3px; margin-top: 1em} + a {color: #6197df; text-decoration: none;} a.nav {color: #6197df; font-family: monospace; letter-spacing: 7px; font-size: 24px; text-decoration: none;} a.log {color: #6197df; text-decoration: none;} a.log_today {color: #f29b00; text-decoration: none;} -.day { font: 12px Verdana; height: 17px; } -.weekday { font: 10px Verdana; height: 17px; color: #FFFFFF; background-color: #000000; } +.day { font: 12px Verdana; height: 17px; color: #BBBBBB} +.weekday { font: 10px Verdana; height: 17px; color: #FFFFFF; background-color: #000000; margin-top: 50px; + padding-left: 5px; padding-right: 5px; padding-top: 3px; text-align: center;} .timestuff {color: #AAAAAA; text-decoration: none;} .muc_join {color: #009900; font-style: italic;} .muc_leave {color: #009900; font-style: italic;} @@ -70,35 +96,18 @@ .muc_bann {color: #009900; font-style: italic;} .muc_msg_nick {color: #0000AA;} .muc_msg_me {color: #0000AA;} -.join_link {font-height: 9px;} .month_title {font: 10pt Verdana;} .year_title {font: bold 16px Verdana;} .footer {margin-top: 20pt; text-align: center;} -//--> + +label {margin-right: 2em} +thead {font: 25pt bold; text-align: center} +tbody {border: solid black 1px;} +img {border: 0px} +body {margin-left: 20pt; margin-right: 20pt;} </style> -<body style="margin-left: 20pt; margin-right: 20pt;"> +<body> ###BODY_STUFF### -<div class="footer"><a href="http://prosody.im"><img alt="Powered by Prosody" src="http://prosody.im/files/powered_by_prosody_80x30.png" border="0"></a></div> +<div class="footer"><a href="http://prosody.im"><img alt="Powered by Prosody" src="http://prosody.im/files/powered_by_prosody_80x30.png"/></a></div> </body> -<script><!-- -window.captureEvents(Event.RESIZE | Event.LOAD); -window.onresize = resize; -window.onload = load; -function load(e) { - resize(e); -} - -function resize(e) { - var ele = document.getElementById("main"); - ele.style.height = window.innerHeight - ele.offsetTop - 100; - - var yearDivs = document.getElemetsByName("yearDiv"); - if(yearDivs) { - for each (var year in yearDivs) { - year.style.width = window.innerWidth - year.style.padding; - } - } -} - ---></script> </html>
--- a/mod_muc_log_http/muc_log_http/themes/prosody/month_header.html Sun Apr 03 22:47:06 2011 +0100 +++ b/mod_muc_log_http/muc_log_http/themes/prosody/month_header.html Sun Apr 03 22:49:36 2011 +0100 @@ -1,4 +1,4 @@ <table rules="groups" cellpadding="5"> -<thead><tr><td colspan="7"><center><H2><font size="2" face="Verdana">###TITLE###</font></H2></center></td></tr></thead> -<tbody style="border: solid black 1px;"> +<thead><tr><td colspan="7">###TITLE###</td></tr></thead> +<tbody> <tr>###WEEKDAYS###</tr>
--- a/mod_muc_log_http/muc_log_http/themes/prosody/year_title.html Sun Apr 03 22:47:06 2011 +0100 +++ b/mod_muc_log_http/muc_log_http/themes/prosody/year_title.html Sun Apr 03 22:49:36 2011 +0100 @@ -1,1 +1,1 @@ -<center><font style="font: bold 16px Verdana;"><a name="###YEAR###">###YEAR###</a></font></center> \ No newline at end of file +<div class=year_title"><a name="###YEAR###">###YEAR###</a></div>