Software /
code /
prosody-modules
Diff
mod_archive_muc/mod_archive_muc.lua @ 237:d900be0dee3e
mod_archive: minor fix;
mod_archive_muc: added new module mod_archive_muc; init commit; workable, not fully tested.
author | shinysky<shinysky1986(AT)gmail.com> |
---|---|
date | Mon, 09 Aug 2010 18:45:51 +0800 |
child | 238:5343b3ebaffb |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mod_archive_muc/mod_archive_muc.lua Mon Aug 09 18:45:51 2010 +0800 @@ -0,0 +1,189 @@ +-- Prosody IM +-- Copyright (C) 2010 Dai Zhiwei +-- +-- This project is MIT/X11 licensed. Please see the +-- COPYING file in the source package for more information. +-- + +local st = require "util.stanza"; +local dm = require "util.datamanager"; +local jid = require "util.jid"; +local datetime = require "util.datetime"; + +local PREFS_DIR = "archive_muc_prefs"; +local ARCHIVE_DIR = "archive_muc"; + +local HOST = 'localhost'; + +local AUTO_ARCHIVING_ENABLED = true; + +module:add_feature("urn:xmpp:archive#preferences"); +module:add_feature("urn:xmpp:archive#management"); + +------------------------------------------------------------ +-- Utils +------------------------------------------------------------ +local function load_prefs(node, host) + return st.deserialize(dm.load(node, host, PREFS_DIR)); +end + +local function store_prefs(data, node, host) + dm.store(node, host, PREFS_DIR, st.preserialize(data)); +end + +local function date_time(localtime) + return datetime.datetime(localtime); +end + +local function match_jid(rule, id) + return not rule or jid.compare(id, rule); +end + +local function is_earlier(start, coll_start) + return not start or start <= coll_start; +end + +local function is_later(endtime, coll_start) + return not endtime or endtime >= coll_start; +end + +------------------------------------------------------------ +-- Preferences +------------------------------------------------------------ +local function preferences_handler(event) + local origin, stanza = event.origin, event.stanza; + module:log("debug", "-- Enter muc preferences_handler()"); + module:log("debug", "-- muc pref:\n%s", tostring(stanza)); + if stanza.attr.type == "get" then + local data = load_prefs(origin.username, origin.host); + if data then + origin.send(st.reply(stanza):add_child(data)); + else + origin.send(st.reply(stanza)); + end + elseif stanza.attr.type == "set" then + local node, host = origin.username, origin.host; + if stanza.tags[1] and stanza.tags[1].name == 'prefs' then + store_prefs(stanza.tags[1], node, host); + origin.send(st.reply(stanza)); + local user = bare_sessions[node.."@"..host]; + local push = st.iq({type="set"}); + push:add_child(stanza.tags[1]); + for _, res in pairs(user and user.sessions or NULL) do -- broadcast to all resources + if res.presence then -- to resource + push.attr.to = res.full_jid; + res.send(push); + end + end + end + end + return true; +end + +------------------------------------------------------------ +-- Archive Management +------------------------------------------------------------ +local function management_handler(event) + module:log("debug", "-- Enter muc management_handler()"); + local origin, stanza = event.origin, event.stanza; + local node, host = origin.username, origin.host; + local data = dm.list_load(node, host, ARCHIVE_DIR); + local elem = stanza.tags[1]; + local resset = {} + if data then + for i = #data, 1, -1 do + local forwarded = st.deserialize(data[i]); + local res = (match_jid(elem.attr["with"], forwarded.tags[2].attr.from) + or match_jid(elem.attr["with"], forwarded.tags[2].attr.to)) + and is_earlier(elem.attr["start"], forwarded.tags[1].attr["stamp"]) + and is_later(elem.attr["end"], forwarded.tags[1].attr["stamp"]); + if res then + table.insert(resset, forwarded); + end + end + for i = #resset, 1, -1 do + local res = st.message({to = stanza.attr.from, id=st.new_id()}); + res:add_child(resset[i]); + origin.send(res); + end + end + origin.send(st.reply(stanza)); + return true; +end + +------------------------------------------------------------ +-- Message Handler +------------------------------------------------------------ +local function is_in(list, jid) + for _,v in ipairs(list) do + if match_jid(v:get_text(), jid) then -- JID Matching + return true; + end + end + return false; +end + +local function is_in_roster(node, host, jid) + -- TODO + return true; +end + +local function apply_pref(node, host, jid) + local pref = load_prefs(node, host); + if not pref then + return AUTO_ARCHIVING_ENABLED; + end + local always = pref:child_with_name('always'); + if always and is_in(always, jid) then + return true; + end + local never = pref:child_with_name('never'); + if never and is_in(never, jid) then + return false; + end + local default = pref.attr['default']; + if default == 'roster' then + return is_in_roster(node, host, jid); + elseif default == 'always' then + return true; + elseif default == 'never' then + return false; + end + return AUTO_ARCHIVING_ENABLED; +end + +local function store_msg(msg, node, host) + local forwarded = st.stanza('forwarded', {xmlns='urn:xmpp:forward:tmp'}); + forwarded:tag('delay', {xmlns='urn:xmpp:delay',stamp=date_time()}):up(); + forwarded:add_child(msg); + dm.list_append(node, host, ARCHIVE_DIR, st.preserialize(forwarded)); +end + +local function msg_handler(data) + module:log("debug", "-- Enter muc msg_handler()"); + local origin, stanza = data.origin, data.stanza; + local body = stanza:child_with_name("body"); + if body then + local from_node, from_host = jid.split(stanza.attr.from); + local to_node, to_host = jid.split(stanza.attr.to); + -- FIXME only archive messages of users on this host + if from_host == HOST and apply_pref(from_node, from_host, stanza.attr.to) then + store_msg(stanza, from_node, from_host); + end + if to_host == HOST and apply_pref(to_node, to_host, stanza.attr.from) then + store_msg(stanza, to_node, to_host); + end + end + + return nil; +end + +-- Preferences +module:hook("iq/self/urn:xmpp:archive#preferences:prefs", preferences_handler); +-- Archive management +module:hook("iq/self/urn:xmpp:archive#management:query", management_handler); + +module:hook("message/full", msg_handler, 20); +module:hook("message/bare", msg_handler, 20); + +-- TODO prefs: [1] = "\n ";