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("<", "&lt;");
-		t = t:gsub(">", "&gt;");
-		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("<", "&lt;");
+        t = t:gsub(">", "&gt;");
+        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###", "&gt;")
+                    end
+                    if previousDay then
+                        previousDay = html.day.dayLink:gsub("###DAY###", previousDay):gsub("###TEXT###", "&lt;");
+                    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###", "&gt;")
-			end
-			if previousDay then
-				previousDay = html.day.dayLink:gsub("###DAY###", previousDay):gsub("###TEXT###", "&lt;");
-			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>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-<input type="checkbox" onclick="showHide('status')" ###STATUS_CHECKED###/>show/hide status changes</input>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
-<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">&lt;###NICK###&gt;</font> ###MSG###<br />
\ No newline at end of file
+###TIME_STUFF###<span class="muc_msg_nick">&lt;###NICK###&gt;</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###">&lt;</a>
-		<a class="nav" href="..">^</a>
-		<a class="nav" href="../###NEXT_ROOM###">&gt;</a>
+<div id="calendar">
+	<div id="navigation">
+		<a class="nav" href="../###PREVIOUS_ROOM###/">&lt;</a>
+		<a class="nav" href="../">^</a>
+		<a class="nav" href="../###NEXT_ROOM###/">&gt;</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>