changeset 952:ef2253a7858d

mod_archive, mod_archive_muc: Remove from repo, as longstanding bugs are causing problems
author Matthew Wild <mwild1@gmail.com>
date Wed, 03 Apr 2013 18:59:10 +0100
parents ef54ae817689
children 2c38d7d8b332
files mod_archive/mod_archive.lua mod_archive_muc/mod_archive_muc.lua
diffstat 2 files changed, 0 insertions(+), 994 deletions(-) [+]
line wrap: on
line diff
--- a/mod_archive/mod_archive.lua	Wed Apr 03 18:49:27 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,800 +0,0 @@
--- 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 um = require "core.usermanager";
-
-local PREFS_DIR = "archive_prefs";
-local ARCHIVE_DIR = "archive";
-local xmlns_rsm = "http://jabber.org/protocol/rsm";
-
-local DEFAULT_MAX = module:get_option_number("default_max", 100);
-local FORCE_ARCHIVING = module:get_option_boolean("force_archiving", false);
-local AUTO_ARCHIVING_ENABLED = module:get_option_boolean("auto_archiving_enabled", true);
-
-module:add_feature("urn:xmpp:archive");
-module:add_feature("urn:xmpp:archive:auto");
-module:add_feature("urn:xmpp:archive:manage");
-module:add_feature("urn:xmpp:archive:manual");
-module:add_feature("urn:xmpp:archive:pref");
-module:add_feature("http://jabber.org/protocol/rsm");
-
-------------------------------------------------------------
--- 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 date_time = datetime.datetime;
-
-local function date_parse(s)
-	local year, month, day, hour, min, sec = s:match("(....)-?(..)-?(..)T(..):(..):(..)Z");
-	return os.time({year=year, month=month, day=day, hour=hour, min=min, sec=sec});
-end
-
-local function list_reverse(list)
-  local t, n = {}, #list
-  for i = 1, n do t[i] = list[n-i+1] end -- reverse
-  for i = 1, n do list[i] = t[i] end -- copy back
-end
-
-local function list_insert(node, host, collection)
-	local data = dm.list_load(node, host, ARCHIVE_DIR);
-    if data then
-        local s, e = 1, #data;
-        while true do
-            local c = st.deserialize(data[s]);
-            if collection.attr["start"] >= c.attr["start"] then
-                table.insert(data, s, collection);
-                break;
-            end
-            c = st.deserialize(data[e]);
-            if collection.attr["start"] <= c.attr["start"] then
-                table.insert(data, e+1, collection);
-                break;
-            end
-            local m = math.floor((s + e) / 2);
-            c = st.deserialize(data[m]);
-            if collection.attr["start"] > c.attr["start"] then
-                e = m - 1;
-            elseif collection.attr["start"] < c.attr["start"] then
-                s = m + 1;
-            else
-                table.insert(data, m, collection);
-                break;
-            end
-        end
-        dm.list_store(node, host, ARCHIVE_DIR, st.preserialize(data));
-    else
-        dm.list_append(node, host, ARCHIVE_DIR, st.preserialize(collection));
-    end
-end
-
-local function store_msg(msg, node, host, isfrom)
-    local body = msg:child_with_name("body");
-    local thread = msg:child_with_name("thread");
-	local data = dm.list_load(node, host, ARCHIVE_DIR);
-    local tag = isfrom and "from" or "to";
-    local with = isfrom and msg.attr.from or msg.attr.to;
-    local utc_datetime = date_time();
-    local utc_secs = date_parse(utc_datetime);
-    if data then
-        -- The collection list are in REVERSE chronological order 
-        for k, v in ipairs(data) do
-            local collection = st.deserialize(v);
-            local do_save = function()
-                local dt = 1;
-                for i = #collection, 1, -1 do
-                    local s = collection[i].attr["utc_secs"];
-                    if s then
-                        dt = os.difftime(utc_secs, tonumber(s));
-                        break;
-                    end
-                end
-                collection:tag(tag, {secs=dt, utc_secs=utc_secs}):add_child(body);
-                local ver = tonumber(collection.attr["version"]) + 1;
-                collection.attr["version"] = tostring(ver);
-                collection.attr["access"] = utc_datetime;
-                data[k] = collection;
-                dm.list_store(node, host, ARCHIVE_DIR, st.preserialize(data));
-            end
-            if thread then
-                if collection.attr["thread"] == thread:get_text() then
-                    do_save();
-                    return;
-                end
-            else
-                local dt = os.difftime(utc_secs, date_parse(collection.attr["start"]));
-                if dt >= 14400 then break end
-                if collection.attr["with"] == with then -- JID matching?
-                    do_save();
-                    return;
-                end
-            end
-        end
-    end
-    -- not found, create new collection
-    local collection = st.stanza('chat', {with=with, start=utc_datetime, thread=thread and thread:get_text() or nil, version='0', access=utc_datetime});
-    collection:tag(tag, {secs='0', utc_secs=utc_secs}):add_child(body);
-    list_insert(node, host, collection);
-end
-
-local function save_result(collection)
-    local save = st.stanza('save', {xmlns='urn:xmpp:archive'});
-    local chat = st.stanza('chat', collection.attr);
-    save:add_child(chat);
-    return save;
-end 
-
-local function gen_uid(c)
-    return c.attr["start"] .. c.attr["with"];
-end
-
-local function tobool(s)
-    if not s then return nil; end
-    s = s:lower();
-    if s == 'true' or s == '1' then
-        return true;
-    elseif s == 'false' or s == '0' then
-        return false;
-    else
-        return nil;
-    end
-end
-
-------------------------------------------------------------
--- Preferences
-------------------------------------------------------------
-local function preferences_handler(event)
-    local origin, stanza = event.origin, event.stanza;
-    module:log("debug", "-- Enter preferences_handler()");
-    module:log("debug", "-- 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
-            local reply = st.reply(stanza):tag('pref', {xmlns='urn:xmpp:archive'});
-            reply:tag('default', {otr='concede', save='false', unset='true'}):up();
-            reply:tag('method', {type='auto', use='concede'}):up();
-            reply:tag('method', {type='local', use='concede'}):up();
-            reply:tag('method', {type='manual', use='concede'}):up();
-            reply:tag('auto', {save='false'}):up();
-            origin.send(reply);
-        end
-    elseif stanza.attr.type == "set" then
-        local node, host = origin.username, origin.host;
-        local data = load_prefs(node, host);
-        if not data then
-            data = st.stanza('pref', {xmlns='urn:xmpp:archive'});
-            data:tag('default', {otr='concede', save='false'}):up();
-            data:tag('method', {type='auto', use='concede'}):up();
-            data:tag('method', {type='local', use='concede'}):up();
-            data:tag('method', {type='manual', use='concede'}):up();
-            data:tag('auto', {save='false'}):up();
-        end
-        local elem = stanza.tags[1].tags[1]; -- iq:pref:xxx
-        if not elem then return false end
-        -- "default" | "item" | "session" | "method"
-        elem.attr["xmlns"] = nil; -- TODO why there is an extra xmlns attr?
-        if elem.name == "default" then
-            local setting = data:child_with_name(elem.name)
-            for k, v in pairs(elem.attr) do
-                setting.attr[k] = v;
-            end
-            -- setting.attr["unset"] = nil
-        elseif elem.name == "item" then
-            local found = false;
-            for child in data:children() do
-                if child.name == elem.name and child.attr["jid"] == elem.attr["jid"] then
-                    for k, v in pairs(elem.attr) do
-                        child.attr[k] = v;
-                    end
-                    found = true;
-                    break;
-                end
-            end
-            if not found then
-                data:tag(elem.name, elem.attr):up();
-            end
-        elseif elem.name == "session" then
-            local found = false;
-            for child in data:children() do
-                if child.name == elem.name and child.attr["thread"] == elem.attr["thread"] then
-                    for k, v in pairs(elem.attr) do
-                        child.attr[k] = v;
-                    end
-                    found = true;
-                    break;
-                end
-            end
-            if not found then
-                data:tag(elem.name, elem.attr):up();
-            end
-        elseif elem.name == "method" then
-            local newpref = stanza.tags[1]; -- iq:pref
-            for _, e in ipairs(newpref.tags) do
-                -- if e.name ~= "method" then continue end
-                local found = false;
-                for child in data:children() do
-                    if child.name == "method" and child.attr["type"] == e.attr["type"] then
-                        child.attr["use"] = e.attr["use"];
-                        found = true;
-                        break;
-                    end
-                end
-                if not found then
-                    data:tag(e.name, e.attr):up();
-                end
-            end
-        end
-        store_prefs(data, node, host);
-        origin.send(st.reply(stanza));
-        local user = bare_sessions[node.."@"..host];
-        local push = st.iq({type="set"});
-        push = push:tag('pref', {xmlns='urn:xmpp:archive'});
-        if elem.name == "method" then
-            for child in data:children() do
-                if child.name == "method" then
-                    push:add_child(child);
-                end
-            end
-        else
-            push:add_child(elem);
-        end
-        push = push:up();
-        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
-    return true;
-end
-
-local function itemremove_handler(event)
-    -- TODO use 'assert' to check incoming stanza?
-    -- or use pcall() to catch exceptions?
-    local origin, stanza = event.origin, event.stanza;
-    if stanza.attr.type ~= "set" then
-        return false;
-    end
-    local elem = stanza.tags[1].tags[1];
-    if not elem or elem.name ~= "item" then
-        return false;
-    end
-    local node, host = origin.username, origin.host;
-    local data = load_prefs(node, host);
-    if not data then
-        return false;
-    end
-    for i, child in ipairs(data) do
-        if child.name == "item" and child.attr["jid"] == elem.attr["jid"] then
-            table.remove(data, i)
-            break;
-        end
-    end
-    store_prefs(data, node, host);
-    origin.send(st.reply(stanza));
-    return true;
-end
-
-local function sessionremove_handler(event)
-    local origin, stanza = event.origin, event.stanza;
-    if stanza.attr.type ~= "set" then
-        return false;
-    end
-    local elem = stanza.tags[1].tags[1];
-    if not elem or elem.name ~= "session" then
-        return false;
-    end
-    local node, host = origin.username, origin.host;
-    local data = load_prefs(node, host);
-    if not data then
-        return false;
-    end
-    for i, child in ipairs(data) do
-        if child.name == "session" and child.attr["thread"] == elem.attr["thread"] then
-            table.remove(data, i)
-            break;
-        end
-    end
-    store_prefs(data, node, host);
-    origin.send(st.reply(stanza));
-    return true;
-end
-
-local function auto_handler(event)
-    -- event.origin.send(st.error_reply(event.stanza, "cancel", "feature-not-implemented"));
-    local origin, stanza = event.origin, event.stanza;
-    if stanza.attr.type ~= "set" then
-        return false;
-    end
-    local elem = stanza.tags[1];
-    local node, host = origin.username, origin.host;
-    local data = load_prefs(node, host);
-    if not data then -- TODO create new pref?
-        return false;
-    end
-    local setting = data:child_with_name(elem.name)
-    for k, v in pairs(elem.attr) do
-        setting.attr[k] = v;
-    end
-    store_prefs(data, node, host);
-    origin.send(st.reply(stanza));
-    return true;
-end
-
-------------------------------------------------------------
--- Manual Archiving
-------------------------------------------------------------
-local function save_handler(event)
-    local origin, stanza = event.origin, event.stanza;
-    if stanza.attr.type ~= "set" then
-        return false;
-    end
-    local elem = stanza.tags[1].tags[1];
-    if not elem or elem.name ~= "chat" then
-        return false;
-    end
-    local node, host = origin.username, origin.host;
-	local data = dm.list_load(node, host, ARCHIVE_DIR);
-    if data then
-        for k, v in ipairs(data) do
-            local collection = st.deserialize(v);
-            if collection.attr["with"] == elem.attr["with"]
-                and collection.attr["start"] == elem.attr["start"] then
-                -- TODO check if there're duplicates
-                for newchild in elem:children() do
-                    if type(newchild) == "table" then
-                        if newchild.name == "from" or newchild.name == "to" then
-                            collection:add_child(newchild);
-                        elseif newchild.name == "note" or newchild.name == "previous"
-                            or newchild.name == "next" or newchild.name == "x" then
-                            local found = false;
-                            for i, c in ipairs(collection) do
-                                if c.name == newchild.name then
-                                    found = true;
-                                    collection[i] = newchild;
-                                    break;
-                                end
-                            end
-                            if not found then
-                                collection:add_child(newchild);
-                            end
-                        end
-                    end
-                end
-                local ver = tonumber(collection.attr["version"]) + 1;
-                collection.attr["version"] = tostring(ver);
-                collection.attr["subject"] = elem.attr["subject"];
-                collection.attr["access"] = date_time();
-                origin.send(st.reply(stanza):add_child(save_result(collection)));
-                data[k] = collection;
-                dm.list_store(node, host, ARCHIVE_DIR, st.preserialize(data));
-                return true;
-            end
-        end
-    end
-    -- not found, create new collection
-    elem.attr["version"] = "0";
-    elem.attr["access"] = date_time();
-    origin.send(st.reply(stanza):add_child(save_result(elem)));
-    -- TODO check if elem is valid(?)
-    list_insert(node, host, elem);
-    -- TODO unsuccessful reply
-    return true;
-end
-
-------------------------------------------------------------
--- Archive Management
-------------------------------------------------------------
-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
-
-local function find_coll(resset, uid)
-    for i, c in ipairs(resset) do
-        if gen_uid(c) == uid then
-            return i;
-        end
-    end
-    return nil;
-end
-
-local function list_handler(event)
-    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 k, v in ipairs(data) do
-            local collection = st.deserialize(v);
-            if collection[1] then -- has children(not deleted)
-                local res = match_jid(elem.attr["with"], collection.attr["with"]);
-                res = res and is_earlier(elem.attr["start"], collection.attr["start"]);
-                res = res and is_later(elem.attr["end"], collection.attr["start"]);
-                if res then
-                    table.insert(resset, collection);
-                end
-            end
-        end
-    end
-    local reply = st.reply(stanza):tag('list', {xmlns='urn:xmpp:archive'});
-    local count = table.getn(resset);
-    if count > 0 then
-        list_reverse(resset);
-        local s, e = 1, 1+DEFAULT_MAX;
-        local rsmset = elem:child_with_name("set")
-        if rsmset then
-            local max = elem.tags[1]:child_with_name("max");
-            if max then
-                max = tonumber(max:get_text()) or DEFAULT_MAX;
-            else max = DEFAULT_MAX; end
-            e = 1 + max
-            local after = elem.tags[1]:child_with_name("after");
-            local before = elem.tags[1]:child_with_name("before");
-            local index = elem.tags[1]:child_with_name("index");
-            if after then
-                after = after:get_text();
-                s = find_coll(resset, after);
-                if not s then -- not found
-                    origin.send(st.error_reply(stanza, "cancel", "item-not-found"));
-                    return true;
-                end
-                s = s + 1;
-                e = s + max;
-            elseif before then
-                before = before:get_text();
-                if not before or before == '' then -- the last page
-                    e = count + 1;
-                    s = e - max;
-                else
-                    e = find_coll(resset, before);
-                    if not e then -- not found
-                        origin.send(st.error_reply(stanza, "cancel", "item-not-found"));
-                        return true;
-                    end
-                    s = e - max;
-                end
-            elseif index then
-                s = tonumber(index:get_text()) + 1; -- 0-based
-                e = s + max;
-            end
-        end
-        if s < 1 then s = 1; end
-        if e > count + 1 then e = count + 1; end
-        for i = s, e-1 do
-            reply:add_child(st.stanza('chat', resset[i].attr));
-        end
-        local set = st.stanza('set', {xmlns = xmlns_rsm});
-        if s <= e-1 then
-            set:tag('first', {index=s-1}):text(gen_uid(resset[s])):up()
-               :tag('last'):text(gen_uid(resset[e-1])):up();
-        end
-        set:tag('count'):text(tostring(count)):up();
-        reply:add_child(set);
-    end
-    origin.send(reply);
-    return true;
-end
-
-local function retrieve_handler(event)
-    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 collection = nil;
-    if data then
-        for k, v in ipairs(data) do
-            local c = st.deserialize(v);
-            if c[1] -- not deleted
-                and c.attr["with"] == elem.attr["with"]
-                and c.attr["start"] == elem.attr["start"] then
-                collection = c;
-                break;
-            end
-        end
-    end
-    if not collection then
-        -- TODO code=404
-        origin.send(st.error_reply(stanza, "cancel", "item-not-found"));
-        return true;
-    end
-    local resset = {}
-    for i, e in ipairs(collection) do
-        if e.name == "from" or e.name == "to" then
-            table.insert(resset, e);
-        end
-    end
-    collection.attr['xmlns'] = 'urn:xmpp:archive';
-    local reply = st.reply(stanza):tag('chat', collection.attr);
-    local count = table.getn(resset);
-    if count > 0 then
-        local s, e = 1, 1+DEFAULT_MAX;
-        local rsmset = elem:child_with_name("set")
-        if rsmset then
-            local max = elem.tags[1]:child_with_name("max");
-            if max then
-                max = tonumber(max:get_text()) or DEFAULT_MAX;
-            else max = DEFAULT_MAX; end
-            e = 1+max
-            local after = elem.tags[1]:child_with_name("after");
-            local before = elem.tags[1]:child_with_name("before");
-            local index = elem.tags[1]:child_with_name("index");
-            --local s, e = 1, 1+max;
-            if after then
-                after = tonumber(after:get_text());
-                if not after or after < 1 or after > count then -- not found
-                    origin.send(st.error_reply(stanza, "cancel", "item-not-found"));
-                    return true;
-                end
-                s = after + 1;
-                e = s + max;
-            elseif before then
-                before = tonumber(before:get_text());
-                if not before then -- the last page
-                    e = count + 1;
-                    s = e - max;
-                elseif before < 1 or before > count then
-                    origin.send(st.error_reply(stanza, "cancel", "item-not-found"));
-                    return true;
-                else
-                    e = before;
-                    s = e - max;
-                end
-            elseif index then
-                s = tonumber(index:get_text()) + 1; -- 0-based
-                e = s + max;
-            end
-        end
-        if s < 1 then s = 1; end
-        if e > count + 1 then e = count + 1; end
-        for i = s, e-1 do
-            reply:add_child(resset[i]);
-        end
-        local set = st.stanza('set', {xmlns = xmlns_rsm});
-        if s <= e-1 then
-            set:tag('first', {index=s-1}):text(tostring(s)):up()
-               :tag('last'):text(tostring(e-1)):up();
-        end
-        set:tag('count'):text(tostring(count)):up();
-        reply:add_child(set);
-    end
-    origin.send(reply);
-    return true;
-end
-
-local function remove_handler(event)
-    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];
-    if data then
-        local count = table.getn(data);
-        local found = false;
-        for i = count, 1, -1 do
-            local collection = st.deserialize(data[i]);
-            if collection[1] then -- has children(not deleted)
-                local res = match_jid(elem.attr["with"], collection.attr["with"]);
-                res = res and is_earlier(elem.attr["start"], collection.attr["start"]);
-                res = res and is_later(elem.attr["end"], collection.attr["start"]);
-                if res then
-                    -- table.remove(data, i);
-                    local temp = st.stanza('chat', collection.attr);
-                    temp.attr["access"] = date_time();
-                    data[i] = temp;
-                    found = true;
-                end
-            end
-        end
-        if found then
-            dm.list_store(node, host, ARCHIVE_DIR, st.preserialize(data));
-        else
-            origin.send(st.error_reply(stanza, "cancel", "item-not-found"));
-            return true;
-        end
-    end
-    origin.send(st.reply(stanza));
-    return true;
-end
-
-------------------------------------------------------------
--- Replication
-------------------------------------------------------------
-local function modified_handler(event)
-    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 k, v in ipairs(data) do
-            local collection = st.deserialize(v);
-            local res = is_earlier(elem.attr["start"], collection.attr["access"]);
-            if res then
-                table.insert(resset, collection);
-            end
-        end
-    end
-    local reply = st.reply(stanza):tag('modified', {xmlns='urn:xmpp:archive'});
-    local count = table.getn(resset);
-    if count > 0 then
-        list_reverse(resset);
-        local max = elem.tags[1]:child_with_name("max");
-        if max then
-            max = tonumber(max:get_text()) or DEFAULT_MAX;
-        else max = DEFAULT_MAX; end
-        local after = elem.tags[1]:child_with_name("after");
-        local before = elem.tags[1]:child_with_name("before");
-        local index = elem.tags[1]:child_with_name("index");
-        local s, e = 1, 1+max;
-        if after then
-            after = after:get_text();
-            s = find_coll(resset, after);
-            if not s then -- not found
-                origin.send(st.error_reply(stanza, "cancel", "item-not-found"));
-                return true;
-            end
-            s = s + 1;
-            e = s + max;
-        elseif before then
-            before = before:get_text();
-            if not before or before == '' then -- the last page
-                e = count + 1;
-                s = e - max;
-            else
-                e = find_coll(resset, before);
-                if not e then -- not found
-                    origin.send(st.error_reply(stanza, "cancel", "item-not-found"));
-                    return true;
-                end
-                s = e - max;
-            end
-        elseif index then
-            s = tonumber(index:get_text()) + 1; -- 0-based
-            e = s + max;
-        end
-        if s < 1 then s = 1; end
-        if e > count + 1 then e = count + 1; end
-        for i = s, e-1 do
-            if resset[i][1] then
-                reply:add_child(st.stanza('changed', resset[i].attr));
-            else
-                reply:add_child(st.stanza('removed', resset[i].attr));
-            end
-        end
-        local set = st.stanza('set', {xmlns = xmlns_rsm});
-        if s <= e-1 then
-            set:tag('first', {index=s-1}):text(gen_uid(resset[s])):up()
-               :tag('last'):text(gen_uid(resset[e-1])):up();
-        end
-        set:tag('count'):text(tostring(count)):up();
-        reply:add_child(set);
-    end
-    origin.send(reply);
-    return true;
-end
-
-------------------------------------------------------------
--- Message Handler
-------------------------------------------------------------
-local function find_pref(pref, name, k, v, exactmatch)
-    for i, child in ipairs(pref) do
-        if child.name == name then
-            if k and v then
-                if exactmatch and child.attr[k] == v then
-                    return child;
-                elseif not exactmatch then
-                    if tobool(child.attr['exactmatch']) then
-                        if child.attr[k] == v then
-                            return child;
-                        end
-                    elseif match_jid(child.attr[k], v) then
-                        return child;
-                    end
-                end
-            else
-                return child;
-            end
-        end
-    end
-    return nil;
-end
-
-local function apply_pref(node, host, jid, thread)
-    if FORCE_ARCHIVING then return true; end
-
-    local pref = load_prefs(node, host);
-    if not pref then
-        return AUTO_ARCHIVING_ENABLED;
-    end
-    local auto = pref:child_with_name('auto');
-    if not tobool(auto.attr['save']) then
-        return false;
-    end
-    if thread then
-        local child = find_pref(pref, 'session', 'thread', thread, true);
-        if child then
-            return tobool(child.attr['save']) ~= false;
-        end
-    end
-    local child = find_pref(pref, 'item', 'jid', jid, false); -- JID Matching
-    if child then
-        return tobool(child.attr['save']) ~= false;
-    end
-    local default = pref:child_with_name('default');
-    if default then
-        return tobool(default.attr['save']) ~= false;
-    end
-    return AUTO_ARCHIVING_ENABLED;
-end
-
-local function msg_handler(data, local_jid, other_jid, isfrom)
-    module:log("debug", "-- Enter msg_handler()");
-    local origin, stanza = data.origin, data.stanza;
-    local body = stanza:child_with_name("body");
-    local thread = stanza:child_with_name("thread");
-    if body then
-        local local_node, local_host = jid.split(local_jid);
-        if hosts[local_host] and um.user_exists(local_node, local_host) and apply_pref(local_node, local_host, other_jid, thread) then
-            store_msg(stanza, local_node, local_host, isfrom);
-        end
-    end
-
-    return nil;
-end
-
-local function message_handler(data)
-    msg_handler(data, data.stanza.attr.to,  data.stanza.attr.from, true)
-end
-
-local function premessage_handler(data)
-    msg_handler(data, data.stanza.attr.from,  data.stanza.attr.to, false)
-end
-
--- Preferences
-module:hook("iq/self/urn:xmpp:archive:pref", preferences_handler);
-module:hook("iq/self/urn:xmpp:archive:itemremove", itemremove_handler);
-module:hook("iq/self/urn:xmpp:archive:sessionremove", sessionremove_handler);
-module:hook("iq/self/urn:xmpp:archive:auto", auto_handler);
--- Manual archiving
-module:hook("iq/self/urn:xmpp:archive:save", save_handler);
--- Archive management
-module:hook("iq/self/urn:xmpp:archive:list", list_handler);
-module:hook("iq/self/urn:xmpp:archive:retrieve", retrieve_handler);
-module:hook("iq/self/urn:xmpp:archive:remove", remove_handler);
--- Replication
-module:hook("iq/self/urn:xmpp:archive:modified", modified_handler);
-
-module:hook("message/full", message_handler, 10);
-module:hook("message/bare", message_handler, 10);
-module:hook("pre-message/full", premessage_handler, 10);
-module:hook("pre-message/bare", premessage_handler, 10);
-
--- TODO exactmatch
--- TODO <item/> JID match
--- TODO 'open attr' in removing a collection
--- TODO save = body/message/stream
--- a/mod_archive_muc/mod_archive_muc.lua	Wed Apr 03 18:49:27 2013 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,194 +0,0 @@
--- 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_compare, jid_split, jid_bare = require "util.jid".compare, require "util.jid".bare, require "util.jid".split;
-local datetime = require "util.datetime".datetime;
-local user_exists = require "core.usermanager".user_exists;
-local is_contact_subscribed = require "core.rostermanager".is_contact_subscribed;
-
-local PREFS_DIR = "archive_muc_prefs";
-local ARCHIVE_DIR = "archive_muc";
-
-local AUTO_MUC_ARCHIVING_ENABLED = module:get_option_boolean("auto_muc_archiving_enabled", true);
-
-local NULL = {};
-
-module:add_feature("urn:xmpp:archive#preferences");
-module:add_feature("urn:xmpp:archive#management");
-
-------------------------------------------------------------
--- Utils
-------------------------------------------------------------
-local function trim(s)
-  return (string.gsub(s, "^%s*(.-)%s*$", "%1"))
-end
-
-local function clean_up(t)
-    for i = #t, 1, -1 do
-        if type(t[i]) == 'table' then
-            clean_up(t[i]);
-        elseif type(t[i]) == 'string' and trim(t[i]) == '' then
-            table.remove(t, i);
-        end
-    end
-end
-
-local function load_prefs(node, host)
-    return st.deserialize(dm.load(node, host, PREFS_DIR));
-end
-
-local function store_prefs(data, node, host)
-    clean_up(data);
-    dm.store(node, host, PREFS_DIR, st.preserialize(data));
-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 apply_pref(node, host, jid)
-    local pref = load_prefs(node, host);
-    if not pref then
-        return AUTO_MUC_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_contact_subscribed(node, host, jid_bare(jid));
-    elseif default == 'always' then
-        return true;
-    elseif default == 'never' then
-        return false;
-    end
-    return AUTO_MUC_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=datetime()}):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);
-        if user_exists(from_node, from_host) and apply_pref(from_node, from_host, stanza.attr.to) then
-            store_msg(stanza, from_node, from_host);
-        end
-        if user_exists(to_node, to_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/bare", msg_handler, 20);
-