# HG changeset patch # User shinysky # Date 1275753844 -28800 # Node ID fd8d76daad9719c48d0dde6c9961692eda987b4f # Parent 0b238b2b0801ce67d2e1dbda83f91d005dd9fbb5 mod_archive: preference handling is done. diff -r 0b238b2b0801 -r fd8d76daad97 mod_archive/mod_archive.lua --- 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);