Software /
code /
prosody-modules
File
mod_message_logging/mod_message_logging.lua @ 1204:fc42f8484451
mod_s2s_keysize_policy: Add note about required LuaSec patch
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Sun, 29 Sep 2013 19:11:29 +0200 |
parent | 1007:ba220790a59c |
child | 1343:7dbde05b48a9 |
line wrap: on
line source
module:set_global(); local jid_bare = require "util.jid".bare; local jid_split = require "util.jid".split; local stat, mkdir = require "lfs".attributes, require "lfs".mkdir; -- Get a filesystem-safe string local function fsencode_char(c) return ("%%%02x"):format(c:byte()); end local function fsencode(s) return (s:gsub("[^%w._-@]", fsencode_char):gsub("^%.", "_")); end local log_base_path = module:get_option("message_logging_dir", prosody.paths.data.."/message_logs"); mkdir(log_base_path); local function get_host_path(host) return log_base_path.."/"..fsencode(host); end local function get_user_path(jid) local username, host = jid_split(jid); local base = get_host_path(host)..os.date("/%Y-%m-%d"); if not stat(base) then mkdir(base); end return base.."/"..fsencode(username)..".msglog"; end local open_files_mt = { __index = function (open_files, jid) local f, err = io.open(get_user_path(jid), "a+"); if not f then module:log("error", "Failed to open message log for writing [%s]: %s", jid, err); end rawset(open_files, jid, f); return f; end }; -- [user@host] = filehandle local open_files = setmetatable({}, open_files_mt); function close_open_files() module:log("debug", "Closing all open files"); for jid, filehandle in pairs(open_files) do filehandle:close(); open_files[jid] = nil; end end module:hook_global("logging-reloaded", close_open_files); local function handle_incoming_message(event) local origin, stanza = event.origin, event.stanza; local message_type = stanza.attr.type; if message_type == "error" then return; end local from, to = jid_bare(stanza.attr.from), jid_bare(stanza.attr.to); local body = stanza:get_child("body"); if not body then return; end body = body:get_text(); local f = open_files[to]; if not f then return; end if message_type == "groupchat" then -- Add the nickname from = from.." <"..(select(3, jid_split(stanza.attr.from)) or "")..">"; end body = body:gsub("\n", "\n "); -- Indent newlines f:write("RECV: ", from, ": ", body, "\n"); f:flush(); end local function handle_outgoing_message(event) local origin, stanza = event.origin, event.stanza; local message_type = stanza.attr.type; if message_type == "error" or message_type == "groupchat" then return; end local from, to = jid_bare(stanza.attr.from), jid_bare(stanza.attr.to); local body = stanza:get_child("body"); if not body then return; end body = body:get_text(); local f = open_files[from]; if not f then return; end body = body:gsub("\n", "\n "); -- Indent newlines f:write("SEND: ", to, ": ", body, "\n"); f:flush(); end function module.add_host(module) local host_base_path = get_host_path(module.host); if not stat(host_base_path) then mkdir(host_base_path); end module:hook("message/bare", handle_incoming_message, 1); module:hook("message/full", handle_incoming_message, 1); module:hook("pre-message/bare", handle_outgoing_message, 1); module:hook("pre-message/full", handle_outgoing_message, 1); module:hook("pre-message/host", handle_outgoing_message, 1); end function module.command(arg) local command = table.remove(arg, 1); if command == "path" then print(get_user_path(arg[1])); else io.stderr:write("Unrecognised command: ", command); return 1; end return 0; end function module.save() return { open_files = open_files }; end function module.restore(saved) open_files = setmetatable(saved.open_files or {}, open_files_mt); end