diff mod_archive/mod_archive.lua @ 165:fd8d76daad97

mod_archive: preference handling is done.
author shinysky<shinysky1986(AT)gmail.com>
date Sun, 06 Jun 2010 00:04:04 +0800
parents 9a37898f4f7c
children ac826882a8cf
line wrap: on
line diff
--- a/mod_archive/mod_archive.lua	Thu Jun 03 11:20:26 2010 +0100
+++ b/mod_archive/mod_archive.lua	Sun Jun 06 00:04:04 2010 +0800
@@ -6,7 +6,10 @@
 --
 
 local st = require "util.stanza";
-local dm = require "util.datamanager"
+local dm = require "util.datamanager";
+
+local PREFS_DIR = "archive_prefs";
+local ARCHIVE_DIR = "archive";
 
 module:add_feature("urn:xmpp:archive");
 module:add_feature("urn:xmpp:archive:auto");
@@ -14,13 +17,26 @@
 module:add_feature("urn:xmpp:archive:manual");
 module:add_feature("urn:xmpp:archive:pref");
 
+------------------------------------------------------------
+-- Utils
+------------------------------------------------------------
+local function load_prefs(node, host, dir)
+    return st.deserialize(dm.load(node, host, dir or PREFS_DIR));
+end
+
+local function store_prefs(data, node, host, dir)
+    dm.store(node, host, dir or PREFS_DIR, st.preserialize(data));
+end
+
+------------------------------------------------------------
+-- Preferences
+------------------------------------------------------------
 local function preferences_handler(event)
-	local origin, stanza = event.origin, event.stanza;
-	module:log("debug", "-- Enter preferences_handler()");
+    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
-        -- dm.store(origin.username, origin.host, "archive_prefs", st.preserialize(reply.tags[1]));
-        local data = st.deserialize(dm.load(origin.username, origin.host, "archive_prefs"));
+    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
@@ -31,28 +47,170 @@
             reply:tag('method', {type='manual', use='concede'}):up();
             reply:tag('auto', {save='false'}):up();
             origin.send(reply);
-            -- origin.send(st.reply(stanza));
         end
-		return true;
     elseif stanza.attr.type == "set" then
-        return false;
-	end
-end
-
-local function auto_handler(event)
-    module:log("debug", "-- stanza:\n%s", tostring(event.stanza));
-	if event.stanza.attr.type == "set" then
-        event.origin.send(st.error_reply(event.stanza, "cancel", "feature-not-implemented"));
-        return true;
+        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"
+        -- FIXME there may be many item/session/method sections!! 
+        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
+                -- TODO bare JID or full JID?
+                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; -- TODO how to gen the message that new modes're set?
+                res.send(push);
+            end
+        end
     end
-end
-
-local function chat_handler(event)
-    module:log("debug", "-- stanza:\n%s", tostring(event.stanza));
     return true;
 end
 
 local function itemremove_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 ~= "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
+        return false;
+    end
+    local setting = data:child_with_name(elem.name)
+    setting.attr["save"] = elem.attr["save"];
+    store_prefs(data, node, host);
+    origin.send(st.reply(stanza));
+    return true;
+end
+
+local function chat_handler(event)
     module:log("debug", "-- stanza:\n%s", tostring(event.stanza));
     return true;
 end
@@ -83,9 +241,10 @@
 end
 
 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);
-module:hook("iq/self/urn:xmpp:archive:chat", chat_handler);
-module:hook("iq/self/urn:xmpp:archive:itemremove", itemremove_handler);
+-- module:hook("iq/self/urn:xmpp:archive:chat", chat_handler);
 module:hook("iq/self/urn:xmpp:archive:list", list_handler);
 module:hook("iq/self/urn:xmpp:archive:modified", modified_handler);
 module:hook("iq/self/urn:xmpp:archive:remove", remove_handler);